Chatgpt回答流式返回数据处理

276 阅读2分钟

背景:开发一个Ai项目时,请求接口后返回的数据是流式的 TypedArray 类型

image.png

一、ArrayBuffer类型数据

1. 定义:

  • ArrayBuffer 是一个用于表示固定长度原始二进制数据缓冲区的对象

  • 本身不提供直接操作数据的方法

  1. 用途
  • 主要用于存储二进制数据。

  • 需要通过 TypedArray 或 DataView 来访问和操作其内容。

3. 特性:

  • 一旦创建,大小固定,不能调整。

  • 只能通过视图(如 TypedArray 或 DataView)来读取或写入数据。

  1. 创建示例
    const buffer = new ArrayBuffer(16); // 创建一个16字节的缓冲区
    

二、TypedArray类型数据

  1. 定义
  • TypedArray 是一组类型化数组的集合,用于在ArrayBuffer上操作特定类型的数值数据。

  • 包括Int8Array, Uint8Array, Uint16Array, Int32Array, Uint32Array...等等。

  1. 用途
  • 提供了一种在 ArrayBuffer 上操作特定类型数据的方式。

  • 允许以特定数值类型(如整数、浮点数)来读取和写入数据。

第一步:使用new Unit8Array() 处理

requestTask.onChunkReceived(response=>{
    let arrayBuffer = response.data /* TypedArray类型*/
    const arrayBufferss = new Uint8Array(arrayBuffer) /*使用new Uint8Array()转化*/  
})

第二步:使用String.fromCharCode() 转字符串

// 流式返回数据
requestTask.onChunkReceived(response=>{
    // console.log(response);
    let arrayBuffer = response.data /* TypedArray类型*/
    const arrayBufferss = new Uint8Array(arrayBuffer) /* 使用new Uint8Array()转化*/
    let string = ''
    for(let i = 0; i < arrayBufferss.length; i++){
        // unicode字符, 将Unicode码点值转换为对应的字符,并返回一个新的字符串
        string += String.fromCharCode(arrayBufferss[i]) 
    }
})

image.png

第三步:使用escapedecodeURIComponent解决乱码问题

先编码,再进行解码

let buffer = ''
// 流式返回数据
requestTask.onChunkReceived(response=>{
        // console.log(response);
        let arrayBuffer = response.data /* TypedArray类型*/
        const arrayBufferss = new Uint8Array(arrayBuffer) /* 使用new Uint8Array()转化*/
        let string = ''
        for(let i = 0; i < arrayBufferss.length; i++){
                // unicode字符, 将Unicode码点值转换为对应的字符,并返回一个新的字符串
                string += String.fromCharCode(arrayBufferss[i]) 
        }
        // 编码和解码
        buffer += decodeURIComponent(escape(string))
        console.log(buffer);
})

image.png

第四步:和后端返回数据保持一致

image.png

// 流式返回数据
requestTask.onChunkReceived(response=>{
        // console.log(response);
        let arrayBuffer = response.data /* TypedArray类型*/
        const arrayBufferss = new Uint8Array(arrayBuffer) /* 使用new Uint8Array()转化*/
        let string = ''
        for(let i = 0; i < arrayBufferss.length; i++){
                // unicode字符, 将Unicode码点值转换为对应的字符,并返回一个新的字符串
                string += String.fromCharCode(arrayBufferss[i]) 
        }
        // 编码和解码
        buffer += decodeURIComponent(escape(string))
        // 循环检查buffer里面是否包含换行符
        while(buffer.includes('\n')){
                const index = buffer.indexOf('\n')
                // 留下需要的
                const chunk = buffer.slice(0,index)
                // 去掉已经处理过
                buffer = buffer.slice(index + 1)
        }
})

image.png

第五步:处理不需要的字符串

// 流式返回数据
requestTask.onChunkReceived(response=>{
        // console.log(response);
        let arrayBuffer = response.data /* TypedArray类型*/
        const arrayBufferss = new Uint8Array(arrayBuffer) /* 使用new Uint8Array()转化*/
        let string = ''
        for(let i = 0; i < arrayBufferss.length; i++){
                // unicode字符, 将Unicode码点值转换为对应的字符,并返回一个新的字符串
                string += String.fromCharCode(arrayBufferss[i]) 
        }
        // 编码和解码
        buffer += decodeURIComponent(escape(string))
        // 循环检查buffer里面是否包含换行符
        while(buffer.includes('\n')){
                const index = buffer.indexOf('\n')
                // 留下需要的
                const chunk = buffer.slice(0,index)
                // 去掉已经处理过
                buffer = buffer.slice(index + 1)
                // 判断以data:开头并且不含有data: [DONE]
                if(chunk.startsWith('data: ') && !chunk.includes('[DONE]')){
                    const jsonData = JSON.parse(chunk.replace('data: ',''))
                }
        }
})

image.png