智能体项目实现AI对话流式返回效果

news2025/4/4 23:34:59

1、智能体项目里与AI大模型对话的时候,需要从后端的流式接口里取数据并实现打字机渲染效果。这里涉及到 Markdown 格式的渲染,所以需要配合 marked.js 实现,安装 marked.js :

npm install marked

引用:

import { marked } from 'marked';

2、调用后端流式接口,并处理获取到的数据

         // 建立连接
        createSseConnect(){
            let token = '1215421542125'
            let that = this;
                // 创建一个 AbortController 实例
                that.abortController = new AbortController();
                
                //接口请求参数
                let sendData = {
                    message: that.currSendValue,
                    modelId:'1',
                }
                // 请求配置
                const config = {
                method: "post",
                headers: {
                    "Content-Type": "application/json",
                    Accept: "text/event-stream",
                    clientid: "112121212121212121212",
                    Authorization: "Bearer " + token, // 根据实际情况获取 token
                },
                body: JSON.stringify(sendData),
                signal: that.abortController.signal, // 将 AbortController 的 signal 传递给 fetch
                };
                let url = base.url + '/zntdata/stream';
                // 发起请求
                let thinkingTime = true;
                fetch(url, config)
                .then((response) => {
                const reader = response.body.getReader();
                const decoder = new TextDecoder("utf-8");
                let buffer = "";

                that.currSendValue = ''
                
                // 处理接收到的消息
                function processMessage(message) {
                    message = message.split("data:")[0];
                    
                    const newChars = message.split("");
                    //解析深度思考
                    if (message.includes("<think>")) {
                        thinkingTime = true;
                    }
                    if (message.includes("</think>")) {
                        thinkingTime = false;
                    }
                    if (thinkingTime) {
                        that.charQueue2.push(...newChars);
                    } else {
                        that.charQueue.push(...newChars);
                    }

                    if (message.includes("[DONE]")) {
                        that.dialogId = message.substring(9)
                    }

                    // 启动打字机效果(如果尚未启动)
                    if (!that.isTyping) {
                        that.startTyping();
                    }
                    return false;
                }

                // 读取流式数据
                function readStream() {
                    reader
                    .read()
                    .then(({ done, value }) => {
                        if (done) {
                            console.log("Stream ended",value);
                            return;
                        }

                        // 解码数据并添加到缓冲区
                        buffer += decoder.decode(value);

                        // 处理完整的事件 -- 非统一处理方法,需根据业务需求和接口数据格式处理
                        while (buffer.includes("data:")) {
                            if ( buffer.includes("[DONE]")) {
                               that.dialogId = 
                            buffer.substring(buffer.indexOf('id:')+3).replaceAll('\n','')
                            }
                            const eventEndIndex = buffer.indexOf("data:");
                            let eventData = buffer.slice(0,eventEndIndex);
                            buffer = buffer.slice(eventEndIndex+5);
                            eventData = eventData.substring(0,eventData.lastIndexOf('\n\n')) 
                            const message = eventData;
                            if (eventData) {
                                if (processMessage(message)) return;
                            }
                        }

                        // 继续读取
                        readStream();
                    }).catch((err) => {
                        console.error("Stream error:", err);
                        const lastQuestionIndex = that.dialogueList.length-1
                        that.dialogueList[lastQuestionIndex].content = that.dialogueList[lastQuestionIndex].content + '出错了,暂时无法回答您的问题,请稍后再试。'
                    });
                }

                    // 开始读取流
                    readStream();
                })
            },



         // 启动打字机效果
         startTyping() {
            const that = this;
            that.isTyping = true;
            const lastQuestionIndex = that.dialogueList.length-1

            // 初始间隔时间
            let intervalTime = 30; // 初始速度为 30ms
            const minIntervalTime = 5; // 最小间隔时间,防止速度过快
            const acceleration = 0.9; // 每次加速的比例(0.9 表示每次间隔时间减少 10%)

            // 清除已有定时器
            if (that.typingInterval) clearInterval(that.typingInterval);
            // 定义打字机效果函数
            function typeCharacter() {
                if (that.charQueue.length === 0 && that.charQueue2.length === 0) {
                   clearInterval(that.typingInterval);
                   that.isTyping = false;
                   return;
                }

                if (that.charQueue2.length > 0) {
                  if (that.dialogueList[lastQuestionIndex].content == '正在思考中...') {
                    that.dialogueList[lastQuestionIndex].content = ''
                  }
                   // 取出一个字符并更新界面
                  let char = that.charQueue2.shift();
                  if (char) {
                      that.thinkText += char;
                  }

                that.dialogueList[lastQuestionIndex].thinkText = marked.parse(that.thinkText) //渲染Markdown格式
                }

                if (that.charQueue.length > 0) {
                    let char = that.charQueue.shift();
                    if (char) {
                        that.answerWithFlow += char;
                    }

                    that.dialogueList[lastQuestionIndex].content = marked.parse(that.answerWithFlow) //渲染Markdown格式

                }


                // 滚动到底部
                that.scrollToSending();

                // 加速逻辑:减少间隔时间
                intervalTime = Math.max(minIntervalTime, intervalTime * acceleration);
                clearInterval(that.typingInterval); // 清除旧的定时器
                that.typingInterval = setInterval(typeCharacter, intervalTime); // 设置新的定时器
            }

            // 启动打字机效果
            that.typingInterval = setInterval(typeCharacter, intervalTime);
         },


         //保持最后一段对话实时出现在视口最下面
         scrollToSending() {
            this.$nextTick(() => {
                if (this.$refs.dialogueBox) {
                this.$refs.dialogueBox.scrollTop =
                    this.$refs.dialogueBox.scrollHeight +
                    this.$refs.dialogueBox.offsetHeight;
                }
            });
          },

3、渲染数据。要保持Markdown的格式输出,不能直接使用花括号{{}}渲染数据,需要结合v-html使用。

以上就能实现逐字渲染的一个AI大模型对话需求

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch中dataloader自定义数据集

前言 在深度学习中我们需要使用自己的数据集做训练&#xff0c;因此需要将自定义的数据和标签加载到pytorch里面的dataloader里&#xff0c;也就是自实现一个dataloader。 数据集处理 以花卉识别项目为例&#xff0c;我们分别做出图片的训练集和测试集&#xff0c;训练集的标…

SQL Server:触发器

在 SQL Server Management Studio (SSMS) 中查看数据库触发器的方法如下&#xff1a; 方法一&#xff1a;通过对象资源管理器 连接到 SQL Server 打开 SSMS&#xff0c;连接到目标数据库所在的服务器。 定位到数据库 在左侧的 对象资源管理器 中&#xff0c;展开目标数据库&a…

标题:利用 Rork 打造定制旅游计划应用程序:一步到位的指南

引言&#xff1a; 在数字化时代&#xff0c;旅游计划应用程序已经成为旅行者不可或缺的工具。但开发一个定制的旅游应用可能需要耗费大量时间与精力。好消息是&#xff0c;Rork 提供了一种快捷且智能的解决方案&#xff0c;让你能轻松实现创意。以下是使用 Rork 创建一个定制旅…

WebSocket原理详解(二)

WebSocket原理详解(一)-CSDN博客 目录 1.WebSocket协议的帧数据详解 1.1.帧结构 1.2.生成数据帧 2.WebSocket协议控制帧结构详解 2.1.关闭帧 2.2.ping帧 2.3.pong帧 3.WebSocket心跳机制 1.WebSocket协议的帧数据详解 1.1.帧结构 WebSocket客户端与服务器通信的最小单…

计算声音信号波形的谐波

计算声音信号波形的谐波 1、效果 2、定义 在振动分析中,谐波通常指的是信号中频率是基频整数倍的成分。基频是振动的主要频率,而谐波可能由机械系统中的非线性因素引起。 3、流程 1. 信号生成:生成或加载振动信号数据(模拟或实际数据)。 2. 预处理:预处理数据,如去噪…

RepoReporter 仿照`TortoiseSVN`项目监视器,能够同时支持SVN和Git仓库

RepoReporter 项目地址 RepoReporter 一个仓库监视器&#xff0c;仿照TortoiseSVN项目监视器&#xff0c;能够同时支持SVN和Git仓库。 工作和学习会用到很多的仓库&#xff0c;每天都要花费大量的时间在频繁切换文件夹来查看日志上。 Git 的 GUI 工具琳琅满目&#xff0c;Git…

UI设计系统:如何构建一套高效的设计规范?

UI设计系统&#xff1a;如何构建一套高效的设计规范&#xff1f; 1. 色彩系统的建立与应用 色彩系统是设计系统的基础之一&#xff0c;它不仅影响界面的整体美感&#xff0c;还对用户体验有着深远的影响。首先&#xff0c;设计师需要定义主色调、辅助色和强调色&#xff0c;并…

【计算机网络】记录一次校园网无法上网的解决方法

问题现象 环境&#xff1a;实训室教室内时间&#xff1a;近期突然出现 &#xff08;推测是学校在施工&#xff0c;部分设备可能出现问题&#xff09;症状&#xff1a; 连接校园网 SWXY-WIFI 后&#xff1a; 连接速度极慢偶发无 IP 分配&#xff08;DHCP 失败&#xff09;即使分…

第二十一章:Python-Plotly库实现数据动态可视化

Plotly是一个强大的Python可视化库&#xff0c;支持创建高质量的静态、动态和交互式图表。它特别擅长于绘制三维图形&#xff0c;能够直观地展示复杂的数据关系。本文将介绍如何使用Plotly库实现函数的二维和三维可视化&#xff0c;并提供一些优美的三维函数示例。资源绑定附上…

系统思考反馈

最近交付的都是一些持续性的项目&#xff0c;越来越感觉到&#xff0c;系统思考和第五项修炼不只是简单的一门课程&#xff0c;它们能真正融入到我们的日常工作和业务中&#xff0c;帮助我们用更清晰的思维方式解决复杂问题&#xff0c;推动团队协作&#xff0c;激发创新。 特…

【C++】vector常用方法总结

&#x1f4dd;前言&#xff1a; 在C中string常用方法总结中我们讲述了string的常见用法&#xff0c;vector中许多接口与string类似&#xff0c;作者水平有限&#xff0c;所以这篇文章我们主要通过读vector官方文档的方式来学习vector中一些较为常见的重要用法。 &#x1f3ac;个…

2025年数智化电商产业带发展研究报告260+份汇总解读|附PDF下载

原文链接&#xff1a;https://tecdat.cn/?p41286 在数字技术与实体经济深度融合的当下&#xff0c;数智化产业带正成为经济发展的关键引擎。 从云南鲜花产业带的直播热销到深圳3C数码的智能转型&#xff0c;数智化正重塑产业格局。2023年数字经济规模突破53.9万亿元&#xff…

Linux中常用服务器监测命令(性能测试监控服务器实用指令)

1.查看进程 ps -ef|grep 进程名以下指令需要先安装:sysstat,安装指令: yum install sysstat2.查看CPU使用情况(间隔1s打印一个,打印6次) sar -u 1 63.#查看内存使用(间隔1s打印一个,打印6次) sar -r 1 6

基于 GEE 的区域降水数据可视化:从数据处理到等值线绘制

目录 1 引言 2 代码功能概述 3 代码详细解析 3.1 几何对象处理与地图显示 3.2 加载 CHIRPS 降水数据 3.3 筛选不同时间段的降水数据 3.4 绘制降水时间序列图 3.5 计算并可视化短期和长期降水总量 3.6 绘制降水等值线图 4 总结 5 完整代码 6 运行结果 1 引言 在气象…

曲线拟合 | Matlab基于贝叶斯多项式的曲线拟合

效果一览 代码功能 代码功能简述 目标&#xff1a;实现贝叶斯多项式曲线拟合&#xff0c;动态展示随着数据点逐步增加&#xff0c;模型后验分布的更新过程。 核心步骤&#xff1a; 数据生成&#xff1a;在区间[0,1]生成带噪声的正弦曲线作为训练数据。 参数设置&#xff1a…

Qt6调试项目找不到Bluetooth Component蓝牙组件

错误如图所示 Failed to find required Qt component "Bluetooth" 解决方法&#xff1a;搜索打开Qt maintenance tool 工具 打开后&#xff0c;找到这个Qt Connectivity&#xff0c;勾选上就能解决该错误

JAVA- 锁机制介绍 进程锁

进程锁 基于文件的锁基于Socket的锁数据库锁分布式锁基于Redis的分布式锁基于ZooKeeper的分布式锁 实际工作中都是集群部署&#xff0c;通过负载均衡多台服务器工作&#xff0c;所以存在多个进程并发执行情况&#xff0c;而在每台服务器中又存在多个线程并发的情况&#xff0c;…

Java Spring Boot 与前端结合打造图书管理系统:技术剖析与实现

目录 运行展示引言系统整体架构后端技术实现后端代码文件前端代码文件1. 项目启动与配置2. 实体类设计3. 控制器设计4. 异常处理 前端技术实现1. 页面布局与样式2. 交互逻辑 系统功能亮点1. 分页功能2. 搜索与筛选功能3. 图书操作功能 总结 运行展示 引言 本文将详细剖析一个基…

深入剖析JavaScript多态:从原理到高性能实践

摘要 JavaScript多态作为面向对象编程的核心特性&#xff0c;在动态类型系统的支持下展现了独特的实现范式。本文深入解析多态的三大实现路径&#xff1a;参数多态、子类型多态与鸭子类型&#xff0c;详细揭示它们在动态类型系统中的理论基础与实践意义。结合V8引擎的优化机制…

GalTransl开源程序支持GPT-4/Claude/Deepseek/Sakura等大语言模型的Galgame自动化翻译解决方案

一、软件介绍 文末提供程序和源码下载 GalTransl是一套将数个基础功能上的微小创新与对GPT提示工程&#xff08;Prompt Engineering&#xff09;的深度利用相结合的Galgame自动化翻译工具&#xff0c;用于制作内嵌式翻译补丁。支持GPT-4/Claude/Deepseek/Sakura等大语言模型的…