根据导师留下的一个参考网址:Android智能聊天机器人的实现.我们可以自己参照做出一个大致的框架。可以把xml文件里的组件背景图片,显示文字改成自己喜欢的样子,然后我们开始着手内核。
一些小坑就不说了,自己也能调试出来,这里说些有点难受的大坑。
在此文件第62行
viewHolder.message = (TextView) convertView
.findViewById(R.id.message)应该为viewHolder.message = (TextView) convertView
.findViewById(R.id.left_message);
我们进入官网API V2.0接入文档,可以清楚的看到
接口地址
http://openapi.tuling123.com/openapi/api/v2
请求方式
HTTP POST
请求参数
请求参数格式为 json
相较于参考网址代码,推测应该是图灵机器人官网进行的某次重大更新,api连接有非常大的改变,参考网址的接口地址即MyRobot.URL_KEY要换成http://openapi.tuling123.com/openapi/api/v2,且其请求方式是http get,所以我们必须用全新的,http post请求方式的,参数是json的网络请求函数。一句话——HttpRequest.java文件要大改。在这里先稍微解释一下json,其实就是一个具有指定格式的字符串,只要你按照要求写对了,你发送到官网接口去,官网就会回你一个json,也是一个字符串,里面有我们需要的信息。更多内容可以参考官网API V2.0接入文档,里面有样例和参数说明,可供理解。
先上代码
private static String fromjson(String message) {
String msg = "";
msg = "{" +
"\"perception\":{" +
"\"inputText\": {" +
"\"text\": \"" +
message+
"\"}}," +
"\"userInfo\":{" +
"\"apiKey\":\"" + MyRobot.API_KEY + "\"," +
"\"userId\":\"" + MyRobot.ID + "\"}}";
return msg;
}
这样,聊天中你输入的信息作为函数参数,返回的是一个最简单的符合要求的json字符串。
聪明的同学已经发现了,我们需要在MyRobot类中新增一个静态字符串成员ID。这个id就是你在图灵官网注册的用户id。这只是得到json,怎么与官网建立连接呢?别慌,上代码
public static String sendJsonPost(String Json) {
// HttpClient 6.0被抛弃了
String result = "";
BufferedReader reader = null;
try {
String urlPath = MyRobot.URL_KEY ;
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
// 设置文件类型:
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
// 设置接收类型否则返回415错误
conn.setRequestProperty("accept", "application/json");
// 往服务器里面发送数据
if (Json != null && !TextUtils.isEmpty(Json)) {
byte[] writebytes = Json.getBytes();
// 设置文件长度
conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
OutputStream outwritestream = conn.getOutputStream();
outwritestream.write(Json.getBytes());
outwritestream.flush();
outwritestream.close();
Log.d("msg", "doJsonPost: " + conn.getResponseCode());
}
if (conn.getResponseCode() == 200) {//上传成功
reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
result = reader.readLine();//得到返回的json字符串
}
} catch (Exception e) {
Log.d("msg","没成功");//Log出现这个一般是fromjson函数没写好,格式不对
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
以传输json为参数,返回得到的json字符串
具体使用:
public static ChatMessage sendMessage(String message) {
ChatMessage chatMessage = new ChatMessage();
Log.d("msg",fromjson(message));
String gsonResult = sendJsonPost(fromjson(message));//连接请求的内容
if (gsonResult != null) {
try {
chatMessage.setMessage(GetText(gsonResult));//http连接获取的内容解析之后的结果给聊天信息赋值
} catch (Exception e) {
chatMessage.setMessage("请求错误...");
Log.d("msg",gsonResult);
Log.e("msg",Log.getStackTraceString(e));
}
}
chatMessage.setDate(new Date());
chatMessage.setType(ChatMessage.Type.INCOUNT);
return chatMessage;
}
这个时候你先别管GetText函数,你可以先尝试去 Log.d(“msg”,gsonResult),即看看你到底有没有收到官网回复的json,如果你Log出来类似
{“emotion”:{“robotEmotion”:{“a”:0,“d”:0,“emotionId”:0,“p”:0},“userEmotion”:{“a”:0,“d”:0,“emotionId”:20300,“p”:0}},“intent”:{“actionName”:"",“code”:10004,“intentName”:""},“results”:[{“groupType”:1,“resultType”:“text”,“values”:{“text”:“一颗蛋,哇哈哈~~”}}]}
那么,恭喜你,你离成功已经不远了,最后的text的内容就是机器人的智能回复
如果不行,那么你可以看看下面这个坑。
安卓版本变高,在系统安全方面挖了不少坑,我们这里到图灵机器人官网的网络连接,可能被系统视为不安全的,导致连接失败。我们可以这样操作:
在res文件夹中新建一个文件夹,放入network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
再在AndroidManifest文件中添加
android:networkSecurityConfig="@xml/network_security_config"
<uses-permission android:name="android.permission.INTERNET" />
【一般的方法】
自定义一个Result类,让这个类契合json文本(json中{表示类,[表示集合),再利用google的gson包的函数,将json数据转换成Result类对象,最后在对象中调用gettext函数得到数据。但由于这里的json是类中含有类,天知道我在这里查了多久资料,debug了多久代码,一直以为我是Result类没写对,一直在调试。直到最后,我得到了结论——此方法不可行。如果谁用这个方法成功了,务必联系我,类中类的result类来一个好吗?秋梨膏!
【可行的方法】
JsonReader
一个通过输入流来得到json数据的数据流读入类,先上代码
private static String GetText(String json) throws IOException {
JsonReader reader = new JsonReader(new StringReader(json));
String ans="";
reader.beginObject();
try {
while(reader.hasNext()){
String name=reader.nextName();
if(name.equals("emotion")){
reader.beginObject();
reader.nextName();
reader.beginObject();
for(int i=0;i<4;i++){
reader.nextName();
reader.nextString();
}
reader.endObject();
name=reader.nextName();
reader.beginObject();
for(int i=0;i<4;i++){
reader.nextName();
reader.nextString();
}
reader.endObject();
reader.endObject();
}
else if(name.equals("intent")){
reader.beginObject();
for(int i=0;i<3;i++){
reader.nextName();
reader.nextString();
}
reader.endObject();
}
else if(name.equals("results")){ reader.beginArray();
reader.beginObject();
for(int i=0;i<2;i++){
reader.nextName();
reader.nextString();
}
name=reader.nextName();
if(name.equals("values")){
reader.beginObject();
reader.nextName();
ans=reader.nextString();
reader.close();
return ans;
}
}
}
} finally {
return ans;
}
}
针对下面这个回复json来看
{"emotion":{"robotEmotion":{"a":0,"d":0,"emotionId":0,"p":0},"userEmotion":{"a":0,"d":0,"emotionId":20300,"p":0}},"intent":{"actionName":"","code":10004,"intentName":""},"results":[{"groupType":1,"resultType":"text","values":{"text":"一颗蛋,哇哈哈~~"}}]}
1.这个是当你发的信息可以判断情绪的时候就会有这样的回复json,如果你发的是形如“1234”,“nmsl”(浓墨山峦),等机器判断不出情绪的消息,回复json中可能就会没有emotion这个类(包含robotEmotion和userEmotion),只有intent类和result集合。我们的程序要做到两种情况都能得到有效数据才算成功,这里我用while循环+if…else来解决这个问题。
2.简单介绍下上面函数reader能点出来的几个函数的意义
beginobject(),在这里可以理解成读入”{“;
beginArray(),在这里可以理解成读入”[“;
nextname(),读入emotion,robotemotion等等字段
nextString(),读入0,20300,text,一颗蛋,哇哈哈~~等字段后的字符串内容
endArray(),在这里可以理解成读入”]“;
endObject(),在这里可以理解成读入”}“;
好,那么剩下的就不讲了,就是对应json字符串内容字段顺序,一个一个读入但不处理,直到"text":“一颗蛋,哇哈哈~~”,最后用ans=reader.nextString()来记录数据。
有一说一,这个方法虽然看上去很笨重,但其实一个很底层的方法,所以是一个很通用的方法。对于这种 类中有类的json数据,我发现是不是只有这种方法才能实现数据的获取?在这里先打一个问号吧,欢迎来评论区交流。
有一说一,这安卓课设确实有点坑,在下身先士卒,为大伙填坑,希望能对大伙有所帮助吧。
联系QQ:2541884980