前端对接生成式AI接口(类ChatGPT)问题汇总

文章目录

前端实现对话流问题总结

流式数据传输问题

后台逻辑为一个模块的一大段数据返回一个流,例如一些表格信息、图表信息等都是一个流返回所有数据

后台Response Headers问题

起初后台设置的相应头为application/stream+json这是一种非标准的流式传输格式,导致控制台无法使用EventStream进行调试,不方便定位问题,后续修改为text/event-stream(被大多数现代浏览器原生支持)实现

大量数据分段接收问题
  • application/stream+json

同时由于每次流传输的是完整一个模块的内容,数据量较大,客户端接收时会切分成多次读取(注:服务端其实是完整发送的),那么在使用application/stream+json不会对一个完整的流进行标注,例如返回的数据可能为

复制代码
// 完整数据
"{"type":"update","value":1},{"type":"update","value":2},{"type":"update","value":3}"
// 实际接收
- fisrt stream
"{"type":"update","value":1},{"ty
- second stream
pe":"update","value":2},{"type":"update","value":3}"

那么要如何判断我多次接收到的数据是不是一个完整模块,这里我采取的方案为判断是否返回了一个完整的JSON,当然性能略差

js 复制代码
const reader = res.getReader()
let stringData = ''
reader.read().then(function processText({ done, value }) {
    if(done) {
        return
    }
    const text = new TextDecoder().decode(value)
    if(text) {
        stringData += text
        if(isValidJSON(stringData)) {
            console.log(JSON.parse(stringData)) // Do something
            stringData = ''
        }
    }
    return reader.read().then(processText)
}
function isValidJSON(data) {
  try {
    JSON.parse(data);
    return true;  // 如果解析成功,说明是有效的JSON
  } catch (e) {
    return false; // 如果解析失败,说明不是有效的JSON
  }
}
  • text/event-stream

使用text/event-stream格式,情况就会好很多,因为服务端发送的一个完整模块会在开头使用data:标注,不需要再额外判断

复制代码
// 完整数据
"data:{"type":"update","value":1},{"type":"update","value":2},{"type":"update","value":3}"
// 实际接收
- fisrt stream
"data:{"type":"update","value":1},{"ty
- second stream
pe":"update","value":2},{"type":"update","value":3}"

实现可以变换为

js 复制代码
const reader = res.getReader()
let stringData = ''
reader.read().then(function processText({ done, value }) {
    if(done) {
        return
    }
    const text = new TextDecoder().decode(value)
    if(text) {
        // 一个data:到下一个data:之间的值为一个完整JSON
        if(text.startsWith('data:')) {
            if(stringData) {
            	console.log(JSON.parse(stringData)) // Do something
            }
            stringData = decodedChunk.substring(5)
        } else {
            jsonString += decodedChunk
        }
    }
    return reader.read().then(processText)
}
多个流时间戳(Time)相同导致被合并的问题

在联调接口时发现有多个流合并在同一次返回中,观察接口EventStream发现当数据生成非常快时(一般是命中了大模型的缓存),流式数据的时间戳会完全相同,导致数据会在统一批次返回,形成这种返回结果。

复制代码
- fisrt stream
"data:{"type":"update","value":1},{"type":"update","value":2}"
"data:{"type":"update","value":3}"

这里的处理方式为让后端在发送每条数据时添加一个毫秒级的延迟,确保每个流的时间戳不同

中止对话问题

其实没什么难度,就是使用reader.cancel(),但有一个点要注意,创建reader的前提是已经建立好了连接,因此在建立连接的这段过程要么不显示中止按钮、要么实现取消发送,我这里采用不显示中止按钮

js 复制代码
// 流式传输返回请求头即为建立连接
async function send(){
	let isConnected = false
    await getData()
    isConnected = true
}
// 在发送完成的done状态也修改为isConnected为false表示结束

复制问题

实现复制功能要注意的一点是,因为浏览器的安全策略,navigator.clipboard需要在https或本地调试这种安全上下文中才有,所以我们的服务如果采用的是http协议,要实现适配,适配方案为创建DOM,获取DOM内容

js 复制代码
const giveCopy = (text) => {
  if (text) {
    if (navigator.clipboard && window.isSecureContext) {
      console.log('复制成功')
      return navigator.clipboard.writeText(text)
    } else {
      let textArea = document.createElement('textarea')
      textArea.value = text
      textArea.style.position = 'absolute'
      textArea.style.opacity = 0
      textArea.style.left = '-9999px'
      textArea.style.top = '-9999px'
      document.body.appendChild(textArea)
      textArea.focus()
      textArea.select()
      return new Promise((res, rej) => {
        document.execCommand('copy') ? res(console.log('复制成功')) : rej()
        textArea.remove()
      })
    }
  }
}

部署上线问题(Nginx缓冲导致)

流式传输为Server-Sent Events (SSE) ,当采用Nginx代理时,由于其默认的缓存和缓冲机制,会出现无法正常流式返回数据的问题

在一些浏览器可能会返回

复制代码
Request with the provided ID has already finished loading

因此需要配置Nginx

nginx 复制代码
proxy_buffering off; # 禁用Nginx缓冲
proxy_cache off; # 禁用缓存
相关推荐
Wyc7240939 分钟前
HTML:入门
前端·html
Sunny_lxm40 分钟前
自定义列甘特图,原生开发dhtmlxgantt根特图,根据数据生成只读根特图,页面展示html demo
前端·html·甘特图·dhtmlxgantt
熊猫钓鱼>_>2 小时前
建筑IT数字化突围:建筑设计企业的生存法则重塑
前端·javascript·easyui
GISer_Jing4 小时前
前端性能指标及优化策略——从加载、渲染和交互阶段分别解读详解并以Webpack+Vue项目为例进行解读
前端·javascript·vue
不知几秋4 小时前
数字取证-内存取证(volatility)
java·linux·前端
水银嘻嘻5 小时前
08 web 自动化之 PO 设计模式详解
前端·自动化
Zero1017137 小时前
【详解pnpm、npm、yarn区别】
前端·react.js·前端框架
&白帝&7 小时前
vue右键显示菜单
前端·javascript·vue.js
Wannaer7 小时前
从 Vue3 回望 Vue2:事件总线的前世今生
前端·javascript·vue.js
羽球知道8 小时前
在Spark搭建YARN
前端·javascript·ajax