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

vue3之写一个aichat---已聊天组件部分功能

渲染聊天数据

这个不必多说,直接从stores/chat中取出聊天列表数据渲染就好,因为前面添加的消息都是按照用户消息、AI助手消息这样添加的,效果如图
在这里插入图片描述

但是需要注意每条助手消息的状态,需要根据状态显示不同的图标或不显示图标,比如,正常完成的回答,不显示图标,如果是调用流式回调的接口出错的或者中途停止的,且是chatRecordList中的最后一条消息,那么就要显示重新生成的图标,点击重新生成会重新发送消息
重新发送的逻辑处理,主要是找到当前的AI助手消息将其状态变为stop停止状态,然后找到当前AI助手消息之前的最后一条用户消息获取其content,去调用stores/chat中的startChat方法从而走到聊天处理逻辑的文件中去

const handleRefresh = async messageId => {try {const message = props.messages.find(msg => msg.id === messageId)if (message && message.role === 'assistant') {// 设置为等待状态message.status = 'stop'// 找到当前助手消息之前的最后一条用户消息const messageIndex = props.messages.findIndex(msg => msg.id === messageId)let lastUserMessage = nullfor (let i = messageIndex; i >= 0; i--) {if (props.messages[i].role === 'user') {lastUserMessage = props.messages[i]break}}if (lastUserMessage) {try {// 直接使用用户消息重新请求await chatStore.startChat(lastUserMessage.content)} catch (error) {// 如果失败,恢复原状态message.status = 'error'console.error('重新生成失败:', error)}}}} catch (error) {console.error('处理重新生成失败:', error)}
}

生成AI助手消息时,滚动条自动滚动向下

在聊天时要自动滚动到最新消息的位置,使用户能看到最新的消息
因为已聊天组件和未聊天组件的切换写在Chat.vue页面中,所以scrollToBottom定义到Chat.vue中才能正常的实现这个功能
在这里插入图片描述
通过scrollTo方法将top设为container.scrollHeight即元素内容的总高度,包括由于滚动而看不见的内容,浏览器会将滚动条的位置设置为元素内容的底部,由于scrollHeight是元素内容的总高度,因此滚动条会被移动到内容的最底部,从而实现滚动到底部的效果

// 滚动到底部
const scrollToBottom = () => {setTimeout(() => {const container = document.querySelector('.chat-container')if (container) {container.scrollTo({top: container.scrollHeight,behavior: 'smooth'})}}, 100)
}

当chatRecordList变化的时候,自动触发滚动到底部的函数,isClickThought是因为在显示正式的回答前会显示思考的过程,思考完成后,开始回答问题时,会将思考的内容收起,通过点击按钮控制思考内容的显示与隐藏,但是当点击思考内容变化的时候,我们是不希望滚动条滚动的,所以就通过isClickThought来控制

watch(() => chatRecordList.value,async (newList, oldList) => {await nextTick()if (!isClickThought.value) {scrollToBottom()// 短暂延迟后检查滚动位置setTimeout(() => {isScrolledToBottom()}, 100)}isClickThought.value = false},{ deep: true }
)

当消息特别多的时候,有时候可能需要查看之前的聊天内容,查看完成后可能需要继续提问,但是由于内容特别多,手动往下翻肯定费劲,所以需要一个“置底”按钮,这个按钮只有在没有消息生成的时候才会出现,不然滚动条变化的时候页面显示不友好,点击的时候直接调用scrollToBottom函数就行,isScrolledToBottom判断是否显示该按钮

const isScrolledToBottom = () => {const container = chatContainer.valueif (!container) return true// 计算是否接近底部(允许20px的误差)const isAtBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 20isShowToBottom.value = !isAtBottom && !isResponding.value
}

停止当前对话和开启新对话功能

通过计算属性isResponding判断是显示“停止”还是显示“开启新对话”,当进入已聊天界面且没有正在回答的消息的时候,显示“开启新对话”按钮,否则显示停止
在这里插入图片描述

const isResponding = computed(() => {const lastMessage = chatRecordList.value[chatRecordList.value.length - 1]return lastMessage?.role === 'assistant' && ['thinking', 'typing'].includes(lastMessage.status)
})

点击停止按钮
触发chatStore中的停止响应函数

const handleStopResponse = () => {chatStore.stopResponse()
}

stores/chat.js,其中isResponseStopped是在chat.service.js判断是否需要停止响应用到的

  const isResponseStopped = ref(false) //是否停止响应function stopResponse() {isResponseStopped.value = true// 确保调用 abortRequestabortRequest()const lastMessage = chatRecordList.value[chatRecordList.value.length - 1]//获取到最后一条聊天记录if (lastMessage && lastMessage.role === 'assistant') {if (lastMessage.status === 'thinking') {//如果当前AI助手消息的状态是思考中则将状态变为stop停止状态lastMessage.status = 'stop'} else if (lastMessage.status === 'typing') {//如果当前AI助手消息的状态是已经构建回答但尚未完成,则将状态设为已完成lastMessage.status = 'done'}}}

如果当前停止的消息是最后一条AI助手消息那么就又会有handleRefresh
点击开启新会话
开启新会话调用chatStore.newChat()方法

const handleNewChat = () => {chatStore.newChat()
}

stores/chat.js
开启新对话要把之前的对话列表、是否已聊天等状态重置

  // 清除聊天状态const clearChatState = () => {hasChatted.value = falsechatRecordList.value = []assistantMessageId.value = nullisResponseStopped.value = falsesessionId.value = ''isHistory.value = falsehistoryTime.value = ''recommendedQuestions.value = []isFromRecommend.value = false}const newChat = () => {clearChatState()setSessionId(chatService.getRandomSessionId())}cosnt setSessionId = (id) => {sessionId.value = id}

每个回答完成会根据当前的问题返回对应的三条推荐,当点击推荐的时候会在当前页面发送一个新的问题

// 点击推荐问题,发送问题
const handleRecommend = item => {chatStore.setRecommendedQuestions([])chatStore.startChat(item) // 添加 true 标识这是推荐问题
}

记住推荐问题一般都是跟在最后一条消息后面的,所以每次调用会话接口的时候要记得将setRecommendedQuestions列表置空

相关文章:

vue3之写一个aichat---已聊天组件部分功能

渲染聊天数据 这个不必多说&#xff0c;直接从stores/chat中取出聊天列表数据渲染就好&#xff0c;因为前面添加的消息都是按照用户消息、AI助手消息这样添加的&#xff0c;效果如图 但是需要注意每条助手消息的状态&#xff0c;需要根据状态显示不同的图标或不显示图标&…...

ffmpeg+ubuntu编译库(完整版本)

个人使用环境: ubuntu desktop 16.04 + ffmpeg 4.2.1创建目录在home目录下创建 ffmpeg_sources:用于下载源文件 ffmpeg_build: 存储编译后的库文件 bin:存储二进制文件(ffmpeg,ffplay,ffprobe,X264,X265等) mkdir ffmpeg_sources ffmpeg_build bin安装依赖 先执行…...

基于STC89C51的太阳自动跟踪系统的设计与实现—单片机控制步进电机实现太阳跟踪控制(仿真+程序+原理图+PCB+文档)

摘 要 随着我国经济的飞速发展&#xff0c;促使各种能源使用入不敷出&#xff0c;尤其是最主要的能源&#xff0c;煤炭石油资源不断消耗与短缺&#xff0c;因此人类寻找其他替代能源的脚步正在加快。而太阳能则具有无污染﹑可再生﹑储量大等优点&#xff0c;且分布范围广&…...

第五: redis 安装 / find 查找目录

redis 安装的 两种方式&#xff1a; mac上安装redis的两种方法_如何在mac上安装redis-CSDN博客 首先可以先看一下brew的常用命令如下&#xff1a; brew search ** //查找某个软件包 brew list //列出已经安装的软件的包 brew install ** //安装某个软件包,默认安装的是…...

c++--vector

1.定义vector vector的定义分为四种 (1)vector() ——————无参构造 (2)vector(size_t n,const value_type& val value_type()) ——————构造并初始化n个val (3)vector(const vector& v1) ———————拷贝构造 (4)vector(inputiterator first,inpu…...

Springboot 项目如何输出优雅的日志

我们先看效果图&#xff1a; 我个人比较喜欢这种格式的日志输出&#xff0c;对其完整&#xff1b; 这种格式其实就是默认的&#xff0c;不需要大家配置任何的 logback-spring 文件和xml中配置日志level 没有做任何多余的配置&#xff1b;...

Linux——进程(5)进程地址空间

先看一个程序和现象 预期现象是&#xff0c;子进程和父进程相互独立&#xff0c;子进程的gval是100&#xff0c;101&#xff0c;102....而父进程一直都是100. 结果我们并不意外&#xff0c;只是我们发现&#xff0c;父子进程的gval的地址是一样的&#xff0c;这有点颠覆我们的认…...

代码随想录_动态规划

代码随想录 动态规划 509.斐波那契数 509. 斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n…...

c库、POSIX库、C++库、boost库之间的区别和联系

文章目录 一、区别1. 定义和来源2. 功能范围3. 可移植性4. 语言支持5. 维护和更新 二、联系1. 相互补充2. 部分功能重叠3. 共同促进编程发展4. 代码兼容性 三、总结 一、区别 1. 定义和来源 C 库函数&#xff1a;由 ANSI C 和 ISO C 标准定义&#xff0c;是 C 语言编程的基础…...

Maven常见问题汇总

Maven刷新,本地仓库无法更新 现象 This failure was cached in the local repository and resolution is not reattempted until the update interval of aliyunmaven has elapsed or updates are forced原因 因为上一次尝试下载&#xff0c;发现对应的仓库没有这个maven配置…...

星越L_陡坡缓降使用讲解

目录 1.陡坡缓降 1.陡坡缓降 中控屏下滑-点击陡坡缓降功能 35km/h以下时生效。35km/h-60km/h该功能暂停 60km/h以上该功能关闭...

XSS跨站脚本攻击漏洞(Cross Site Scripting)

前提概要 本文章主要用于分享XSS跨站脚本攻击漏洞基础学习&#xff0c;以下是对XSS跨站脚本攻击漏洞的一些个人解析&#xff0c;请大家结合参考其他文章中的相关信息进行归纳和补充。 XSS跨站脚本攻击漏洞描述 跨站脚本攻击&#xff08;XSS&#xff09;漏洞是一种常见且危害较…...

html5基于Canvas的经典打砖块游戏开发实践

基于Canvas的经典打砖块游戏开发实践 这里写目录标题 基于Canvas的经典打砖块游戏开发实践项目介绍技术栈核心功能实现1. 游戏初始化2. 游戏对象设计3. 碰撞检测系统4. 动画系统5. 用户界面设计 性能优化1. 渲染优化2. 内存管理 项目亮点技术难点突破项目总结 项目介绍 在这个…...

企业信息化的“双螺旋”——IT治理和数据治理

企业信息化的“双螺旋”——IT治理和数据治理 一、核心定义二、关键差异三、内在联系四、实践挑战与融合路径五、行业案例参考六、结论数据治理(Data Governance)和IT治理(IT Governance)是现代企业数字化转型中的关键概念,二者既有紧密关联又各有侧重。以下从定义、核心内…...

设计模式之工厂模式的优缺点

工厂模式是一种创建对象的设计模式&#xff0c;它将对象的创建和使用分离。以下是工厂模式的优缺点&#xff1a; 优点 - 解耦对象的创建和使用&#xff1a;使得代码的依赖关系更加清晰&#xff0c;使用者不需要了解对象的具体创建过程&#xff0c;只需要关心如何使用对象&a…...

CCBCISCN复盘

AWDP – ccfrum 自己搭了一下环境, 复现一下这道题目, 之前比赛的时候完全没想到这个漏洞要怎么打, 修也不知道要怎么修, 就仅仅是对用户名的账号和密码进行了一下过滤, 完全没起到作用, 唉, 实在太菜 如果想要尝试复现的话可以尝试拉取这个镜像, 我打完之后就直接把这个容器给…...

糊涂人寄信——递推

思路分析&#xff1a;当有n封信&#xff0c;n个信封时。第k封信没有装在第k个信封里&#xff08;k从1~n&#xff09;&#xff0c;就算所有的信封都装错了。我们可以得知的是&#xff0c;当有1封信,时&#xff0c;装错类别数为0。当有两封信时&#xff0c;装错类别为1。 当有三…...

OpenHarmony子系统开发 - 电源管理(一)

OpenHarmony子系统开发 - 电源管理&#xff08;一&#xff09; 一、电源模式定制开发指导 概述 简介 OpenHarmony默认提供了电源模式&#xff08;如正常模式、性能模式、省电模式、超级省电模式&#xff09;的特性。但由于不同产品的部件存在差异&#xff0c;导致在同样场景…...

使用 OpenCV 拼接进行图像处理对比:以形态学操作为例

图像处理在计算机视觉中起着至关重要的作用&#xff0c;而 OpenCV 作为一个强大的图像处理库&#xff0c;提供了丰富的函数来实现各类图像处理任务。形态学操作&#xff08;Morphological Operations&#xff09;是其中常用的技术&#xff0c;尤其适用于二值图像的处理。常见的…...

数据库的左连接,右连接,全外连接,自连接,内连接的区别

从语法层面上看&#xff0c; 全外连接full outer join 左连接是left outer join 右连接是right outer join 内连接是inner join 自连接是自身表与自身表进行的左右连接&#xff0c;需要注意的是并没有左内连接和右内连接。 左外连接 select * from A left outer join B …...

Nexus L2 L3基本配置

接口基本配置 N7K上所有端口默认处于shutdown状态; N5K上所有端口默认处于no shutdown状态(所有端口都是switchport) 默认所有接口都是三层route模式, 只有当线卡不支持三层的时候, 接口才会处于二层switchport模式 show run all | in “system default” 创建SVI口需要提前打…...

OpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)

文章大纲 引言一、在代码逻辑使用LocalStorage二、从UI内部使用LocalStorage三、LocalStorageProp和LocalStorage单向同步四、LocalStorageLink和LocalStorage双向同步五、兄弟组件之间同步状态变量七、将LocalStorage实例从UIAbility共享到一个或多个视图 引言 前面一篇文章主…...

Python数据可视化实战:从基础图表到高级分析

Python数据可视化实战&#xff1a;从基础图表到高级分析 数据可视化是数据分析的重要环节&#xff0c;通过直观的图表可以快速洞察数据规律。本文将通过5个实际案例&#xff0c;手把手教你使用Python的Matplotlib库完成各类数据可视化任务&#xff0c;涵盖条形图、堆积面积图、…...

在 Elasticsearch 中扩展后期交互模型 - 第 2 部分 - 8.18

作者&#xff1a;来自 Elastic Peter Straer 及 Benjamin Trent 本文探讨了如何优化后期交互向量&#xff0c;以适应大规模生产工作负载&#xff0c;例如减少磁盘空间占用和提高计算效率。 在之前关于 ColPali 的博客中&#xff0c;我们探讨了如何使用 Elasticsearch 创建视觉搜…...

蓝桥每日打卡--区间移位

#蓝桥#JAVA#区间移位 题目描述 数轴上有n个闭区间&#xff1a;D1,⋯Dn。 其中区间Di用一对整数[ai,bi]来描述&#xff0c;满足 ai≤bi。 已知这些区间的长度之和至少有。 所以&#xff0c;通过适当的移动这些区间&#xff0c;你总可以使得他们的"并"覆盖 [0,],也…...

CUDAOpenCV 基于Hessian矩阵计算特征值

文章目录 一、简介二、实现代码三、实现效果一、简介 基于之前的博客:CUDA&OpenCV Hessain矩阵计算,我们可以计算出每个像素的特征值: 二、实现代码 ComputeHessainMatrix.cuh #ifndef HESSAIN_GPU_CUH #...

基于CAMEL 的Workforce 实现多智能体协同工作系统

文章目录 一、workforce 简介1.架构设计2.通信机制 二、workforce 工作流程图示例1.用户角色2.工作流程 三、workforce 中重要函数说明1.__init__函数2.add_single_agent_worker 函数3.add_role_playing_worker 函数4.add_workforce 函数 四、基于workforce实现多智能体协调&am…...

深入探讨 `ip2region` 中三种初始化方法:newWithBuffer、newWithVectorIndex 和 newWithFileOnly

在处理IP地址地理位置定位时&#xff0c;ip2region 提供了多种方式来初始化 Searcher 实例&#xff0c;以适应不同的应用场景和资源限制。本文将详细介绍并对比 newWithBuffer、newWithVectorIndex 和 newWithFileOnly 这三种初始化方法&#xff0c;帮助开发者根据自己的需求选…...

PostgreSQL_数据表结构设计并创建

目录 前置&#xff1a; 1 数据表设计思路 2 数据表格SQL 3 创建 3.1 创建数据库 db_stock 3.2 在 pgAdmin4 中创建表 前置&#xff1a; 本博文是一个系列。在本人“数据库专栏”-》“PostgreSQL_”开头的博文 1 数据表设计思路 1 日数据来自优矿&#xff0c;优矿的数据…...

如何在MCU工程中启用HardFault硬错误中断

文章目录 一、HardFault出现场景二、启动HardFault三、C代码示例 一、HardFault出现场景 HardFault&#xff08;硬故障&#xff09; 错误中断是 ARM Cortex-M 系列微控制器中一个较为严重的错误中断&#xff0c;一旦触发&#xff0c;表明系统遇到了无法由其他异常处理机制解决…...