微信小程序对接chat gpt
最近公司开发的微信小程序需要接入chat gpt来完成一个智能聊天助手的需求。 前端开发过程中遇到些许问题,在此记录一下。
一、数据传输:由于chatgpt是使用流式传输,因此我们选择使用sse来创建连接。
这里介绍一下SSE: SSE(Server-Sent Events):是一种基于HTTP协议的,以流的形式由服务端持续向客户端发送数据的技术,是一种持久连接。
二、小程序中如何使用sse协议
微信小程序目前的Api不支持sse协议的接口,我们使用wx.request()接口来实现该功能。
代码如下:
// 创建sse连接,接收问答消息
getMsgBySSE() {
const that = this
const token = wx.getStorageSync('token') || '';
// 创建sse连接
const requestTask = wx.request({
url: `${hostUrl}/wx/chat/${uuid}`,
data: {
msg
},
enableChunked: true,
method: 'post',
timeout: 10000,
dataType: 'json',
header: {
'Authorization': token,
},
success: () => {
that.endAnswer()
},
complete: function () {
},
fail: err => {
that.failCallBack(err.errMsg)
that.scrollToBottom() // 页面跟随回答的消息滑动
}
})
// 监听 Transfer-Encoding Chunk Received 事件。当接收到新的chunk时触发。
requestTask.onChunkReceived(async (result) => {
const parser = createParser((event) => {
if (event.type !== 'event') return
// 回答结束
if (event.id === '[DONE]' || event.data === '[DONE]') {
that.endAnswer()
return
}
// 终止任务
if (that.data.isStop) {
requestTask.abort()
that.endAnswer()
return
}
// 回答中
try {
const data = JSON.parse(event.data)
const content = data.content
if (content) {
reply += content
that.setData({
answering: true,
thinking: false,
[`msgList[${index}].msg`]: reply, // 此处是将回答的消息渲染在页面上
[`msgList[${index}].id`]: data.id,
[`msgList[${index}].created_at`]: data.messageTime,
})
that.scrollToBottom() // 页面跟随消息内容滑动
}
} catch (e) {
that.failCallBack(e)
}
})
// 格式化数据
if (result.data) {
let unit8Arr = new Uint8Array(result.data);
let decodedString = this.utf8ArrayToStr(unit8Arr)
parser.feed(decodedString)
} else {
console.warn("result不存在", result)
}
})
},
因为接收到的结果数据类型固定为arrayBuffer,需要进行转换,可以使用下面方法进行转换
utf8ArrayToStr(array, startingIndex = 0) { // Based on code by Masanao Izumo <iz@onicos.co.jp> // posted at http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt const len = array.length; let c; let char2; let char3; let out = ''; let i = startingIndex || 0; while (i < len) { c = array[i++]; // If the character is 3 (END_OF_TEXT) or 0 (NULL) then skip it if (c === 0x00 || c === 0x03) { continue; } switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx out += String.fromCharCode(c); break; case 12: case 13: // 110x xxxx 10xx xxxx char2 = array[i++]; out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: // 1110 xxxx 10xx xxxx 10xx xxxx char2 = array[i++]; char3 = array[i++]; out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break; default: } } return out; }

浙公网安备 33010602011771号