vue3+fetch请求+接收到流式的markdown数据+一边gpt打字机式输出内容,一边解析markdown语法+highlight.js实现代码高亮

这个问题终于解决了!好开心。

先看最终效果:

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-it
import 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>`;
}
})

到这里,基本的功能和样式应该都实现了,希望能帮到你。

如果本文对你有帮助,希望能得到你的点赞或收藏或关注,这是对我最好的鼓励;

如你有问题或疑惑,欢迎在评论区写下,必将努力解答;

如本文有误区,希望你不吝赐教,让我们共勉!
 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值