微信小程序对接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;
    }

 

posted @ 2023-08-29 16:08  icon-icon  阅读(572)  评论(0)    收藏  举报