加载中...

微信小程序通过SSE接入AI

微信小程序通过SSE接入AI

前言

近期忙于将公司内部的AI产品接入到小程序中

调研

发现通过调用内部AI接口发现接口返回的格式是event stream的形式,而小程序则是通过开启wx.request中的enableChunked的方式来实现
关于wx.request的官方说明

New Image

关于Event Stream(SSE)

相比于SSE之前更熟悉Websocket,那么两种有什么区别呢?

  1. SSE本质上还是属于http协议,而Websocket并不属于http协议
  2. SSE是单向通信,只能由服务端向客户端发送请求
  3. 以及SSE是通过保持一个持久的 HTTP 连接来实现推送,属于长连接,而Websocket是全双工的。

在微信小程序中如何处理SSE

1. 在小程序中相应的API

前文已经提到,核心在于配置wx.request中的enableChunked参数

javascript
代码解读
复制代码
const requestTask = wx.request({ url, method: ''POST'', data: params, enableChunked: true, header: { token, } })

微信官方并且提供了监听取消的API

javascript
代码解读
复制代码
//监听的api requestTask.onChunkReceived((res) => { //xxxxxxxxxx }); //取消的api requestTask.offChunkReceived()

2.关于如何处理onChunkReceived回调的结果

可以看到返回的结果为Uint8Array,而在小程序中由于不支持TextEncoder/TextDecoder对象 我的解决方式

  1. 先将unit8Array转化为十六进制
  2. 将十六进制转为中文字符串
    其中需要引入encoding.js和encoding-indexes.js两个文件
    这两个文件的来源为text-encoding下lib文件下的两个文件。
javascript
代码解读
复制代码
import encoding from ''./encoding.js''
javascript
代码解读
复制代码
decodeUint8Array(uint8Array) { const data16 = this.buf2hex(uint8Array); const requestData = this.hexToStr(data16) return requestData }, buf2hex(arrayBuffer) { return Array.prototype.map.call(new Uint8Array(arrayBuffer), x => (''00'' + x.toString(16)).slice(-2)).join(''''); }, /** * 十六进制字符串转中文 * @param {String} hex 为十六进制字符串 * @return {String} 包含中文的字符串 */ hexToStr(hex) { // 去掉字符串首尾空格 let trimedStr = hex.trim() // 判断trimedStr前两个字符是否为0x,如果是则截取从第三个字符及后面所有,否则返回全部字符 let rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr // 得到rawStr的长度 let len = rawStr.length // 如果长度不能被2整除,那么传入的十六进制值有误,返回空字符 if (len % 2 !== 0) { return "" } let curCharCode // 接收每次循环得到的字符 let resultStr = [] // 存转换后的十进制值数组 for (let i = 0; i < len; i = i + 2) { curCharCode = parseInt(rawStr.substr(i, 2), 16) resultStr.push(curCharCode) } // encoding为空时默认为utf-8 let bytesView = new Uint8Array(resultStr) // 8 位无符号整数值的类型化数组 let str = new encoding.TextDecoder().decode(bytesView) return str },

最终调用的伪代码,其中的chunkText为处理好的字符串。

ini
代码解读
复制代码
requestTask.onChunkReceived((res) => { let chunkText = this.decodeUint8Array(res.data); });

tips:不知道为什么在微信开发者工具的控制台中,即使接口响应成功还是看不到SSE的返回,如下图,只能通过console的方式来查看返回的数据。

New Image

如何实现打字机效果

在我们熟悉的大多AI产品中,它们的回答都是逐字出现的,这种效果我们也称为打字机效果 打字机的核心代码

ini
代码解读
复制代码
startTyping(text) { const strLength = text.length; let currentIndex = 0; const intervalTime = 100; let msg = ''''; let typingInterval = setInterval(() => { if (currentIndex < strLength) { //获取当前索引对应的字 let currentChar = text.charAt(currentIndex); msg += currentChar //将msg赋值给你需要的数据项即可 this.setData({ test:msg }); currentIndex++; } else { clearInterval(typingInterval); } }, intervalTime); },

最终效果

New Image

解释代码