当前位置: 首页 > article >正文

Uniapp仿ChatGPT Stream流式输出(非Websocket)

Uniapp仿ChatGPT Stream流式输出(非Websocket)

前言:流式输出可以使用websocket也可以使用stream来实现EventSource是 HTML5 中的一个接口,用于接收服务器发送的事件流(Server - Sent Events,SSE)。它提供了一种从服务器单向推送实时数据到 Web 页面的方式,使得 Web 应用能够以类似于事件驱动的模式获取更新,而不需要通过传统的轮询方式(不断地向服务器询问是否有新数据)。

请求和接收

  1. 使用代码
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, // 此为消息类别,设 1 为发出去的消息,0 为收到对方的消息,
					end: true,
					name: 'me',
					list: [],
					id: new Date().getTime()
				})
			}
			this.dataList.unshift({
				content: '', // 消息内容
				content1: '', // 消息内容
				type: 0, // 此为消息类别,设 1 为发出去的消息,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, // 设置超时时间为10秒
			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) {
				// 将ArrayBuffer转换为Uint8Array	
				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
				}
			})
		});
	},
}

  1. 以上为对话请求 和 流响应接收逻辑。

框架使用 z-paging

  1. 插件地址 z-paging
  2. 我的框架使用 z-paging 插件
    在这里插入图片描述

文本回显 普通文本

<view class="text-warp">
	{{ item.content }}
</view>

含有标签结构的文本回显 如img video 等

  1. 插件地址 zero-markdown-view
<zero-markdown-view :markdown="item.content"></zero-markdown-view>

流推送标签 会导致页面回显出标签 标签推送完才能展示出图片或视频

  1. 解决方法 声明新的变量接收 字符
  2. 遍历字符 当流中出现<img 字符开始截取 然后插入loading图片
  3. 当 图片标签尾部 /> 出现后 用截取的图片 替换掉 loading图片
  4. 以上为处理方法 , 可以解决zero-markdown-view 组件回显 带图片,标签的流数据时 闪烁的问题,以及标签的暴漏问题

流推送 字符长短不一,实现打字效果

  1. 每次推送调用递归方法 取一个字符
	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){
				// 此处在请求完成后 清空所有的数据
			}
		}
	},

以上为开发中聊天功能 问题整理。代码有点乱,暂不付代码。有问题还请私信。 代码地址https://gitee.com/xyx904/ai/tree/master/artShow


http://www.kler.cn/a/488408.html

相关文章:

  • Springboot——钉钉(站内)实现登录第三方应用
  • MySQL 视图 存储过程与存储函数
  • oracle位运算、左移右移、标签算法等
  • el-table表格合并某一列
  • Mac中配置vscode(第一期:python开发)
  • 用OpenCV实现UVC视频分屏
  • UML(统一建模语言)
  • VUE3 VITE项目在 npm 中,关于 Vue 的常用命令有一些基础命令
  • clickhouse 离线包安装(ubuntu)
  • SOLIDWORKS 或 AutoCAD:选择CAD 解决方案时应考虑哪些问题?
  • TR-069协议学习--Soap报文、事件、RPC方法
  • ubuntu报错:没有在该文件夹中粘贴文件的权限
  • 【Unity功能集】TextureShop纹理工坊(十二)画笔工具、橡皮擦工具
  • 初学stm32 --- DAC输出
  • 谷歌浏览器的文件管理与上传功能
  • 【C++】22.AVL树实现
  • Excel中SUM求和为0?难道是Excel有Bug!
  • 爬虫数据抓取中的维度
  • micro-app【微前端系列教程】生命周期
  • JVM远程调试原理剖析
  • Apache XMLBeans 一个强大的 XML 数据处理框架
  • 【LLM文本分类微调】骚扰邮件分类
  • day 36 tcp协议粘包问题 http协议
  • 定时器中断方式
  • VUE + pdfh5 实现pdf 预览,主要用来uniappH5实现嵌套预览PDF
  • openGauss系列 --启动和停止服务器