基于 Vite7.2 集成 DeepSeek-V3.2 聊天大模型搭建本地网页版 AI 对话。
deepseek-vue3-webai:运用
vite7.2+vue3.5+arco-design集成deepseek-v3.2打造网页版 AI 系统。提供浅色/暗黑两种主题、深度思考 R1、代码高亮/复制、Latex 数学公式、Mermaid 图表渲染。
技术栈
- 编辑器:VScode
- 前端框架:vite7.2.4+vue3.5.24+vue-router^4.6.4
- 大模型框架:DeepSeek-R1 + OpenAI
- 组件库:arco-design^2.57.0 (字节桌面端组件库)
- 状态管理:pinia^3.0.4
- 本地存储:pinia-plugin-persistedstate^4.7.1
- 高亮插件:highlight.js^11.11.1
- markdown 插件:markdown-it
- katex 公式:@mdit/plugin-katex^0.24.1
项目特色
- 最新版 Vite7.2 接入 DeepSeek 流式输出,性能更丝滑流畅
- 提供暗黑 + 浅色两种主题、侧边栏收缩
- 支持丰富 Markdown 样式,代码高亮/复制/收缩功能
- 新增思考模式 DeepSeek-R1
- 支持 Katex 数学公式
- 支持 Mermaid 各种甘特图/流程图/类图等图表
- 使用 arco-design 组件库,风格统一,美观大气
项目结构框架
使用最新 vite7.2 构建项目,集成 deepseek-v3.2 chat 大模型。
项目 DeepSeek Key 配置

如上图:替换下项目根目录下.env 文件里的 deepseek apikey 即可体验 ai 流式对话。
# title
VITE_APP_TITLE='Vue3-Web-DeepSeek'
# port
VITE_PORT=3001
# 运行时自动打开浏览器
VITE_OPEN=true
# 开启 https
VITE_HTTPS=false
# 是否删除生产环境 console
VITE_DROP_CONSOLE=true
# DeepSeek API 配置
VITE_DEEPSEEK_API_KEY= 替换为你的 API Key
VITE_DEEPSEEK_BASE_URL= https://api.deepseek.com
项目布局模板

项目布局结构如下图所示:

<script setup>
import Sidebar from '@/layouts/components/sidebar/index.vue'
</script>
<template>
<div class="vu__container">
<div class="vu__layout flexbox flex-col">
<div class="vu__layout-body flex1 flexbox">
<!-- 侧边区域 -->
<Sidebar />
<!-- 主面板区域 -->
<div class="vu__layout-main flex1">
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" :key="route.path"/>
</keep-alive>
</router-view>
</div>
</div>
</div>
</div>
</template>
Vue3 实现 DeepSeek 深度思考模式


// 调用 deepseek 接口
const completion = await openai.chat.completions.create({
// 单一会话
/* messages: [ {role: 'user', content: editorValue} ], */
// 多轮会话
messages: props.multiConversation ? historySession.value : [{role:'user', content: editorValue}],
// deepseek-chat 对话模型 deepseek-reasoner 推理模型
model: sessionstate.thinkingEnabled ?'deepseek-reasoner':'deepseek-chat',
stream:true,// 流式输出
max_tokens:8192,// 一次请求中模型生成 completion 的最大 token 数 (默认使用 4096)
temperature:0.4,// 严谨采样
})
Vue3-DeepSeek 集成 Katex 和 Mermaid 插件
import{ katex }from"@mdit/plugin-katex";// 支持数学公式
import'katex/dist/katex.min.css'
// 渲染 mermaid 图表
import{ markdownItMermaidPlugin }from'@/components/markdown/plugins/mermaidPlugin'
渲染流式输出 Markdown。
<Markdown :source="item.content" :html="true" :linkify="true" :typographer="true" :plugins="[[katex,{delimiters:'all'}],[markdownItMermaidPlugin,{...}]]" @copy="onCopy"/>
export const markdownItMermaidPlugin = (md, options) => {
const defaultFence = md.renderer.rules.fence
md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args
const token = tokens[idx]
const lang = token.info.replace(/\[.*\]/,'').trim()||''
if(lang ==='mermaid'){
const code = token.content.trim()
const hash = generateHash(code)
const uuid = `${hash}-${Date.now()}-${Math.random().toString(36).substring(2,9)}`
// 如果有缓存,加载缓存图表
if(renderCache.has(hash)){
// console.log('加载缓存 mermaid 图表')
return`${defaultFence(...args)} <div>${renderCache.get(hash)}</div> `
}
nextTickRender(uuid)
return`${defaultFence(...args)} <div> <div>📊Mermaid 图表加载中...</div> </div> `
}
return defaultFence(...args)
}
function nextTickRender(containerId){
// 如果容器存在,直接渲染
if(document.getElementById(containerId)){
renderMermaidDiagram(containerId)
return
}
// 使用 MutationObserver 监听 DOM 更新
const observer = new MutationObserver((mutations, ob)=>{
const container = document.getElementById(containerId)
if(container){
ob.disconnect()
renderMermaidDiagram(containerId)
}
})
observer.observe(document.body,{ childList:true, subtree:true})
}
async function renderMermaidDiagram(containerId){
const container = document.getElementById(containerId)
if(!container){
console.warn(`Mermaid container #${containerId} not found`)
return
}
const code = decodeURIComponent(container.dataset.mermaidCode)
const hash = container.dataset.mermaidHash
if(!code){
return
}
// 检查 mermaid 是否可用
if(typeof window.mermaid ==='undefined'){
showError(container,'Mermaid 库未加载!')
return
}
try{
// 配置 mermaid(如果还未配置)
if(!window.mermaid.initialized){
window.mermaid.initialize({ startOnLoad:false, theme:'default', securityLevel:'loose',})
window.mermaid.initialized =true
}
let svg
// 检查缓存
if(renderCache.has(hash)){
svg = renderCache.get(hash)
}else{
const{ isValid }=await verifyMermaid(code)
if(!isValid){
showError(container,`<pre>渲染语法错误:\n${ code }\n</pre>`)
return
}
// 使用唯一 ID 渲染 (避免图表冲突)
const{svg: renderedSvg}=await window.mermaid.render(`mermaid-${containerId}`, code)
svg = renderedSvg
renderCache.set(hash, svg)
}
container.innerHTML = svg
container.removeAttribute('data-mermaid-hash')
container.removeAttribute('data-mermaid-code')
// 触发回调
if(options?.reachBottom){
options?.onRender?.()
}
}catch(error){
console.error('Mermaid 渲染失败:', error)
showError(container,`<pre>渲染图表时出错:\n ${error.message}\n</pre>`)
}
}
}
Vue3 调用 DeepSeek API
// 调用 deepseek 接口
const completion = await openai.chat.completions.create({
// 单一会话
// messages: [{role: 'user', content: editorValue}],
// 多轮会话
messages: props.multiConversation ? historySession.value : [{role:'user', content: editorValue}],
// deepseek-chat 对话模型 deepseek-reasoner 推理模型
model: sessionstate.thinkingEnabled ?'deepseek-reasoner':'deepseek-chat',
stream:true,// 流式输出
max_tokens:8192,
temperature:0.4
})
处理流式生成内容。
for await(const chunk of completion){
// 检查是否已终止
if(sessionstate.aborted) break
const content = chunk.choices[0]?.delta?.content ||''
// 获取推理内容
const reasoningContent = chunk.choices[0]?.delta?.reasoning_content ||''
if(content || reasoningContent){
answerText += content
reasoningText += reasoningContent
// 限制更新频率:每 100ms 最多更新一次
const now = Date.now()
if(now - lastUpdate >100){
lastUpdate = now
requestAnimationFrame(()=>{
// ...
})
}
}
if(chunk.choices[0]?.finish_reason ==='stop'){// ...}
}


