经过两周爆肝迭代研发tauri2.10+vue3.5+openai深度接入deepseek-v3.2搭建客户端流式ai智能小助手。新增深度思考、复制代码、katex公式及mermaid图渲染等功能。
项目支持性
- 支持深度思考链 ✨
- 支持KaTex数学公式 ✨
- 支持Mermaid图表渲染(放大/缩小/下载svg/下载png)✨
- 支持代码块滚动粘性、横向滚动、行号、复制代码、下载代码 ✨
- 支持表格、链接跳转、图片预览 ✨
使用技术
- 编辑器:VScode
- 跨平台框架:Tauri^2.10
- 前端技术框架:vite^7.3.1+vue^3.5.29+vue-router^5.0.3
- 通用大模型:deepseek-v3.2 + openai
- 组件库:arco-design^2.57.0
- 状态管理:pinia^3.0.4
- 本地存储:pinia-plugin-persistedstate^4.7.1
- markdown解析:markdown-it^14.1.0
- katex公式渲染:@mdit/plugin-katex^0.25.0
项目框架结构
使用vite7.3+tauri2.10搭建项目框架,集成deepseek-v3.2智能模型,采用vue3 setup语法糖编码开发页面。
项目入口文件
import { createApp } from "vue"
import App from "./App.vue"
import './style.scss'
// 引入插件配置
import Plugins from './plugins'
// 引入路由/状态管理
import Router from './router'
import Pinia from './pinia'
createApp(App)
.use(Plugins)
.use(Router)
.use(Pinia)
.mount("#app")
环境变量配置.env
如上图:替换下自己申请的deepseek apikey即可体验流式对话功能。
项目通用模板
<script setup>
import { appState } from '@/pinia/modules/app'
import Titlebar from '@/layouts/components/titlebar/index.vue'
import Sidebar from '@/layouts/components/sidebar/index.vue'
const appstate = appState()
</script>
<template>
<div class="vu__chatbot">
<div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">
<div class="vu__layout flexbox flex-col">
<!-- 导航栏 -->
<Titlebar />
<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>
</div>
</template>
自定义集成katex公式+mermaid渲染
import { imgSize } from '@mdit/plugin-img-size' // 支持带尺寸图片
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"
@preview="onPreview"
/>
封装mermaid渲染插件。
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 class="mermaid-container">${renderCache.get(hash)}</div>
`
}
nextTickRender(uuid)
return `
${ defaultFence(...args) }
<div class="mermaid-container" id="${uuid}" data-mermaid-hash="${hash}" data-mermaid-code="${encodeURIComponent(code)}">
<div class="mermaid-loading">📊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')
} catch (error) {
console.error('Mermaid 渲染失败:', error)
showError(container, `<pre>渲染图表时出错: \n ${error.message}\n</pre>`)
}
}
}
自定义ai对话框
<template>
<div class="v3ai__footbar flexbox flex-col">
<!-- 技能栏 -->
<div v-if="skillbar" class="v3ai__skills flexbox flex-alignc">
<div class="item" v-for="(item, index) in skills" :key="index" @click="handleSkill(item)">
<i class="iconfont" :class="item.icon"></i><span class="text">{{item.text}}</span>
</div>
</div>
<!-- 编辑栏 -->
<div class="v3ai__inputbox flexbox flex-col">
<div class="v3ai__editor flexbox">
<a-textarea v-model="editorText" :auto-size="autoSize" placeholder="想问点什么..." spellcheck="false" @input="handleInput" />
</div>
<!-- 操作栏 -->
<div class="v3ai__tools flexbox flex-alignc">
<div class="option flex1 flexbox">
<div class="btn" @click="isDeep =! isDeep"><i class="iconfont ai-deepthink"></i> 深度思考 <span class="fs-12">(R1)</span></div>
<div class="btn" @click="isNetwork =! isNetwork"><i class="iconfont ai-network"></i> 联网</div>
</div>
<a-dropdown trigger="hover" :show-arrow="false" position="lb" :content-style="{'min-width': '250px'}">
<a-button shape="circle"><icon-attachment size="18" /></a-button>
<template #content>
<a-dgroup>
<template #title><div style="margin-bottom: 5px;">从网盘添加</div></template>
<a-doption value="wx"><icon-more /> 选择网盘文件</a-doption>
</a-dgroup>
<a-dgroup>
<template #title><div style="margin-bottom: 5px;">从本地添加</div></template>
<a-doption value="wx"><icon-apps /> 上传文件</a-doption>
<a-dsubmenu trigger="hover" position="rb" :popup-translate="[8, 8]" value="option-1">
<template #default><icon-apps /> 上传代码</template>
<template #content>
<a-doption value="pyq"><icon-apps /> 代码文件</a-doption>
<a-doption value="qq"><icon-apps /> 代码文件夹</a-doption>
<a-doption value="qq"><icon-apps /> GitHub仓库</a-doption>
</template>
</a-dsubmenu>
</a-dgroup>
</template>
</a-dropdown>
<a-dropdown :show-arrow="false" position="top" :popup-translate="[-5, -5]" :content-style="{'min-width': '150px'}">
<a-button shape="circle"><icon-plus size="18" /></a-button>
<template #content>
<a-doption value="image"><icon-file-image /> 图片</a-doption>
<a-doption value="file"><icon-file /> 本地文件</a-doption>
<a-doption value="pdf"><icon-file-pdf /> PDF文档分析</a-doption>
<a-doption value="page"><icon-cloud /> 网页总结</a-doption>
</template>
</a-dropdown>
<a-divider direction="vertical" style="margin: 0 7px;" />
<a-button class="submit" type="primary" shape="circle" @click="handleSubmit">
<icon-send v-if="!sessionstate.loading" size="20" />
<icon-loading v-else size="18" />
</a-button>
</div>
</div>
</div>
</template>
接入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,
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) {
// ...
}
if(chunk.choices[0]?.finish_reason === 'stop') {
// ...
}
}
推荐热文
2026实战uniapp+vue3+mphtml调用deepseek【小程序+安卓+H5】流式输出ai
2026最新款Vue3+DeepSeek-V3.2+Arco+Markdown网页端流式生成AI Chat
2026原创Electron39.2+Vue3+DeepSeek从0-1手搓AI模板桌面应用Exe
2026最新款Vite7+Vue3+DeepSeek-V3.2+Markdown移动端流式输出AI会话
基于electron38+vite7+vue3 setup+elementPlus电脑端仿微信/QQ聊天软件
electron38.2-vue3os系统|Vite7+Electron38+Pinia3+ArcoDesign桌面版OS后台管理
2025最新款Electron38+Vite7+Vue3+ElementPlus电脑端后台系统Exe
基于uni-app+vue3+uvui跨三端仿微信app聊天模板【h5+小程序+app】
基于uniapp+vue3+uvue短视频+聊天+直播app系统
自研2025版flutter3.38实战抖音app短视频+聊天+直播商城系统
基于flutter3.32+window_manager仿macOS/Wins风格桌面os系统
flutter3.27+bitsdojo_window电脑端仿微信Exe应用
自研tauri2.0+vite6.x+vue3+rust+arco-design桌面版os管理系统Tauri2-ViteOS