这个问题终于解决了!好开心。
先看最终效果:
video_20240724_141543_edit
项目背景:vue3
场景:像gpt一样可以对话,当用户发送问题之后,ai回复,ai是一部分一部分回复,像打印机式输出。后端返回的是流式数据,且这个数据是如下格式:
data里的content存放的就是ai回复的一部分数据,但这个数据是Unicode格式的字符串,前端(我)需要做的就是实现视频中的效果:打印机式的输出+实时解析markdown文本并正确渲染到页面上。
如果你只是要实现打印机式的输出,直接看我之前的一篇文章就行:
像ChatGPT一样实现打印机式输出_vue 仿gpt打印显示-CSDN博客
如果你要实现:打印机式的输出+实时解析markdown文本并正确渲染到页面上,就请继续往下看。
特别提示:如果你接收到的数据格式和我的不一样,我也不确定能不能帮到你,因为之前我的后端给我返回的数据格式不长这样,之前是直接是data:'数据'的格式,我试过很多方法都不能边接收markdown语法的数据,边正确解析渲染到页面上,当时我没想过可能是后端数据格式的问题,我就一直认为是我这边的问题。所以如果你怎么试都不成功,可以试着让后端改改。
解析Unicode格式的字符串的方法
// 解码包含Unicode转义序列的字符串function decodeUnicode(str) { return str.replace(/\\u[\dA-Fa-f]{4}/g, function(match) { return String.fromCharCode(parseInt(match.substr(2), 16)); });}
配置环境
//为了接收流式数据,需导入npm install --save @microsoft/fetch-event-source//这里我使用的是markdown-it这个库去解析markdown文本。npm install markdown-it --save
下面两块代码,其实就是整个效果的完整代码
//script标签中 // 导入EventSource,这里使用fetchEventSource去接收流式数据import { fetchEventSource } from '@microsoft/fetch-event-source';// 导入解析markdown语法的第三方库markdown-itimport MarkdownIt from 'markdown-it'let md: MarkdownIt = new MarkdownIt()// 聊天框内容列表let chatDatas = ref([])// 解码包含Unicode转义序列的字符串function decodeUnicode(str) { return str.replace(/\\u[\dA-Fa-f]{4}/g, function(match) { return String.fromCharCode(parseInt(match.substr(2), 16)); });}// 发送信息按钮let sendMessage = async () => { let arr1=reactive({ 注意初始值要为空字符串,后面才能拼接 content: '' }); chatDatas.push(arr1) // 请求数据,流式输出 await fetchEventSource(baseURL+'/require/stream_generate_requirements', { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8' }, body: JSON.stringify({ 要传递的参数 }), async onmessage(ev) { // ev.data里面是实时传递过来的数据 // 根据后端返回的数据,我这里需要将字符串转成对象 let obj = JSON.parse(ev.data) // 拿到具体的内容 let content = obj.content // Unicode转成中文 let decodeContent = decodeUnicode(content) // 拼接:这里是数据打印机式输出的关键 arr1.content+=decodeContent }, //会话发送完毕时触发 onclose() { 这里可以写结束时,你需要做的事,如果没有,可以删除 } })}
// template标签中<div v-for="i in chatDatas" :key="i.content" > <p v-html="md.render(i.content)"></p></div>
拓展:代码高亮
如果你收到的数据中包含代码,你想让代码高亮,则你需要添加这些东西:
配置:
npm install highlight.js --save
// script标签中// 引入代码高亮import hljs from 'highlight.js';// 你用到了什么语言就要引入什么语言,目前我还不知道怎么样导入所有语言import javascript from 'highlight.js/lib/languages/javascript';// 这个是高亮的样式,有很多,我选了这个import 'highlight.js/styles/ir-black.css';hljs.registerLanguage('javascript', javascript);let md: MarkdownIt = MarkdownIt({ highlight: function (str: string, lang: string) { const language = hljs.getLanguage(lang); if (language) { try { return `<div> <div> <span>${lang}</span> </div> <div class="hljs"> <code>${hljs.highlight(lang, str, true).value}</code> </div> </div>`; } catch (error) { console.error(error); } } // 如果未指定语言或无法识别语言,则使用默认的逃逸 HTML 处理 return `<div class="hl-code"> <div> <span>${lang}</span> </div> <div class="hljs"> <code>${md.utils.escapeHtml(str)}</code> </div> </div>`;}})
到这里,基本的功能和样式应该都实现了,希望能帮到你。
如果本文对你有帮助,希望能得到你的点赞或收藏或关注,这是对我最好的鼓励;
如你有问题或疑惑,欢迎在评论区写下,必将努力解答;
如本文有误区,希望你不吝赐教,让我们共勉!