一、微信小程序-处理流式请求(sse)

目前AI比较火热,很多小程序都接入了AI功能,但是对于AI对话,很多都是使用websocket的解决方案,但是会带来一些复杂度,前后端都需要维护连接的状态。因此AI对话主流方案还是使用sse,相对比较简单和轻量。本文将会介绍微信小程序接入sse的简单示例。

二、基于RequestTask.onChunkReceived,实现流式数据处理

2.1、index.js

// index.js
// 请求任务
let task = null;

Page({
  data: {
    msg: ''
  },
  // 取消请求
  cancelRequest() {
    if (task) {
      console.log('cancel')
      task.abort()
    }
  },
  // 发起请求
  startRequest() {
    // 初始化消息内容,可忽略
    this.setData({
      msg: ''
    });

    // 实际发起请求,本文示例使用coze
    task = wx.request({
      url: 'https://api.coze.cn/v3/chat?conversation_id=7519696701909794856',
      header: {
        'content-type': 'application/json',
        'Authorization': 'Bearer pat_Ey1d7Ix9urMKVE99xd7doplsMGAhE4UpwDqe7mP9F5mACb1mJB39q3zAf06p1UQn'
      },
      method: 'POST',
      enableChunked: true,
      data: {
        "bot_id": "7478216525708247078",
        "user_id": "123456",
        "stream": true,
        "additional_messages": [
          {
            "role": "user",
            "type": "question",
            "content_type": "text",
            "content": "你好"
          }
        ]
      },
      responseType:'arraybuffer',
      success: (res) => {
        // 请求完成回调用
      },
    });

    // 缓存数据
    let buffer = '';
    task.onChunkReceived((res) => {
      // 由于返回数据为二进制,需要进行解析
      const chunk = this.decodeChunk(res.data);
      if (!chunk) return;
      
      buffer += chunk;
      
      if (buffer.includes('\n\n')) {
        this.parseSSEData(buffer);
        buffer = '';
      }
    });
  },
  // 处理sse数据
  parseSSEData(text) {
    const messages = text.split('\n\n');
    for (const message of messages) {
      // 这里需要根据实际sse内容进行处理
      if (!message.includes('event:conversation.message.delta')) continue;
      
      const dataMatch = message.match(/data:(.+)/);
      if (!dataMatch) continue;
      
      try {
        const jsonData = JSON.parse(dataMatch[1]);
        this.setData({
          msg: this.data.msg + jsonData.content
        });
      } catch (e) {
        console.error('JSON解析错误:', e);
      }
    }
  },
  // 解析二进制数据
  decodeChunk(data) {
    // 兼容处理,真机返回的的是 ArrayBuffer
    if (data instanceof ArrayBuffer) {
      data = new Uint8Array(data);
    }
    try {
      // 由于小程序真机不支持TextEncoder/TextDecoder,因此需要使用其他方式
      return decodeURIComponent(escape(String.fromCharCode.apply(null, data)));
    } catch (e) {
      console.error('解码错误:', e);
      return '';
    }
  },
})

2.2、index.wxml

<!--index.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
  <view class="container">
    <view class="text-box" scroll-y="true" scroll-top="{{scrollTop}}">
      <text>{{msg}}</text>
    </view>
    <button bindtap="startRequest">发起请求</button>
    <button bindtap="cancelRequest">取消请求</button>
  </view>
</scroll-view>

2.3、显示效果

在这里插入图片描述
在这里插入图片描述

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐