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


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

    可以扫码体验:

    后端关键代码:

    1. // 定义正则表达式
    2. String regex = "data:\\s*(\\{.*\\})";
    3. // 创建Pattern对象
    4. Pattern pattern = Pattern.compile(regex);
    5. String line;
    6. while ((line = reader.readLine()) != null) {
    7. // 处理每条数据
    8. // System.out.println(line);
    9. // 创建Matcher对象
    10. Matcher matcher = pattern.matcher(line);
    11. // 查找匹配项
    12. if (matcher.find()) {
    13. String dataValue = matcher.group(1);
    14. JSONObject jsonObject = JSON.parseObject(dataValue);
    15. String content = jsonObject.getString("result");
    16. Boolean end = jsonObject.getBoolean("is_end");
    17. JSONObject data = new JSONObject();
    18. data.put("content", content);
    19. data.put("end", end);
    20. data.put("type", "message");
    21. webSocketServer.sendInfo(uid.toString(), data.toJSONString());
    22. }
    23. }

    小程序ts代码:

    1. data: {
    2. messages: [], // 聊天消息列表
    3. inputValue: '', // 输入框的值
    4. ask: '', // 输入框的值
    5. socketOpen: false, // WebSocket 连接状态
    6. socketTask: null, // WebSocket 实例
    7. answering: false, // 回答中。。。
    8. type: 2,
    9. credit: 0,
    10. scrollTop: 0,
    11. }
    12. scrollToBottom() {
    13. // 在需要滚动到最底部的时机
    14. const query = wx.createSelectorQuery();
    15. query.select('.chat-container').boundingClientRect();
    16. query.select('.msgList').boundingClientRect();
    17. query.exec(res => {
    18. const scorllHeight = res[0].height;
    19. const listHeight = res[1].height;
    20. this.setData({
    21. scrollTop: listHeight - scorllHeight + 92
    22. });
    23. });
    24. },
    25. async onLoad() {
    26. const chatList = 历史聊天记录;
    27. const chatListMessage: any = [];
    28. if (chatList && chatList.length > 0) {
    29. chatList.map((v: any) => {
    30. const ask = {
    31. sender: 'user',
    32. avatar: '',
    33. content: v.ask,
    34. createTime: v.createTime,
    35. id: v.id,
    36. };
    37. const answer = {
    38. sender: 'chat',
    39. avatar: 'xxx',
    40. content: v.answer,
    41. id: v.id,
    42. }
    43. chatListMessage.push(ask);
    44. chatListMessage.push(answer);
    45. })
    46. }
    47. // 初始化聊天消息列表,包含一条欢迎消息
    48. const messages: any = [
    49. {
    50. sender: 'chat',
    51. avatar: 'xxx',
    52. content: `欢迎`
    53. },
    54. ...this.data.messages,
    55. ...chatListMessage
    56. ]
    57. // @ts-ignore
    58. this.setData({ messages });
    59. this.scrollToBottom();
    60. },
    61. //滾動到底部
    62. bindscroll() {
    63. // console.log(1);
    64. },
    65. onUnload: function () {
    66. // 页面卸载时关闭 WebSocket 连接
    67. this.closeSocket();
    68. },
    69. inputChange: function (e: any) {
    70. // 监听输入框值的变化
    71. this.setData({
    72. inputValue: e.detail.value
    73. });
    74. },
    75. async sendMessage() {
    76. // 发送消息
    77. const message = this.data.inputValue;
    78. if (message.trim() === '') {
    79. showToast("请输入问题");
    80. return;
    81. }
    82. // 添加用户发送的消息到聊天消息列表
    83. const newMessage = {
    84. sender: 'user',
    85. avatar: '',
    86. content: message
    87. };
    88. //@ts-ignore
    89. this.data.messages.push(newMessage);
    90. // 清空输入框
    91. this.setData({
    92. messages: this.data.messages,
    93. inputValue: '',
    94. });
    95. this.data.ask = message;
    96. // 发送消息到 Chat
    97. this.sendToChat(message);
    98. },
    99. sendToChat: function (message: any) {
    100. if (!this.data.socketOpen) {
    101. // 如果 WebSocket 连接未打开,则创建连接
    102. this.createSocket();
    103. }
    104. this.setData({ answering: true });
    105. // 这里请求后台
    106. // 处理 Chat 的回答消息
    107. const newMessage: any = {
    108. sender: 'chat',
    109. avatar: '',
    110. content: ""
    111. };
    112. //@ts-ignore
    113. this.data.messages.push(newMessage);
    114. // 更新聊天消息列表并滚动到最新消息
    115. this.setData({ messages: this.data.messages });
    116. this.scrollToBottom();
    117. },
    118. createSocket: function () {
    119. // 创建 WebSocket 连接
    120. const socketTask = wx.connectSocket({
    121. url: ``, // 替换为你的 WebSocket 服务器地址
    122. success: () => {
    123. console.log('WebSocket 连接成功');
    124. },
    125. fail: (error) => {
    126. console.error('WebSocket 连接失败', error);
    127. }
    128. });
    129. // 监听 WebSocket 连接打开事件
    130. socketTask.onOpen(() => {
    131. console.log('WebSocket 连接已打开');
    132. this.setData({
    133. socketOpen: true,
    134. socketTask: socketTask
    135. });
    136. });
    137. // 监听 WebSocket 接收到服务器的消息事件
    138. socketTask.onMessage((res: any) => {
    139. const data = JSON.parse(res.data);
    140. // console.log(data);
    141. if (data.type === 'message') {
    142. // 收到 Chat 的回答消息
    143. this.handleChatResponse(data);
    144. }
    145. });
    146. // 监听 WebSocket 连接关闭事件
    147. socketTask.onClose(() => {
    148. console.log('WebSocket 连接已关闭');
    149. this.setData({
    150. socketOpen: false,
    151. socketTask: null
    152. });
    153. });
    154. // 监听 WebSocket 错误事件
    155. socketTask.onError((error) => {
    156. console.error('WebSocket 错误', error);
    157. });
    158. },
    159. closeSocket: function () {
    160. if (this.data.socketOpen) {
    161. // 关闭 WebSocket 连接
    162. this.data.socketTask.close();
    163. }
    164. },
    165. handleChatResponse: async function (data: any) {
    166. // 处理 Chat 的回答消息
    167. const index = this.data.messages.length - 1;
    168. this.data.messages[index].content += data.content;
    169. // 更新聊天消息列表并滚动到最新消息
    170. this.setData({ messages: this.data.messages });
    171. if (data.end) {
    172. this.setData({ answering: false, messages: this.data.messages });
    173. this.data.ask = "";
    174. };
    175. this.scrollToBottom();
    176. },

    可以扫码体验:

     

  • 相关阅读:
    I.MX RT1176笔记(9)-- 程序异常追踪(CmBacktrace 和 segger rtt)
    ssm+校园疫情申报系统 毕业设计-附源码221228
    python面向对象
    实验七 组合数据类型
    【C++类和对象】const成员函数及流插入提取
    物联网?快来看 Arduino 上云啦
    HTML5+CSS3+JS小实例:涟漪特效按钮
    【redis】-使用Lua脚本解决多线程下的超卖问题以及为什么?
    论文-分布式-拜占庭将军问题
    redis 重启后数据丢失
  • 原文地址:https://blog.csdn.net/oKeYue/article/details/133546644