用Flutter实现小Q聊天机器人(五)
用Flutter实现小Q聊天机器人(一)
用Flutter实现小Q聊天机器人(二)
用Flutter实现小Q聊天机器人(三)
用Flutter实现小Q聊天机器人(四)
用Flutter实现小Q聊天机器人(五)
GitHub:https://github.com/baiyuliang/Qrobot_Flutter
前几篇我们基本实现了一个简单的聊天界面,也基本掌握了如何通过Flutter去完成这样一个布局及功能的实现,但离我们标题所需要实现的还差那么一步,既然是聊天机器人,那就不能只做本地的聊天了,网络请求+机器人API是必须的啦!
首先说一下本项目用到的机器人API是腾讯AI平台:https://ai.qq.com/doc/nlpchat.shtml,大家可以到这里申请,然后会得到APP_ID和APP_KEY,就可以调用它的API并带入参数请求机器人回复了。
Dart网络请求需要引入一个库:http: ^0.12.0
具体写法:
import 'package:http/http.dart' as http;
http.get(Uri.parse(url), headers:{})
.then((res){ })
.catchError((error){ });
http.post(Uri.parse(url), headers:{},body:)
.then((res){ })
.catchError((error){ });
http常用的get、post、put、delete方法全部都有提供,根据接口类型使用不同方法,headers根据需要传入,格式如headers: {'Content-Type': 'application/x-www-form-urlencoded'}
,then就是请求结果回调,res就是请求结果,catchError是请求异常捕获,另外post请求时参数需要用body传入,如:body:params
,params是key1=value1&key2=value2&…的String类型,这样一个网络请求就完成了,是不是好简单!
那我们 就来先试着请求一下机器人API,文档中已经给出API的url为:https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat
,我们先忽略参数,直接去请求一下,来实验一下上述http请求方法是否可用:
import 'package:http/http.dart' as http;
main() {
http.post("https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat").then((res) {
print(res.body);
});
}
运行结果:
{
"ret": 4096,
"msg": "paramter invalid",
"data": {
"session": "",
"answer": ""
}
}
网络请求没毛病,只是接口返回了错误信息:参数错误!那么接下来我们就要看文档,看这个接口到底需要怎样的参数:
其中最主要的就是“sign”这个参数,点击接口鉴权,看看如何生成sign:
第一步:参数升序:
这个很简单,参数已知的,我们按顺序排列一下就行了:app_id,nonce_str,question,session,time_stamp;
第二步:拼接并编码:
按上述顺序进行键值对拼接,并且value部分需要URL编码,其实除了question参数是我们输入的,大部分为中文,需要去编码外,其它的都不需要编码,因此只对question编码即可;我们知道,在java中,直接调用系统方法URLEncoder.encode()方法编码即可,那在dart中用什么呢?这个需要dart提供的Uri这个类的Uri.encodeFull方法就可以了;
第三步:拼接appkey:
将&app_key=xxx继续拼接在第二步拼接的参数后面;
第四步:MD5后大写:
dart中md5方法需要导入两个库:
crypto: ^2.0.6
utf: ^0.9.0+5
然后就可以调用md5.convert方法,但convert需要传入的参数为字节数组,那么就需要先对参数进行编码utf8.encode(params)得到字节数组后再传入:
var sign = md5.convert(utf8.encode(params));
最后一步转换为大写,就很简单了,直接调用String的方法:sign.toString().toUpperCase()就行了!
另外,Flutter中获取当前时间可以用DateTime:
DateTime.now().millisecondsSinceEpoch
得到的是毫秒,类似于安卓的:
System.currentTimeMillis()
由于参数中需要传入秒,那么就需要/1000:
DateTime.now().millisecondsSinceEpoch/1000
但其并不会像java一样结果为整数,而是一个double类型,因此我们需要强制转换,dart中强制转化也不像java中直接在代码前面加转换类型,而是用到as:
DateTime.now().millisecondsSinceEpoch/1000 as int
其可以简化为:
DateTime.now().millisecondsSinceEpoch ~/ 1000
“~”这个符号是不是很神奇?
好了,参数算完,我们就来试验一下效果:
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
var url = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat";
var app_id = "";//填入自己申请的appid
var app_key = "";//填入自己申请的appkey
main() {
getText("你好");
}
getText(question) {
var params =
"app_id=$app_id&nonce_str=fa577ce340859f9fe&question=${Uri.encodeFull(question)}&session=10000&time_stamp=${DateTime.now().millisecondsSinceEpoch ~/ 1000}";
http
.post(Uri.parse(url),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: params + "&sign=" + getSign(params))
.then((res) {
print(res.body);
}).catchError((error) {
print(error);
});
}
//获取签名
getSign(params) {
params += "&app_key=$app_key";
var sign = md5.convert(utf8.encode(params));
return sign.toString().toUpperCase();
}
运行结果:
注意:appid和appkey需要填入你自己申请的!
既然有接口请求,那么就要有json解析转换了,安卓中我们常用的是谷歌的GSON,很方便,而Dart中需要用到上面的一个库:dart:convert:
jsonDecode(json)
需要注意的是,这个方法解析后得到的是一个map,比如我要取字段ret,就要这么写:
jsonDecode(json)['ret']
最终,我们将其封装为一个类:
import 'dart:convert';
class RobotMessage {
int ret;
var msg;
RobotData data;
RobotMessage(json) {
var map = jsonDecode(json);
ret = map['ret'];
msg = map['msg'];
var _data = map['data'];
data = RobotData(_data);
}
}
class RobotData {
var session;
String answer;
RobotData(data) {
session = data['session'];
answer = data['answer'];
}
}
那么在接口请求完成后,我们就可以直接用:
RobotMessage robotMessage = RobotMessage(res.body);
来解析并转换为RobotMessage 对象了!
UI和接口都完成了,那么结合起来后就基本上实现了一个简单的聊天机器人的应用了!
另外,在安卓中我们常用EventBus来进行通信,在Dart中也可以使用的,引入库:event_bus: ^1.0.3,使用方法:
1.初始化:
初始化需要在你生命的Event类中初始化,如:
EventBus eventBus=EventBus();
class EventTest{
}
一定要注意,初始化代码要写在class之外;
2.发送Event:
eventBus.fire(EventTest());
3.接收Event:
eventBus.on<EventTest>().listen((event) {
});
上一篇: Tomcat的优点/功能及安装
下一篇: 对Promise的个人理解