Skip to content

AI聊天平台 - 项目分析 ​

在线预览 ​

https://ai-chat.fjxylin.cn/

项目概述 ​

基于 Vue 3 构建的 AI 聊天平台,支持多平台 LLM 接入(DeepSeek / 阿里百炼 / 字节火山引擎)、SSE 流式输出、多模态输入(文本+图片)、语音识别、MCP 服务管理,提供完整的对话管理、主题切换等能力。

技术栈 ​

类别技术用途
框架Vue 3 (Composition API + <script setup>)响应式 UI
状态管理Pinia 3全局状态(聊天/设置/用户)
路由Vue Router 4页面路由 + 导航守卫
UI 组件Element Plus 2对话框、输入框、图标等
构建Vite 7开发服务器与生产构建
HTTP原生 fetch (SSE)流式 AI 对话请求
Markdownmarked + highlight.js消息内容渲染
语音Web Speech API语音输入识别
测试PlaywrightE2E 测试
工具@vueuse/coreComposition API 工具函数

目录结构 ​

src/
├── api/
│   ├── chat.js            # 聊天 API(SSE 流式请求、图片转 Base64、连接测试)
│   └── models.js          # 模型列表获取
├── components/
│   ├── ChatInput.vue      # 多模态输入区(文本/图片/语音)
│   ├── ChatMessage.vue    # 消息气泡(Markdown 渲染 + 代码高亮)
│   ├── SettingsDialog.vue # 设置弹窗(平台/MCP 配置)
│   └── ThinkingProcess.vue# AI 推理链折叠面板
├── composables/
│   └── useSpeechRecognition.js  # Web Speech API 封装
├── router/
│   └── index.js           # 路由配置 + 鉴权守卫
├── stores/
│   ├── chat.js            # 聊天 Store(对话/消息管理)
│   ├── settings.js        # 设置 Store(API/MCP/主题)
│   └── user.js            # 用户 Store(模拟登录)
├── views/
│   ├── ChatView.vue       # 主聊天视图(侧边栏 + 消息列表 + 输入区)
│   └── LoginView.vue      # 登录页面
├── App.vue                # 根组件
├── main.js                # 应用入口
└── style.css              # 全局样式 + 主题变量

架构与数据流 ​

整体架构 ​

正在加载图表...

消息发送数据流 ​

正在加载图表...

路由与鉴权流程 ​

正在加载图表...

核心模块详解 ​

1. 路由与鉴权 (src/router/index.js) ​

  • 两个路由:/login(LoginView)和 /(ChatView)
  • /:pathMatch(.*)* 兜底重定向至 /
  • requiresAuth 元信息控制访问权限
  • 全局前置守卫:未登录访问 / 时重定向至 /login,已登录访问 /login 时重定向至 /
  • 组件懒加载(() => import(...))

2. Pinia Store ​

userStore(src/stores/user.js) ​

  • 状态:token、username(从 localStorage 初始化)
  • isLoggedIn 计算属性(!!token.value)
  • login() / logout() 同步 localStorage
  • 纯前端模拟,无真实后端

chatStore(src/stores/chat.js) ​

  • 管理 conversations 数组、currentConversationId、当前 messages
  • 全部持久化至 localStorage
  • 核心操作:createConversation / switchConversation / deleteConversation / addMessage / updateLastMessage
javascript
// 关键操作:更新流式消息
updateLastMessage(content, thinking) {
    const messages = this.messages
    const lastMsg = messages[messages.length - 1]
    if (lastMsg?.role === 'assistant') {
        lastMsg.content = content || lastMsg.content
        if (thinking) lastMsg.thinking = thinking
    }
}

settingsStore(src/stores/settings.js) ​

  • 三个 LLM 提供商预设(DeepSeek / 阿里百炼 / 字节火山引擎)
  • 每个提供商配置:apiKey、apiUrl、model
  • 通用设置:theme(light/dark)、enableWebSearch、mcpServers 数组
  • MCP 服务管理:addMcpServer / updateMcpServer / removeMcpServer
  • 主题切换通过操作 document.documentElement.classList 的 'dark' 类
  • watch(settings, saveSettings, { deep: true }) 自动持久化

3. 视图层 ​

ChatView.vue(主聊天视图) ​

  • 固定侧边栏(可折叠)+ 主区域布局
  • 侧边栏:会话列表(标题 + 删除按钮),底部用户信息入口
  • 主区域:顶栏(汉堡菜单、标题、主题切换、设置、退出按钮)
  • 消息容器:空状态提示,实时滚动到底部
  • handleSend 流程:构建消息 → 写入 store → 发起 streamChat

LoginView.vue(登录页面) ​

  • 居中卡片布局,径向渐变背景
  • 表单:用户名 + 密码输入
  • 模拟登录(800ms 延迟,生成 mock-token-{timestamp})

4. 组件 ​

ChatInput.vue(输入区) ​

  • textarea 输入(Enter 发送 / Shift+Enter 换行)
  • 图片上传(<input type="file" accept="image/*">),预览缩略图
  • Web Speech API 语音输入(脉冲动画录音指示)
  • 联网搜索开关按钮
  • emit('send', { text, image }) 向父组件发送

ChatMessage.vue(消息气泡) ​

  • 用户消息右对齐,AI 消息左对齐(flex-direction: row-reverse)
  • Markdown 渲染:marked 解析 + highlight.js 代码高亮(js/python/markdown)
  • 多模态消息支持:content 为数组时逐项渲染(图片 + 文本)
  • AI 消息可选展示 ThinkingProcess 推理链面板
javascript
// 核心渲染逻辑
const renderedContent = computed(() => {
    if (Array.isArray(props.message.content)) {
        return props.message.content
            .map(item => item.type === 'image_url'
                ? `<img src="${item.image_url.url}" />`
                : marked(item.text))
            .join('')
    }
    return marked(props.message.content || '')
})

ThinkingProcess.vue(推理链) ​

  • 可折叠面板展示 AI 推理过程
  • 加载旋转动画 + 展开/折叠切换
  • 使用 el-collapse-transition 实现动画

SettingsDialog.vue(设置弹窗) ​

  • 双 Tab:platform + mcp
  • 平台 Tab:三个平台卡片(API Key / URL / 模型选择下拉框 + 搜索创建)
  • 模型列表从 API 获取(/v1/models 端点)
  • MCP Tab:SSE 服务器的增删改查,每项有开关/测试连接/编辑/删除
  • 打开时自动获取模型列表

5. API 层 ​

streamChat(src/api/chat.js) ​

核心流式对话函数:

javascript
export async function streamChat(messages, onChunk, onThinking) {
    const settingsStore = useSettingsStore()
    const { apiUrl, apiKey, model, platform } = settingsStore.currentSettings
    const url = resolveChatCompletionsUrl(apiUrl)
    const body = {
        model, stream: true,
        messages: normalizeMessagesForPlatform(messages, platform)
    }
    if (settingsStore.settings.enableWebSearch && platform === 'aliyun') {
        body.enable_search = true
    }

    const response = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
        body: JSON.stringify(body)
    })

    const reader = response.body.getReader()
    const decoder = new TextDecoder()
    // 读取 SSE 流,解析 data: {...} 格式
    // delta.reasoning_content → onThinking
    // delta.content → onChunk
}

关键工具函数:

  • resolveChatCompletionsUrl(url) — 确保以 /chat/completions 结尾
  • imageToBase64(file) — File 转 Base64 data URL
  • buildMessageWithImage(text, imageFile) — 构建多模态消息数组
  • testConnection(platform, apiKey, apiUrl, model) — 测试 API 连接

fetchModels(src/api/models.js) ​

  • 调用 /v1/models 获取模型列表(兼容 OpenAI 格式)
  • 返回 [{ value, label }, ...] 并按 ID 排序
  • 火山引擎平台异常时返回空数组(前端展示预设模型)

6. Composables ​

useSpeechRecognition(src/composables/useSpeechRecognition.js) ​

  • 封装 SpeechRecognition / webkitSpeechRecognition
  • 配置:continuous: true、interimResults: true、lang: 'zh-CN'
  • 返回:isListening / isSupported / error / start(onResult, onError) / stop()
  • start():自动重启(除非手动停止),遍历识别结果合并完整文本
  • onUnmounted 时 recognition.abort() 清理

关键特性 ​

多平台 LLM 支持 ​

平台默认 API URL默认模型
DeepSeekhttps://api.deepseek.com/v1/chat/completionsdeepseek-chat
阿里百炼https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completionsqwen-turbo
字节火山引擎https://ark.cn-beijing.volces.com/api/v3doubao-seed-2-0-pro-260215

平台差异适配:

  • 火山引擎图片格式需添加 detail: 'auto' 字段
  • 阿里云支持 enable_search: true 联网搜索
  • DeepSeek 支持 reasoning_content 思维链

数据持久化策略 ​

localStorage 键存储内容
token登录令牌
username用户名
conversations会话及消息列表
ai_settingsAPI 配置 / 主题 / MCP 服务

主题系统 ​

通过 CSS 自定义属性实现主题切换:

  • :root — 浅色主题变量
  • html.dark — 深色主题变量
  • 核心变量:--bg-color、--text-color、--border-color、--hover-bg 等

测试 ​

基于 Playwright 的 E2E 测试(tests/e2e.spec.js):

  1. 标题验证:导航至 /,验证登录页面标题
  2. 完整流程:登录 → 打开设置 → 测试连接(mock API)→ 发送消息 → 验证消息气泡

配置:Chrome 桌面端,baseURL http://localhost:5173

Last updated: