项目背景:前端使用vue3组合式api写法 + 后端传递流式数据
最近在工作中,需要实现一个场景:用户向ai提问之后,ai的回复是一部分一部分的持续输出,而不是等全部内容生成之后再一次性回复。
这个场景的好处:像这种打印机式的输出,用户的体验感会更好。
那我是怎么实现的呢?直接上代码:
配置环境
npm install --save @microsoft/fetch-event-source
//script标签中
// 导入EventSource
import { fetchEventSource } from '@microsoft/fetch-event-source';
// 聊天框内容列表
let chatDatas = ref([])
//将ai回复的内容放到聊天列表中(这里使用的是v-for渲染chatDatas列表,生成元素)
let arr1=reactive({
content: '', //注意初始值要为空字符串
});
chatDatas.value.push(arr1)
// 请求数据,流式输出
await fetchEventSource('完整的路径(http.....)', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
要传递的参数
}),
//接收服务器发送的所有消息
async onmessage(ev) {
//拼接返回的数据
arr1.content += ev.data
},
//会话发送完毕时触发
onclose() {
这里可以写结束时,你需要做的事,如果没有,可以删除
}
})
// template标签中
<div
v-for="i in chatDatas"
:key="i.content"
>
<p>{{ i.content }}</p>
</div>
这里提示一下,如果后端返回的是普通文本,则直接渲染上去就行;如果是使用了markdown语法的文本,想要正常显示还得解析markdown文本,上网搜索解析markdown文本的方法即可,这里我给不出具体的方法,因为我找了好几个方法,都解析不完全.....emmm心累,要是你有可行的方法,期待你的分享。
解析不完全的问题大概如下:换行、加粗这些都能显示,但无序列表解析不了。
我使用的方法如下:
//配置npm i marked
//导入
import {marked} from 'marked';
//使用
<p v-html="marked(i.content)"></p>
如果本文对你有帮助,希望能得到你的点赞或收藏或关注,这是对我最好的鼓励;
如你有问题或疑惑,欢迎在评论区写下,必将努力解答;
如本文有误区,希望你不吝赐教,让我们共勉!