首页 前端知识 vue实现大语言模型返回的数据将代码高亮显示的实现

vue实现大语言模型返回的数据将代码高亮显示的实现

2025-03-20 12:03:39 前端知识 前端哥 485 659 我要收藏

0. 引言

最近在学习ai大模型相关的东西,就想着自己做一个类似于chatGPT的网站,做到最后的时候代码块始终是不能高亮显示,以前一直搞Java没太了解过前端vue相关的东西,经过自己查资料,自己慢慢也是研究出来了。
这个项目整体前端是vue3,后端是python,ollama,chatOpenAi,langchain,第三方的大模型API。
ollama部署模型在本地,chatOpenAi调用模型,langchain用来做提示词和聊天记录保存支持上下文对话。
题外:项目已经部署了,想体验的可以私信我。

 1.导入配置

  其他无关的依赖省略 

"dependencies": {
        "@traptitech/markdown-it-katex": "^3.6.0",
        "github-markdown-css": "^5.5.1",
        "highlight.js": "^9.18.5",
        "markdown-it": "^14.1.0"

      },
      "devDependencies": {
        "@types/markdown-it": "^14.1.1",
      }

 2.依赖的下载命令

npm i markdown-it
 
npm i @traptitech/markdown-it-katex
 
npm i -D @types/markdown-it
 
npm i highlight.js

3.项目中引入 

import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';

在引入import hljs from 'highlight.js';可能会报一个提示,在项目srm中新建一个.d.ts结尾的文件,写入以下内容
 

declare module '*.vue'{

    import Vue from 'vue'

    export default Vue

}


 

declare module 'highlight.js'

4.我的vue

4.1页面显示 

<div>
    <div
        v-html="changeItem(item)"
        class="message"
        style="margin: 1rem"
     ></div>
</div>

4.2定义一个数据来接受用户输入和大模型响应的数据,用户输入的时候就往数组里push就可以了。

const contentdata = reactive([]);

4.3发请求获取数据
用的是SSE(Server-Sent Events)来实时获取响应流中的数据。

fetch(url, {
        method: "POST",
        signal: controller.signal,
        body: formData,
    })
        .then((response) => {
            loadFlg.value = false;
            if (response.status === 200) {
                const reader = response.body.getReader();
                let accumulatedText = ""; // 用于累积未完成的数据

                function read() {
                    reader
                        .read()
                        .then(({ done, value }) => {
                            if (done) {
                                icType.value = Top;
                                return;
                            }
                            // 解码接收到的数据
                            const text = new TextDecoder().decode(value);
                            accumulatedText += text;
                            // 按换行符分割数据块
                            let lines = accumulatedText.split("\n");
                            // 保留未完成的一行
                            accumulatedText = lines.pop();
                            lines.forEach((line) => {
                                if (line.trim()) {
                                    // 确保非空行
                                    if (line === "[END]") {
                                        icType.value = Top;
                                        return;
                                    }
                                    // 移除前缀 'data: '
                                    if (line.startsWith("data: ")) {
                                        line = line.substring(6);
                                    }
                                    try {
                                        const data = JSON.parse(line);
                                        const content = data.content;
                                        // 直接使用 content,因为 content 已经是一个字符串
                                        contentdata[
                                            contentdata.length - 1
                                        ].ai += content;
                                        div.scrollTop = div.scrollHeight;
                                    } catch (error) {
                                        console.error(
                                            "JSON parse error:",
                                            error
                                        );
                                    }
                                }
                            });
                            // 继续读取下一个数据块
                            read();
                        })
                        .catch((error) => {
                            icType.value = Top;
                            console.error("Read error:", error);
                        });
                }
                // 开始读取数据
                read();
            } else {
                contentdata[contentdata.length - 1].ai =
                    "非法请求,请刷新页面或关闭页面再次打开。";
                icType.value = Top;
                alIsShow.value = true;
            }
        })
        .catch((error) => {
            icType.value = Top;
            console.error("Fetch error:", error);
        });

主要的代码其实就是下面这个,将获取到的数据解析出来显示在页面上。

contentdata[contentdata.length - 1].ai += content;

5.使用MarkdownIt 

const mdi = new MarkdownIt({
  linkify: true,
  highlight(code, language) {
    const validLang = !!(language && hljs.getLanguage(language))
    if (validLang) {
      const lang = language ?? ''
      return highlightBlock(hljs.highlight(lang, code, true).value, lang)
    }
    return highlightBlock(hljs.highlightAuto(code).value, '')
  }
})
mdi.use(mdKatex, { blockClass: 'katexmath-block rounded-md p-[10px]', errorColor: ' #cc0000' })
 
function highlightBlock(str, lang) {
    lang = lang || "text";
  return `<pre class="pre-code-box">
            <div class="pre-code-header" 
            style = "
                background-color: #50505a;
                padding: 0.2rem;
                padding-left: 1rem;
                color: white;
                font-size: 1rem;
                border-top-left-radius: 10px;
                border-top-right-radius: 10px;
            "><span class="code-block-header__lang">${lang}</span></div><div class="pre-code"><code class="hljs code-block-body ${lang}" style="padding:1.5rem; font-size: 1.05rem;border-bottom-left-radius: 10px;border-bottom-right-radius: 10px;" >${str}</code></div></pre>`
}


// 把数组最后一项的ai属性的值转换成html
const changeItem = (item) => {
    return mdi.render(item.ai)
};

 6.效果

转载请注明出处或者链接地址:https://www.qianduange.cn//article/24199.html
评论
发布的文章

动态规划感悟1

2025-03-20 12:03:52

华为NAS真实测评!

2025-03-20 12:03:52

Java设计模式之代理模式

2025-03-20 12:03:51

Linux 锁、线程同步

2025-03-20 12:03:48

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!