Uniapp仿ChatGPT Stream流式输出(非Websocket)
前言:流式输出可以使用websocket也可以使用stream来实现EventSource是 HTML5 中的一个接口,用于接收服务器发送的事件流(Server - Sent Events,SSE)。它提供了一种从服务器单向推送实时数据到 Web 页面的方式,使得 Web 应用能够以类似于事件驱动的模式获取更新,而不需要通过传统的轮询方式(不断地向服务器询问是否有新数据)。
请求和接收
使用代码
data ( ) {
return {
task : null ,
msg : "" ,
dataList : [ ] ,
}
} ,
methods : {
askAgain ( ) {
if ( this . msg) {
this . $util. showToast ( ` 请输入您的问题 ` )
return
}
this . $refs. paging. scrollToBottom ( )
setTimeout ( ( ) => {
if ( ! item) {
this . dataList. unshift ( {
content : msg,
type : 1 ,
end : true ,
name : 'me' ,
list : [ ] ,
id : new Date ( ) . getTime ( )
} )
}
this . dataList. unshift ( {
content : '' ,
content1 : '' ,
type : 0 ,
end : false ,
name : 'ai' ,
id : new Date ( ) . getTime ( )
} )
this . toSend ( msg) ;
this . $refs. paging. scrollToBottom ( )
} , 300 )
} ,
toSend ( msg ) {
const that = this ;
this . task = uni. request ( {
url : ` ${ getApp ( ) . globalData. requestUrl } ai/app/escort/ai/chat?question= ${ msg} ` ,
enableChunked : true ,
method : 'POST' ,
timeout : 900000 ,
data : {
"question" : msg,
"userId" : uni. getStorageSync ( 'wxopenid' ) ,
} ,
success : ( res ) => {
console. log ( res)
if ( res. statusCode == 200 ) {
}
} ,
fail : ( ) => {
}
} )
this . task. onChunkReceived ( ( res ) => {
let uint8Array = new Uint8Array ( res. data) ,
txt;
const type = Object . prototype. toString . call ( uint8Array) ;
if ( type === "[object Uint8Array]" ) {
txt = decodeURIComponent ( escape ( String. fromCharCode ( ... uint8Array) ) ) ;
} else if ( uint8Array instanceof ArrayBuffer ) {
const arr = new Uint8Array ( uint8Array) ;
txt = decodeURIComponent ( escape ( String. fromCharCode ( ... arr) ) ) ;
}
console. log ( txt)
txt. split ( '^' ) . forEach ( it => {
if ( it) {
let res = JSON . parse ( it)
console. log ( res)
that. dataList[ 0 ] . content1 += res. data
}
} )
} ) ;
} ,
}
以上为对话请求 和 流响应接收逻辑。
框架使用 z-paging
插件地址 z-paging 我的框架使用 z-paging 插件
文本回显 普通文本
< view class = "text-warp" >
{ { item. content } }
< / view>
含有标签结构的文本回显 如img video 等
插件地址 zero-markdown-view
< zero- markdown- view : markdown= "item.content" > < / zero- markdown- view>
流推送标签 会导致页面回显出标签 标签推送完才能展示出图片或视频
解决方法 声明新的变量接收 字符 遍历字符 当流中出现<img 字符开始截取 然后插入loading图片 当 图片标签尾部 /> 出现后 用截取的图片 替换掉 loading图片 以上为处理方法 , 可以解决zero-markdown-view 组件回显 带图片,标签的流数据时 闪烁的问题,以及标签的暴漏问题
流推送 字符长短不一,实现打字效果
每次推送调用递归方法 取一个字符
addNextCharacter ( ) {
if ( this . index < this . newVal. length) {
this . messages[ 0 ] . content += this . newVal[ this . index] ;
this . index++ ;
this . character = setTimeout ( ( ) => {
this . addNextCharacter ( )
} , Math. random ( ) * 150 + 30 )
} else {
clearTimeout ( this . character)
this . character = null
if ( ! this . stratSet) {
}
}
} ,