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

uniapp中的流式输出

一、完整代码展示

  • 目前大多数的ai对话都是流式输出,也就是对话是一个字或者多个字逐一进行显示的
  • 下面是一个完整的流式显示程序,包含的用户的消息发出和ai的消息回复
<template><view class="chat-container"><view class="messages"><!-- 对话气泡 --><viewv-for="(message, index) in messages":key="index":class="['message', message.sender]"><text selectable="true">{{ message.text }}</text></view><!-- 加载状态 --><view v-if="isLoading" class="loading-spinner"></view></view><!-- 消息输入和发送按钮 --><view class="input-area"><textareav-model="inputMessage"placeholder="输入消息"@input="adjustInputHeight"></textarea><button @click="sendMessage">发送</button></view></view>
</template><script>
export default {data() {return {messages: [],inputMessage: '',isLoading: false,inputHeight: 48};},methods: {sendMessage() {//如果输出消息为空直接返回if (!this.inputMessage.trim()) return;// 添加用户消息this.messages.push({text: this.inputMessage,sender: 'user'});// 初始化AI消息const aiIndex = this.messages.length;this.messages.push({text: '',sender: 'ai'});// 重置输入this.inputMessage = '';this.isLoading = true;// 发起流式请求const url = 'http://localhost:8081/chat';const params = {session_id: 'token',content: this.inputMessage};uni.request({url: url + '?' + this.serializeParams(params),method: 'GET',header: {'Accept': 'text/event-stream',},success: (res) => {this.processStreamResponse(res.data, aiIndex);},fail: (err) => {console.error('请求失败:', err);this.isLoading = false;}});},processStreamResponse(data, aiIndex) {const chunks = data.split('\n');let chunkIndex = 0;const interval = setInterval(() => {if (chunkIndex >= chunks.length) {clearInterval(interval);this.isLoading = false;return;}const chunk = chunks[chunkIndex].replace('data:', '').trim();if (chunk) {this.messages[aiIndex].text += chunk;this.$forceUpdate();}chunkIndex++;}, 50);},serializeParams(params) {return Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');},adjustInputHeight(e) {const textarea = e.target;textarea.style.height = 'auto';textarea.style.height = textarea.scrollHeight + 'px';this.inputHeight = textarea.scrollHeight;}}
};
</script><style>
.chat-container {height: 100vh;display: flex;flex-direction: column;padding: 20px;background-color: #f5f5f7;
}.messages {flex: 1;overflow-y: auto;padding: 20px;
}.message {margin: 10px 0;padding: 12px 16px;border-radius: 16px;max-width: 70%;word-wrap: break-word;
}.message.user {background: linear-gradient(135deg, #cbe7ff, #cfe9ff);align-self: flex-end;
}.message.ai {background: linear-gradient(135deg, #f0f0f0, #e0e0e0);align-self: flex-start;
}.loading-spinner {border: 4px solid #f3f3f3;border-top: 4px solid #007aff;border-radius: 50%;width: 24px;height: 24px;animation: spin 1s linear infinite;margin: 20px auto;
}.input-area {display: flex;gap: 10px;margin-top: 20px;
}textarea {flex: 1;padding: 12px;border: 1px solid #ddd;border-radius: 8px;resize: none;
}button {padding: 12px 24px;background-color: #007aff;color: white;border: none;border-radius: 8px;cursor: pointer;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}
</style>

二、流式传输核心代码讲解

1、请求发起

  • 设置Accept: text/event-stream告知服务器需要流式响应
  • 通过session_id传递认证信息
  • 使用GET请求发送消息内容
uni.request({url: url + '?' + this.serializeParams(params),method: 'GET',header: {'Accept': 'text/event-stream',},success: (res) => {this.processStreamResponse(res.data, aiIndex);}
});

2、流式响应处理

  • 将响应数据按换行符分割成块
  • 使用setInterval控制显示速度(这里设置为 50ms / 块)
  • 逐块追加到 AI 消息中
  • 使用$forceUpdate强制刷新视图
processStreamResponse(data, aiIndex) {const chunks = data.split('\n');let chunkIndex = 0;const interval = setInterval(() => {if (chunkIndex >= chunks.length) {clearInterval(interval);this.isLoading = false;return;}const chunk = chunks[chunkIndex].replace('data:', '').trim();if (chunk) {this.messages[aiIndex].text += chunk;this.$forceUpdate();}chunkIndex++;}, 50);
}

3、加载状态管理

  • 在请求发起时显示加载状态
  • 响应处理完成后隐藏加载状态
// 发送消息时
this.isLoading = true;// 响应处理完成
clearInterval(interval);
this.isLoading = false;

4、数据格式处理 

  • 将参数对象序列化为 URL 查询字符串
  • 使用encodeURIComponent处理特殊字符
serializeParams(params) {return Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');
}

5、消息显示 

  • 使用 flex 布局实现消息气泡
  • 通过selectable="true"实现文本选中
  • 根据 sender 添加不同样式
<view v-for="(message, index) in messages" :class="['message', message.sender]"><text selectable="true">{{ message.text }}</text>
</view>

相关文章:

uniapp中的流式输出

一、完整代码展示 目前大多数的ai对话都是流式输出&#xff0c;也就是对话是一个字或者多个字逐一进行显示的下面是一个完整的流式显示程序&#xff0c;包含的用户的消息发出和ai的消息回复 <template><view class"chat-container"><view class&quo…...

理解 C++ 中的顶层 const 与底层 const(二十四)

1. 示例解析 下面的代码展示了不同 const 限定符的组合及其含义&#xff1a; int i 0; int *const p1 &i; // p1 是一个常量指针&#xff1a;p1 本身不可改变&#xff08;顶层 const&#xff09;&#xff0c;但 *p1 所指的 int 可修改 const int ci 42; …...

Linux之数据链路层

Linux之数据链路层 一.以太网1.1以太网帧格式1.2MAC地址1.3MTU 二.ARP协议2.1ARP协议工作流程2.2ARP协议格式 三.NAT技术四.代理服务4.1正向代理4.2反向代理 五.四大层的学习总结 一.以太网 在我们学习完了网络层后我们接下来就要进入数据链路层的学习了&#xff0c;在学习完网…...

如何在 vue 渲染百万行数据,vxe-table 渲染百万行数据性能对比,超大量百万级表格渲染

vxe-table 渲染百万行数据性能对比&#xff0c;超大量百万级表格渲染&#xff1b;如何在 vue 渲染百万行数据&#xff1b;当在开发项目时&#xff0c;遇到需要流畅支持百万级数据的表格时&#xff0c; vxe-table 就可以非常合适了&#xff0c;不仅支持强大的功能&#xff0c;虚…...

std::reference_wrapper 和 std::function的详细介绍

关于 std::reference_wrapper 和 std::function 的详细介绍及具体测试用例&#xff1a; 1. std::reference_wrapper&#xff08;引用包装器&#xff09; 核心功能 包装引用&#xff1a;将引用转换为可拷贝、可赋值的对象支持隐式转换&#xff1a;可自动转换为原始引用类型容器…...

如何封装一个上传文件组件

#今天用el-upload感到很多不方便&#xff0c;遂决定自己封装一个。注&#xff1a;本文不提供表面的按钮样式和文件上传成功后的样式&#xff0c;需要自己创建。本文仅介绍逻辑函数# 1&#xff0c;准备几个表面用来指引上传的元素 2&#xff0c;创造统一的隐藏文件上传输入框&…...

MySQL-5.7.37安装配置(Windows)

1.下载MySQL-5.7.37软件包并解压 2.配置本地环境变量 打开任务栏 搜索高级系统设置 新建MySQL的环境变量 然后在path中添加%MYSQL_HOME%\bin 3.在MySQL-5.7.37解压的文件夹下新建my.ini文件并输入以下内容 [mysqld]#端口号port 3306#mysql-5.7.27-winx64的路径basedirC:\mysq…...

CentOS与Ubuntu命令对比指南:从软件包管理到系统配置

CentOS与Ubuntu命令对比指南 作为两大主流Linux发行版,**CentOS(基于RHEL)和Ubuntu(基于Debian)**在日常运维中常因命令差异引发混淆。本文通过关键场景对比,助您快速掌握两者的核心操作区别。 一、软件包管理:yum/dnf vs apt 操作CentOSUbuntu更新软件源yum check-upd…...

鸿蒙北向应用开发:deveco 5.0 kit化文件相关2

鸿蒙北向应用开发:deveco 5.0 kit化文件相关 在kit化时,有时候会出现这样一种场景即你想把已有的d.ts导出换个名字,这样从名字上更贴合你的kit聚合 什么意思呢?比如现在有 ohos.hilog.d.ts 导出了hilog,现在你想kit化hilog,使得hilog导出名字为usrhilog,这样用户在使用你的k…...

《HelloGitHub》第 108 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对开源感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…...

C++可变参数

可变参数C风格的可变参数C风格可变参数的使用 C11可变参数模板递归展开参数包参数列表展开折叠表达式 STL中的emplace插入接口 可变参数 C风格的可变参数 可变参数是一种语言特性&#xff0c;可以在函数声明中使用省略号...来表示函数接受可变数量的参数。 例如典型的printf…...

光传输设备现状

随着运营商准备好其基础设施以应对新一代高带宽应用程序和 AI 部署&#xff0c;光传输网络 (OTN) 市场再次有望实现稳健增长。 隧道的尽头有光亮&#xff0c;OTN 市场在 2024 年最后一个季度表现强劲&#xff0c;设备供过于求的时代已经结束。 供应商表示设备订单量有所增加&…...

Python 笔记 (二)

Python Note 2 1. Python 慢的原因2. 三个元素3. 标准数据类型4. 字符串5. 比较大小: 富比较方法 rich comparison6. 数据容器 (支持*混装* )一、允许重复类 (list、tuple、str)二、不允许重复类 (set、dict)1、集合(set)2、字典(dict)3、特殊: 双端队列 deque 三、数据容器的共…...

nt!IopCompleteReques函数分析之IopUpdateOtherTransferCount和IopDequeueThreadIrp

VOID IopCompleteRequest( IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2 ) 第一部分&#xff1a; if (irp->UserEvent) { (VOID) KeSetEvent( …...

d2025329

目录 一、修复表中名字 二、患某种疾病的患者 三、最长连续子序列 四、二叉树的层序遍历 一、修复表中名字 1667. 修复表中的名字 - 力扣&#xff08;LeetCode&#xff09; concat(A,B)&#xff0c;将字符串A和B拼接left(str,len)&#xff0c;从字符串左边开始截取len个字…...

北斗导航 | 中国北斗卫星导航系统的发展历程——“三步走”战略:背景,信号频点,调制方式,短报文,等

中国北斗卫星导航系统的发展历程按照“三步走”战略逐步推进,从区域服务到全球覆盖,形成了北斗一号、北斗二号、北斗三号三代系统的迭代升级,展现了中国航天科技的自主创新与突破。以下是各阶段的核心内容与发展特点综述:一、北斗一号:中国卫星导航的奠基(1994-2003年) …...

cordova android12+升级一些配置注意事项

1.以android13为例 Cordova Android 13.0.0 cordova platform remove android cordova platform add android13.0.0Cordova Android 13.0.0 这里建议将android-studio升级到最新 build时若是需要到gradled安装失败 建议多试几次 或者直接用网页下载 找到 Android Studio 的 G…...

批量处理word里面表格的空白行

1&#xff0c;随便打开一个word文档。 2&#xff0c;按下Alt F11 VBA编辑器,在左侧的「工程资源管理器」窗口中找到Normal 项目,右键选择插入->模块。 弹出一下弹窗 3&#xff0c;输入一下代码 代码&#xff1a; Sub RemoveEmptyTableRows()Dim tbl As TableDim row As R…...

K8S学习之基础五十七:部署代码扫描工具sonarqube

部署代码扫描工具sonarqube 拉取postgres、sonarqube镜像&#xff0c;在harbor上创建postgres、sonarqube项目&#xff0c;将镜像上传至harbordocker pull postgres docker pull sonarqube docker tat postgres:latest 172.16.80.140/postgres/postgres:latest docker tat sona…...

Nginx 解决具有不安全、不正确或缺少 SameSite 属性的 Cookie方案

针对Nginx中Cookie的SameSite属性配置问题&#xff0c;以下是综合解决方案及注意事项&#xff1a; 一、基础配置方法 全局设置Cookie属性‌&#xff08;适用于Nginx直接生成Cookie&#xff09; 在nginx.conf的location块中通过add_header指令添加&#xff1a; add_header Se…...

音频知识 参数分析

通道布局 参考 通过pcm音频数据计算分贝 理解FFT和信号加窗原理及意义 dts音效大师教程...

使用 rsync 进行服务器文件同步与优化

使用 Rsync 工具在两台 Linux 服务器之间同步文件 Rsync 是一种高效的文件同步工具&#xff0c;它可以在本地或远程服务器之间同步文件和目录。Rsync 通过仅传输文件的变化部分来减少数据传输量&#xff0c;因此特别适合用于定期备份或同步大量数据。本文将详细介绍如何将 A 服…...

MySQL 的 SQL 语句执行顺序

MySQL 的 SQL 语句执行顺序并不完全按照代码的书写顺序执行&#xff0c;而是遵循一套固定的逻辑流程 1. FROM 和 JOIN 作用&#xff1a;确定查询的数据来源&#xff0c;包括表和它们的连接方式&#xff08;如 INNER JOIN, LEFT JOIN 等&#xff09;。 细节&#xff1a; 先执行…...

小型水库大坝安全及水雨情监测技术方案

一、小型水库监测系统构成 小型水库雨水情测报和大坝安全监测系统由水库监测站点、通信网络和监测平台等组成&#xff0c;系统总体架构如图所示。 水库监测站点设施包括&#xff1a;雨量计、水位计、视频监视设备、渗压计、量水堰计、变形监测仪器、数据采集仪、遥测终端、水准…...

scala简介和基础语法

Scala简介 Scala 是一门多范式&#xff08;multi-paradigm&#xff09;的编程语言&#xff0c;设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在 Java 虚拟机上&#xff0c;并兼容现有的 Java 程序。Scala 源代码被编译成 Java 字节码&#xff0c;所以它可…...

‘无法定位程序输入点kernel32.dll’详细的修复方法,一键快速修复kernel32.dll

在 Windows 系统运行过程中&#xff0c;若程序提示“无法定位程序输入点 kernel32.dll”&#xff0c;往往意味着程序调用了 kernel32.dll 中不存在或已变更的函数接口。作为系统的核心动态链接库&#xff0c;kernel32.dll 承担着内存管理、进程控制、文件操作等底层功能&#x…...

电源系统的热设计与热管理--以反激式充电器为例

前言 反激电源常用于各种电子设备中&#xff0c;比如充电器、适配器等&#xff0c;它们通过变压器进行能量转换。高温环境可能对电子元件造成影响&#xff0c;特别是像MOSFET、二极管、变压器这样的关键部件&#xff0c;导致效率变低&#xff0c;甚至可能导致功能失效。还有安…...

笔记本电脑更换主板后出现2203:System configuration is invalid,以及2201、2202系统错误的解决

笔记本电脑更换主板后启动出现2203:System configuration is invalid,以及2201、2202系统错误的解决 自用的一台ThinkpadT490笔记本电脑 ,由于主板故障,不得不更换主板,通过某宝购置主板后进行了更换。 具体拆卸笔记本可搜索网络视频教程。 注意: 在更换主板时,注意先拍…...

项目-苍穹外卖(十七) Apache POI+导出数据

一、介绍 二、入门案例 package com.sky.test;import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File; import java.io.FileNotFoundException; import jav…...

蓝桥杯单片机刷题——E2PROM记录开机次数

设计要求 使用E2PROM完成数据记录功能&#xff0c;单片机复位次数记录到E2PROM的地址0中。每复位一次数值加1&#xff0c;按下按键S4&#xff0c;串口发送复位次数。串口发送格式如下&#xff1a; Number&#xff1a;1 备注&#xff1a; 单片机IRC振荡器频率设置为12MHz。 …...