微信小程序WebSocket实现stream流式聊天对话功能

要在微信小程序实现聊天对话功能,回话是流式应答,这里使用了WebSocket技术。WebSocket大家应该都很熟悉,使用wx.connectSocket就可以了。这里可能需要注意下的是流式应答,后端如何发送,前端如何接收。直接上代码:

可以扫码体验:

后端关键代码:

// 定义正则表达式String regex = "data:\\s*(\\{.*\\})";// 创建Pattern对象Pattern pattern = Pattern.compile(regex);String line;while ((line = reader.readLine()) != null) {// 处理每条数据// System.out.println(line);// 创建Matcher对象Matcher matcher = pattern.matcher(line);// 查找匹配项if (matcher.find()) {String dataValue = matcher.group(1);JSONObject jsonObject = JSON.parseObject(dataValue);String content = jsonObject.getString("result");Boolean end = jsonObject.getBoolean("is_end");JSONObject data = new JSONObject();data.put("content", content);data.put("end", end);data.put("type", "message");webSocketServer.sendInfo(uid.toString(), data.toJSONString());}}

小程序ts代码:

data: {messages: [],    // 聊天消息列表inputValue: '',  // 输入框的值ask: '',  // 输入框的值socketOpen: false,  // WebSocket 连接状态socketTask: null,  // WebSocket 实例answering: false, // 回答中。。。type: 2,credit: 0,scrollTop: 0,}
scrollToBottom() {// 在需要滚动到最底部的时机const query = wx.createSelectorQuery();query.select('.chat-container').boundingClientRect();query.select('.msgList').boundingClientRect();query.exec(res => {const scorllHeight = res[0].height;const listHeight = res[1].height;this.setData({scrollTop: listHeight - scorllHeight + 92});});},
async onLoad() {const chatList = 历史聊天记录;const chatListMessage: any = [];if (chatList && chatList.length > 0) {chatList.map((v: any) => {const ask = {sender: 'user',avatar: '',content: v.ask,createTime: v.createTime,id: v.id,};const answer = {sender: 'chat',avatar: 'xxx',content: v.answer,id: v.id,}chatListMessage.push(ask);chatListMessage.push(answer);})}// 初始化聊天消息列表,包含一条欢迎消息const messages: any = [{sender: 'chat',avatar: 'xxx',content: `欢迎`},...this.data.messages,...chatListMessage]// @ts-ignorethis.setData({ messages });this.scrollToBottom();},//滾動到底部bindscroll() {// console.log(1);},onUnload: function () {// 页面卸载时关闭 WebSocket 连接this.closeSocket();},inputChange: function (e: any) {// 监听输入框值的变化this.setData({inputValue: e.detail.value});},async sendMessage() {// 发送消息const message = this.data.inputValue;if (message.trim() === '') {showToast("请输入问题");return;}// 添加用户发送的消息到聊天消息列表const newMessage = {sender: 'user',avatar: '',content: message};//@ts-ignorethis.data.messages.push(newMessage);// 清空输入框this.setData({messages: this.data.messages,inputValue: '',});this.data.ask = message;// 发送消息到 Chatthis.sendToChat(message);},sendToChat: function (message: any) {if (!this.data.socketOpen) {// 如果 WebSocket 连接未打开,则创建连接this.createSocket();}this.setData({ answering: true });// 这里请求后台// 处理 Chat 的回答消息const newMessage: any = {sender: 'chat',avatar: '',content: ""};//@ts-ignorethis.data.messages.push(newMessage);// 更新聊天消息列表并滚动到最新消息this.setData({ messages: this.data.messages });this.scrollToBottom();},createSocket: function () {// 创建 WebSocket 连接const socketTask = wx.connectSocket({url: ``,  // 替换为你的 WebSocket 服务器地址success: () => {console.log('WebSocket 连接成功');},fail: (error) => {console.error('WebSocket 连接失败', error);}});// 监听 WebSocket 连接打开事件socketTask.onOpen(() => {console.log('WebSocket 连接已打开');this.setData({socketOpen: true,socketTask: socketTask});});// 监听 WebSocket 接收到服务器的消息事件socketTask.onMessage((res: any) => {const data = JSON.parse(res.data);// console.log(data);if (data.type === 'message') {// 收到 Chat 的回答消息this.handleChatResponse(data);}});// 监听 WebSocket 连接关闭事件socketTask.onClose(() => {console.log('WebSocket 连接已关闭');this.setData({socketOpen: false,socketTask: null});});// 监听 WebSocket 错误事件socketTask.onError((error) => {console.error('WebSocket 错误', error);});},closeSocket: function () {if (this.data.socketOpen) {// 关闭 WebSocket 连接this.data.socketTask.close();}},handleChatResponse: async function (data: any) {// 处理 Chat 的回答消息const index = this.data.messages.length - 1;this.data.messages[index].content += data.content;// 更新聊天消息列表并滚动到最新消息this.setData({ messages: this.data.messages });if (data.end) {this.setData({ answering: false, messages: this.data.messages });this.data.ask = "";};this.scrollToBottom();},

可以扫码体验:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/124301.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uboot启动流程-涉及s_init汇编函数

一. uboot启动涉及函数 本文简单分析uboot启动流程中,涉及的汇编函数: lowlevel_init函数调用的函数:s_init 函数 save_boot_params_ret函数调用的函数: _main 函数 本文继上一篇文章的学习,地址如下:…

如何实现torch.arange的tensor版本

文章目录 背景实现方案不可行的情况 背景 import torch我们都知道,torch.arange只支持数字,不支持tensor,如下: torch.arange(0,5,1)tensor([0, 1, 2, 3, 4]) 但是如果使用tensor,就会报错: torch.arang…

正点原子嵌入式linux驱动开发——U-boot顶层Makefile详解

在学习uboot源码之前,要先看一下顶层Makefile,分析gcc版本代码的时候一定是先从顶层Makefile开始的,然后再是子Makefile,这样通过层层分析Makefile即可了解整个工程的组织结构。顶层Makefile也就是uboot根目录下的Makefile文件&am…

word已排序好的参考文献,插入新的参考文献,序号更新

原排序好的文献序号。 现在在3号后面插入一个新文献。4,5号应该成为5,6 这时在3号后面,回车,就会自动的增长。如下图: 但是如果手滑,把[4]删除了如何排序?? 如下图: …

数据分析与挖掘: 红楼梦人物关系(Python)词云图

一: 角色剧本 第一代:水字辈祖宗创下基业 贾源、贾演兄弟二人帮先帝打江山立下战功,贾演被封为宁国公(大约有平定江山安宁天下之意),贾源被封荣国公(大约有强国富民之功)。贾源贾演二兄弟皆是一…

23.2 Bootstrap 卡片

1.卡片 1.1卡片样式 在Bootstrap 5中, .card, card-header, .card-body, .card-footer类是用于创建卡片样式.下面是这些类的简单介绍: * 1. .card: 用于创建一个基本的卡片容器它作为一个包裹元素,通常与其他卡片类一起使用.* 2. .card-header: 用于创建卡片的头部部分.通常在…

Scala第十六章节

Scala第十六章节 scala总目录 文档资料下载 章节目标 掌握泛型方法, 类, 特质的用法了解泛型上下界相关内容了解协变, 逆变, 非变的用法掌握列表去重排序案例 1. 泛型 泛型的意思是泛指某种具体的数据类型, 在Scala中, 泛型用[数据类型]表示. 在实际开发中, 泛型一般是结合…

编程新手?跟着这个教程,用Python画出小猪佩奇

小猪佩奇是许多小朋友们的心头好,它的形象可爱、颜色鲜艳。你知道吗,只需要Python中的一个简单模块,我们就可以自己绘制出这个可爱的形象!本文将教你如何使用Python的turtle模块,一步步画出小猪佩奇。 1. 准备工作&a…

mybatis项目启动报错:reader entry: ���� = v

问题再现 解决方案一 由于指定的VFS没有找,mybatis启用了默认的DefaultVFS,然后由于DefaultVFS的内部逻辑,从而导致了reader entry乱码。 去掉mybatis配置文件中关于别名的配置,然后在mapper.xml文件中使用完整的类名。 待删除的…

创建线程池

如何创建线程池及处理相应任务 目录 如何创建线程池及处理相应任务线程池定义解决的问题(需求)工作原理实现线程池创建示意图重要构造器创建线程池(ExecutorService)线程池任务处理常用API处理Runnable任务处理Callable任务 使用工具类(Executors)创建线程池常用API应用案例 拓…

SG Former论文学习笔记

超越SWin和CSWin Transformer的新模型 代码地址:https://github.com/OliverRensu/SG-Former 论文地址:https://arxiv.org/pdf/2308.12216.pdf ViT在各种视觉任务中虽然成功,但它的计算成本随着Token序列长度的增加呈二次增长,这在…

OpenGLES:绘制一个混色旋转的3D球体

一.概述 前面几篇博文讲解了如何使用OpenGLES实现不同的3D图形 本篇博文讲解怎样实现3D世界的代表图形:一个混色旋转的3D球体 二.球体解析 2.1 极限正多面体 如果有学习过我前几篇3D图形绘制的博文,就知道要想绘制一个3D图形,首先要做的…