欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用Flutter实现小Q聊天机器人(五)

程序员文章站 2022-07-02 23:20:51
...

用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": ""
  }
}

网络请求没毛病,只是接口返回了错误信息:参数错误!那么接下来我们就要看文档,看这个接口到底需要怎样的参数:
用Flutter实现小Q聊天机器人(五)
其中最主要的就是“sign”这个参数,点击接口鉴权,看看如何生成sign:
用Flutter实现小Q聊天机器人(五)
第一步:参数升序:

这个很简单,参数已知的,我们按顺序排列一下就行了: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();
}

运行结果:
用Flutter实现小Q聊天机器人(五)
注意: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和接口都完成了,那么结合起来后就基本上实现了一个简单的聊天机器人的应用了!

用Flutter实现小Q聊天机器人(五)用Flutter实现小Q聊天机器人(五)

另外,在安卓中我们常用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) {
  
   });