前言

       在人工智能时代,开发一款自己的智能问答机器人,既可以提升自己的编程能力,又可以作为开发项目的实战练习。

       百度有小度,小米有小爱,VIVO有小V,总之类似的智能聊天机器人是越来越多了。面对这些智能的机器人,我们似乎只能是体验者。想想底层的算法就让人头疼,它到底是怎么识别出一句话的意思的?又是怎么实现智能回复的?

       接下来我将用Android studio并借用百度图灵机器人((turingapi.com))教大家实现一个属于自己的智能聊天机器人。

学  号     231   

 姓  名      福福      

指导教师:赵,罗,钟

  2022  5   8 

1  系统设计

1.1 设计要求

1.1.1 设计任务   

设计一个对话框能实现聊天功能,要求能联网实现自动对话的功能,可以实现编辑、发送、删除等功能。

1.1.2 性能指标要求  

1、基本要求

  要求完成程序源码编写、调试及关键代码注释。

2、发挥部分

实现多客户端间的聊天功能。

1.2 设计思路及设计框图

1.2.1设计思路

智能聊天机器人的设计流程如下:

①将要显示的数据封装成Data数据。

②将封装好的Data数据设置成HTTP请求数据。

③向图灵机器人服务器发送HTTP请求。

④图灵服务器接收到HTTP请求数据之后,返回JSON数据。

⑤将获取到的JSON数据进行解析。

⑥解析后的JSON数据封装并显示到界面中。

1.2.2总体设计框图

 

2  各个模块程序的设计

1、申请机器人身份标识 

在图灵机器人官网注册并获取key值

2、建立聊天布局

整个界面最外层采用线性布局,接着在TextView下面放置了一个RelativeLayout,在它里面先放置了一个ListView,用于显示聊天消息列表。然后放置了一个小的RelativeLayout,里面放置了一个Button和一个EditText,Button在EditText右侧,文本为“发送”,作为发送按钮,EditText则是聊天输入框,在里面输入聊天内容。这样整个聊天界面的布局文件就搭建好了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="#0cc4e5"
        android:gravity="center"
        android:text="小福机器人"
        android:textColor="#795548"
        android:textSize="20sp" />
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ListView
            android:id="@+id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_above="@+id/rl_bottom"
            android:cacheColorHint="@android:color/black"
            android:divider="@null"
            android:listSelector="@null"
            android:transcriptMode="alwaysScroll"/>
        <RelativeLayout
            android:id="@+id/rl_bottom"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="@drawable/bottom_bg">

            <Button
                android:id="@+id/btn_send"
                android:layout_width="60dp"
                android:layout_height="48dp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginRight="10dp"
                android:background="@drawable/btn_send_selector"
                android:text="发送"
                android:textColor="@android:color/black"
                android:textSize="14sp" />

            <EditText
                android:id="@+id/et_send_msg"
                android:layout_width="fill_parent"
                android:layout_height="40dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_toLeftOf="@+id/btn_send"
                android:background="@drawable/send_msg_bg"
                android:singleLine="true"
                android:textColor="@android:color/black"
                android:textSize="18sp"
                tools:ignore="SpeakableTextPresentCheck,SpeakableTextPresentCheck,TouchTargetSizeCheck,TouchTargetSizeCheck" />
        </RelativeLayout>
    </RelativeLayout>
</LinearLayout>

3、搭建聊天条数布局

chatting_left_item文件为机器人聊天头像和聊天框显示文件,用于显示机器人的聊天内容。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="6dp">
    <ImageView
        android:id="@+id/iv_head"
        android:layout_width="65dp"
        android:layout_height="65dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="5dp"
        android:background="@drawable/robot_head"
        android:focusable="false"/>

    <TextView
        android:id="@+id/tv_chat_content"
        style="@style/chat_content_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/iv_head"
        android:background="@drawable/chat_left_selector"
        tools:ignore="SpeakableTextPresentCheck" />

</RelativeLayout>

chatting_right_item文件为用户聊天头像和聊天框显示文件,用于显示用户的聊天内容。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="6dp">
    <ImageView
        android:id="@+id/iv_head"
        android:layout_width="65dp"
        android:layout_height="65dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="5dp"
        android:background="@drawable/myhead"
        android:focusable="false"/>

    <TextView
        android:id="@+id/tv_chat_content"
        style="@style/chat_content_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:layout_toLeftOf="@+id/iv_head"
        android:background="@drawable/chat_right_selector"
        tools:ignore="SpeakableTextPresentCheck" />

</RelativeLayout>

4、封装聊天信息实体类

      创建一个ChatBean类,在该类中创建机器人与用户聊天信息的属性重写了get和set方法

package com.example.ffshixun;

public class ChatBean {
    public static final int SEND=1;//发送消息
    public static final int RECEIVE=2;//接收消息
    private int state;//消息的状态(是接收还是发送)
    private String message;//消息的内容

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

5、编写聊天列表适配器

   创建一个ChatAdapter类,由于聊天界面用了ListView控件显示聊天信息,因此需要创建一个数据适配器ChatAdapter对ListView控件进行数据适配。

package com.example.ffshixun;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

import zj.dzh.intelrobot.R;

public class ChatAdapter extends BaseAdapter {
    private List<ChatBean> chatBeanList;//聊天数据
    private LayoutInflater layoutInflater;
    public ChatAdapter(List<ChatBean>chatBeanList, Context context){
        this.chatBeanList=chatBeanList;
        layoutInflater=LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return chatBeanList.size();
    }

    @Override
    public Object getItem(int position) {
        return chatBeanList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Holder holder=new Holder();
        //判断当前的消息是发送的消息还是接收到的消息,不同消息加载不同的view
        if (chatBeanList.get(position).getState()==ChatBean.RECEIVE){
            //加载左边布局,也就是机器人对应的布局信息
            convertView=layoutInflater.inflate(R.layout.chatting_left_item,null);
        }else{
            //加载右边布局,也就是用户对应的布局信息
            convertView=layoutInflater.inflate(R.layout.chatting_right_item,null);
        }
        holder.tv_chat_content=(TextView)convertView.findViewById(R.id.tv_chat_content);
        holder.tv_chat_content.setText(chatBeanList.get(position).getMessage());
        return convertView;
    }
    class Holder{
        public TextView tv_chat_content;//聊天内容
    }
}

6、实现智能机器人通信

    在项目MainActivity中实现聊天界面的逻辑代码,首先添加okhttp库,然后设置机器人的欢迎信息,最后编写界面交互代码。

package com.example.ffshixun;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telecom.Call;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import zj.dzh.intelrobot.R;

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ChatAdapter adapter;
    private List<ChatBean> chatBeanList;//存放所有聊天数据的集合
    private EditText et_send_msg;
    private Button btn_send;
    //接口地址
    private static final String WEB_SITE="http://www.tuling123.com/openapi/api";
    //唯一key,该key的值是从官网注册账号获取的,注册地址为:http://www.tuling123.com/
    private static final String KEY="d2001c59d6af4c51b4eff1535fbf81ec";
    private String sendMsg;//发送的信息
    private String welcome[];//存储欢迎信息
    private MHandler mHandler;
    public static final int MSG_OK=1;//获取数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        chatBeanList=new ArrayList<ChatBean>();
        mHandler=new MHandler();
        //获取内置的欢迎信息
        welcome=getResources().getStringArray(R.array.welcome);
        initView();//初始化界面控件

    }
    public void initView(){
        listView=(ListView)findViewById(R.id.list);
        et_send_msg=(EditText)findViewById(R.id.et_send_msg);
        btn_send=(Button)findViewById(R.id.btn_send);
        adapter=new ChatAdapter(chatBeanList,this);
        listView.setAdapter(adapter);
        btn_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendData();//点击发送按钮,发送信息
            }
        });
        et_send_msg.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent keyEvent) {
                if (keyCode==KeyEvent.KEYCODE_ENTER && keyEvent.getAction()==
                KeyEvent.ACTION_DOWN){
                    sendData();//点击Enter键也可以发送信息
                }
                return false;
            }
        });
        int position=(int)(Math.random()*welcome.length-1);//获取一个随机数
        showData(welcome[position]);//用随机数获取机器人的首次聊天信息
    }
    private void sendData(){
        sendMsg=et_send_msg.getText().toString();//获取你输入的信息
        if(TextUtils.isEmpty(sendMsg)){//判断是否为空
            Toast.makeText(this,"您还未输入任何信息哦",Toast.LENGTH_LONG).show();
            return;
        }
        et_send_msg.setText("");
        //替换空格和换行
        sendMsg=sendMsg.replaceAll(" ","").replaceAll("\n","").trim();
        ChatBean chatBean=new ChatBean();
        chatBean.setMessage(sendMsg);
        chatBean.setState(chatBean.SEND);//SEND表示自己发送的信息
        chatBeanList.add(chatBean);//将发送的信息添加到chatBeanList集合中
        adapter.notifyDataSetChanged();//更新ListView列表
        getDataFromServer();//从服务器获取机器人发送的信息
    }

    private void getDataFromServer(){
        OkHttpClient okHttpClient=new OkHttpClient();
        Request request =new Request.Builder().url(WEB_SITE+"?key="+KEY+"&info="+sendMsg).build();
        Call call=okHttpClient.newCall(request);
        //开启异步线程访问网络
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String res=response.body().string();
                Message msg=new Message();
                msg.what=MSG_OK;
                msg.obj=res;
                mHandler.sendMessage(msg);
            }
        });
    }


    //事件捕获
    class MHandler extends Handler{
        @Override
        public void dispatchMessage(Message msg){
            super.dispatchMessage(msg);
            switch(msg.what){
                case MSG_OK:
                    if(msg.obj!=null){
                        String vlResult=(String)msg.obj;
                        paresData(vlResult);
                    }
                    break;
            }
        }
    }
    private void paresData(String JsonData){  //Json解析
        try{
            JSONObject obj=new JSONObject(JsonData);
            String content=obj.getString("text");//获取的机器人信息
            int code=obj.getInt("code");//服务器状态码
            updateView(code,content);
        }catch (JSONException e){
            e.printStackTrace();
            showData("主人,你的网络不好哦");
        }
    }


    private void showData(String message){
        ChatBean chatBean=new ChatBean();
        chatBean.setMessage(message);
        chatBean.setState(ChatBean.RECEIVE);//机器人发送的消息
        chatBeanList.add(chatBean);//将机器人发送的消息添加到chatBeanList集合中
        adapter.notifyDataSetChanged();
    }


    private void updateView(int code,String content){
        //code有很多形状,在此例举几种。
        switch (code){
            case 4004:
                showData("主人,今天我累了,我要休息了,明天再来找我耍吧");
                break;
            case 40005:
                showData("主人,你说的是火星语吗?");
                break;
            case 40006:
                showData("主人,我今天要去约会哦,改天再聊哦。");
                break;
            case 40007:
                showData("主人,明天再和你耍啦,我感冒了,呜呜呜。。。");
                break;
            default:
                showData(content);
                break;
        }
    }


    protected long exitTime;//记录第一次点击时的时间


    @Override
    public boolean onKeyDown(int keyCode,KeyEvent event){
        if (keyCode==KeyEvent.KEYCODE_BACK
            &&event.getAction()==KeyEvent.ACTION_DOWN){
            if ((System.currentTimeMillis()-exitTime)>2000){
                Toast.makeText(MainActivity.this,"再按一次退出聊天程序",Toast.LENGTH_SHORT).show();
                exitTime=System.currentTimeMillis();
            }else {
                MainActivity.this.finish();
                System.exit(0);
            }
            return true;
        }
        return super.onKeyDown(keyCode,event);
    }

    private class OkHttpClient {
    }
}

在MainActivity中创建几个方法:

  1. initView( ) 用于获取界面控件并初始化界面数据;
  2. showData( ) 用于显示欢迎信息到界面上;
  3. sendData ( ) 用于用户发送信息;
  4. getDataFromServer( ) 从服务器获取机器人的回复信息;
  5. updateView( ) 更新界面信息;

3  调试过程

  运行会会有随机的欢迎消息,可以在回复设置里面自定义修改。发英文字母a,b,c,它会自动往下接,实现了单人聊天。

4  功能测试

4.1 测试仪器与设备

    Android studio  笔记本电脑

4.2 性能指标测试

    实现联网自动对话,发送功能,未实现发送、删除等功能。

5  实训心得体会

安卓实训结束了,通过对智能聊天机器人的开发设计,对Android 应用开发有了更为深层次的理解,对手机应用也有了全新的认识于熟练,对基于Android多种布局以及第三方软件API的引用有了更深层次的理解。实训前对android的应用操作还不熟悉,实训结束后终于知道了个步骤操作。本机器人聊天系统基本上实现了需求中的全部功能需求,整体上较为满意。本应用的难点在于如何设置的不同布局,以及跳转,实现聊天的效果。学完后,加深了对布局的理解,为以后开发类似程序打下了基础。但是自己对安卓的很多方面还不是很了解,各种方法也不是很会使用,实训过后自己还会加强对安卓应用设计的学习。

6  参考文献

 [1] 张思民.Android Studio(第二版).北京:清华大学出版社,2017

附录

相关图片

 

 

程序清单

链接:https://pan.baidu.com/s/1yywLy4soGEQ9YNR8PEePtg 
提取码:1314

 

Logo

智屏生态联盟致力于大屏生态发展,利用大屏快应用技术降低开发者开发、发布大屏应用门槛

更多推荐