
全网最全vue2技术栈实现流式AI问答机器人功能(2025/2/18已更新接入deepSeek)
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue

·
更新日志:(我最开始是使用非流式接口实现的,后续业务改造使用流式接口,重点的代码讲解都在下边哈~~)
关于打印机效果后端同样可以实现的逻辑说明:(2024/4/11)
打印机效果使用前端的框架实现时,其实颇有局限,而且逻辑有点复杂,可以百度的也不是很多,最好是交给后端通同学来做,方案是后端控制接口请求的请求头content-type为text/event-stream;这是SSE热更新方案,相当于建立了一个长连接,前端再对该event事件流返回的数据进行判断和监听处理;简单理解就是可以实现后端一直给前端同学返回数据,我们再进行拼接即可,这样可以直接实现打印机效果啦,
2. 补丁上述使用流式接口实现打印机效果讲解:(2024/5/10)
3. 补充实退出时对会话进行保存(下次进入可以看到之前的对话):(2024/6/7)
4.
1)更新更为规范且简便的流式数据获取方法;
2)大模型接入deepseek,处理渲染流式数据返回的think标签
3)更新会话dom滚动方法
4)删除非流式打印机实现步骤,仅保留插件地址参考
5)上述内容于2025/2/18更新
1.与AI问答机器人对话模型效果展示
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
2-流式重点代码解析(流式解析,deepSeek的think标签处理,实时dom滚动与取消)

//发送用户提问的内容时
async sendMsg() {
//可以根据自己业务情况做一些请求前的的中止提示,比如非空等
//data中的数据不再赘述
this.chunkRef = null //重置临时数据
//重置处理deepSeek返回think标签的变量
this.haveThinkStart = false
this.haveThinkEnd = false
this.controller = new AbortController() // 创建AbortController实例,以便中止请求
//使用fetch 实现流式请求
const response = await fetch('url地址', {
method: 'POST',
body: JSON.stringify('请求体对象数据'),
timeout: 0,
dataType: 'text/event-stream',
headers: {
'Content-Type': 'application/json',
},
signal: this.controller.signal,
})
if (response.ok) {
const reader = response.body.getReader()
const decoder = new TextDecoder() //解码器
while (1) {
const { done, value } = await reader.read()
if (done) {
//this.controller?.abort() //这个可以在停止生成功能中使用,意为中断请求,这里不要加,若你有停止生成功能,可在停止生成回调中如此操作。
//do something
//对于有think开始标签而无结束的我们要做处理
if (!this.haveThinkEnd && this.haveThinkStart) {
let length = this.chatList.length - 1
let newContent = this.chatList[length].think
this.chatList[length].think = ''
this.chatList[length].content = newContent
}
break
}
//解码器解析后的单条数据
const text = decoder.decode(value, { stream: true })
//防止后端返回数据不全,创建临时数据进行比对。非常重要!
const chunk = this.handleChunkData(text)
if (!this.chunkRef) {
for (const item of chunk.split('\n')) {
// 移除前缀 'data: ' 或 'data: [DONE]',这里正则有点问题,只能去除data:
let _item = item.replace(/^(data: [DONE])|^(data:)/, '')
try {
if (_item && _item != '[DONE]') {
let index = this.chatList.length - 1
content = JSON.parse(_item)?.choices[0]?.delta.content
//处理deepSeek的think标签数据,markDown-it解析有问题,手动变量保存
if (content == '<think>') {
this.haveThinkStart = true
} else if (content == '</think>') {
this.haveThinkEnd = true
}
if (this.haveThinkEnd) {
this.haveThinkStart = false
}
if (this.haveThinkStart) {
this.chatList[index].think += content
} else {
this.chatList[index].content += content
}
}
} catch (error) {
// 处理 JSON 解析错误
console.error('解析数据时出错:', error)
}
}
}
}
}
},
//暂存处理不完整的json数据
handleChunkData(chunk) {
chunk = chunk.trim()
if (this.chunkRef) {
chunk = this.chunkRef + chunk
this.chunkRef = null
}
if (chunk.includes('[DONE]')) {
return chunk
}
if (chunk[chunk.length - 1] !== '}') {
this.chunkRef = chunk
}
return chunk
},
/**----分割线,下面是保存历史会话方法,用户下次进入可以实现查看历史对话----**/
mounted(){
//监听浏览器刷新事件 &&注意!亲测不包含浏览器回退
window.addEventListener('beforeunload', this.onBeforeUnload)
},
beforeDestroy() {
// 移除事件监听器
window.removeEventListener('beforeunload', this.onBeforeUnload)
},
methods:{
onBeforeUnload(){
//此方法中调用后端给的保存会话接口即可
},
async beforeRouteLeave(to, from, next) {
//await同步调用接口保存会话
next()
}
/**----分割线,如何Dom实现实时跟随会话滚动,但在上滑后停止滚动----**/
//不再使用定时器实现,使用感官很差
//给dom绑定滚动事件,设置阙值,设置滚动开关(控制这个开关就行了,很重要),然后大模型再流式输出和输出完毕后都调用滚动到底部方法
chatBoxScroll(e) {
const scrollTop = e.target.scrollTop //滚动条距离滚动内容顶部的垂直距离
const scrollHeight = e.target.scrollHeight //元素内容的总高度,包括那些在视口中不可见的部分
const clientHeight = e.target.clientHeight //元素节点的可见高度,包括内边距(padding),但不包括水平滚动条、边框和外边距(margin)的高度。
const threshold = 10 // 阈值,可以根据需要调整,以避免在非常接近底部时触发加载
if (!scrollTop || !scrollHeight || !clientHeight) return
//触底
if (scrollTop + clientHeight >= scrollHeight - threshold) {
// alert('我执行设置了true')
this.setScrollStatus(true)
} else {
this.$nextTick(() => {
//alert('我执行设置了false')
this.setScrollStatus(false)
})
}
},
//设置dom滚动开关
setScrollStatus(value) {
this.isScroll = value
},
//dom渲染更新完成后页面滚动到底,大模型输出时和结束输出调用
scrollTop() {
let domScrollHeight = this.$refs.list.scrollHeight
if (domScrollHeight && this.isScroll) {
this.$nextTick(() => {
this.$refs.list.scrollTop = domScrollHeight
})
}
},
3-涉及文档:
markdown-it | markdown-it 中文文档 // 流式markdown数据解析插件
Typed.js - Type your heart out //非流式想实现打印机效果的同学用这个插件
最后补充一下:
对于非流式的i机器人的回答,是由接口提供的模板数据,那么就涉及到dom渲染;如果要使用打印机效果,就不可以使用v-html!原因是v-htm会将模板中的“<,/>”打印出来!所以我们就要换一种方式实现了~ Typed.js插件,给每一个dom绑定唯一id,具体参考typed.js文档。这里不再赘述,非流式用的人少~
推荐内容
阅读全文
AI总结




vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:8 个月前 )
9e887079
[skip ci] 6 个月前
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 10 个月前
更多推荐
相关推荐
查看更多
vue

Vue.js 是一款构建用户界面的 JavaScript 框架,以其简洁的语法和丰富的组件库著称,适用于开发单页面及多页面应用程序。
vue

Javascript Powered forms and JSON form builder for Vue.js
RuoYi-Vue3

yangzongzhuan/RuoYi-Vue3: RuoYi是一款基于Java Spring Boot和Vue3技术栈开发的企业级后台管理系统,提供了一整套快速开发解决方案,包括用户权限管理、数据字典、任务调度等多个基础模块。
热门开源项目
活动日历
查看更多
直播时间 2025-04-25 15:00:00


直播时间 2025-04-23 19:00:00

GitTalk:国内首个微服务编排框架Juggle实战解析
直播时间 2025-04-22 18:31:56

字节AI 黑科技!从 Manus Agent 入门 Eino
直播时间 2025-04-09 14:34:18

樱花限定季|G-Star校园行&华中师范大学专场
直播时间 2025-04-07 14:51:20

樱花限定季|G-Star校园行&华中农业大学专场
目录
所有评论(0)