Files
map-client-vue/CHAT_IMPLEMENTATION.md
2025-10-14 21:52:11 +08:00

13 KiB
Raw Blame History

聊天对话模块实现文档

📅 实现日期

2025年10月14日

🎯 项目概述

基于 Cherry Studio 的架构,完整重构了 MCP 客户端的聊天对话模块,实现了话题管理、消息流式响应、上下文管理等核心功能。


📋 实现内容

1 类型系统 (types/chat.ts)

核心类型定义

// 消息
interface Message {
  id: string
  role: 'user' | 'assistant' | 'system'
  content: string
  status: 'pending' | 'sending' | 'success' | 'error'
  timestamp: Date
  model?: string
  error?: string
  tokens?: { prompt: number; completion: number; total: number }
}

// 话题
interface Topic {
  id: string
  name: string
  description?: string
  createdAt: Date
  updatedAt: Date
  messageCount: number
  lastMessage?: string
  pinned?: boolean       // 置顶
  archived?: boolean     // 归档
  favorite?: boolean     // 收藏
  model?: string
}

// 对话
interface Conversation {
  id: string
  topicId: string
  messages: Message[]
  createdAt: Date
  updatedAt: Date
  metadata?: {
    model?: string
    temperature?: number
    maxTokens?: number
    systemPrompt?: string
  }
}

2 聊天服务 (services/chatService.ts)

核心功能

话题管理
  • 创建话题: createTopic(name, options)
  • 获取话题列表: getTopics(filter)
    • 支持搜索、置顶、归档、收藏过滤
    • 自动排序(置顶优先,然后按更新时间)
  • 更新话题: updateTopic(topicId, updates)
  • 删除话题: deleteTopic(topicId)
  • 切换置顶: toggleTopicPin(topicId)
  • 切换收藏: toggleTopicFavorite(topicId)
  • 归档话题: archiveTopic(topicId)
消息管理
  • 发送消息: sendMessage(options)
    • 自动调用已连接的模型服务
    • 支持上下文管理
    • 错误处理和重试机制
  • 流式发送: sendMessageStream(options, onChunk)
    • 模拟流式输出效果
    • 实时更新 UI
  • 删除消息: deleteMessage(topicId, messageId)
  • 重新生成: regenerateMessage(topicId, messageId)
    • 删除指定消息后的所有消息
    • 使用最后一条用户消息重新请求
持久化
  • LocalStorage 存储
    • chat-topics: 话题列表
    • chat-conversations: 对话历史
  • 自动加载和保存
  • Date 对象恢复

技术亮点

  1. 智能模型调用

    private async callModel(conversation, model?) {
      // 获取已连接的服务
      const services = modelServiceManager.getAllServices()
        .filter(s => s.status === 'connected')
    
      // 准备消息历史
      const messages = conversation.messages
        .filter(m => m.status === 'success')
        .map(m => ({ role: m.role, content: m.content }))
    
      // 调用 API
      const result = await modelServiceManager.sendChatRequest(...)
    
      // 解析响应(支持多种格式)
      return { content: this.parseModelResponse(result.data) }
    }
    
  2. 多格式响应解析

    • 支持 OpenAI 格式
    • 支持 Claude 格式
    • 支持 Gemini 格式
    • 支持自定义格式
  3. 流式输出模拟

    // 模拟打字机效果
    const chunkSize = 5
    for (let i = 0; i < content.length; i += chunkSize) {
      const chunk = content.slice(i, i + chunkSize)
      onChunk(chunk)
      await new Promise(resolve => setTimeout(resolve, 30))
    }
    

3 状态管理 (stores/chatStore.ts)

响应式状态

interface ChatState {
  topics: Topic[]              // 所有话题
  currentTopicId: string | null // 当前选中的话题
  messages: Message[]          // 当前话题的消息
  filter: TopicFilter          // 话题过滤器
  isLoading: boolean          // 加载状态
  isSending: boolean          // 发送状态
}

Computed 属性

  • currentTopic: 当前话题对象
  • filteredTopics: 过滤后的话题列表
  • pinnedTopics: 置顶话题列表
  • recentTopics: 最近话题列表最多10个

Actions

// 话题操作
createTopic(name)                    // 创建并切换到新话题
setCurrentTopic(topicId)            // 切换话题
updateTopic(topicId, updates)       // 更新话题
deleteTopic(topicId)                // 删除话题
toggleTopicPin(topicId)             // 切换置顶
toggleTopicFavorite(topicId)        // 切换收藏
archiveTopic(topicId)               // 归档话题

// 消息操作
sendMessage(content, model?)         // 发送消息
sendMessageStream(content, model?, onChunk?)  // 流式发送
deleteMessage(messageId)            // 删除消息
regenerateMessage(messageId)        // 重新生成

// 其他
setFilter(filter)                   // 设置过滤器
initialize()                        // 初始化

4 UI 组件 (components/Chat/ChatLayout.vue)

整体布局

┌────────────────────────────────────────────────┐
│  ┌──────────┐  ┌──────────────────────────┐   │
│  │          │  │  对话头部                 │   │
│  │  话题    │  ├──────────────────────────┤   │
│  │  列表    │  │                          │   │
│  │          │  │  消息列表                 │   │
│  │  [搜索]  │  │                          │   │
│  │          │  │  - 用户消息               │   │
│  │  话题1   │  │  - AI 回复               │   │
│  │  话题2   │  │  ...                     │   │
│  │  话题3   │  │                          │   │
│  │          │  ├──────────────────────────┤   │
│  │          │  │  [输入框]          [发送] │   │
│  └──────────┘  └──────────────────────────┘   │
└────────────────────────────────────────────────┘

核心功能

话题侧边栏
  • 话题列表展示
    • 名称、最后消息预览、消息数、时间
    • 置顶话题显示在顶部
  • 搜索功能
    • 搜索话题名称和消息内容
    • 实时过滤
  • 话题操作菜单
    • 置顶/取消置顶
    • 重命名
    • 删除
  • 创建新话题
对话区域
  • 空状态提示
    • 引导用户创建对话
  • 对话头部
    • 显示话题名称和消息数
    • 清空消息按钮
  • 消息列表
    • 用户/助手消息区分
    • 头像、角色、时间显示
    • 发送状态(发送中、成功、失败)
    • 打字机动画效果
  • 消息操作
    • 复制消息
    • 重新生成
    • 删除消息
  • 输入区域
    • 多行文本输入
    • Shift+Enter 换行Enter 发送
    • 发送按钮
    • 模型显示(可选)

UI 特性

  1. 响应式布局

    • 左侧固定宽度 280px
    • 右侧自适应
  2. 滚动优化

    • 自动滚动到底部
    • 平滑滚动动画
  3. 状态反馈

    • Loading 状态
    • 发送状态标签
    • 错误提示
  4. 交互体验

    • Hover 效果
    • 选中高亮
    • 快捷键支持

🎨 样式设计

颜色系统

  • 使用 CSS 变量,支持主题切换
  • 用户消息:主色调
  • AI 消息:成功色
  • 错误:错误色

动画效果

  • 打字机动画: 三个跳动的圆点
    @keyframes typing {
      0%, 60%, 100% { opacity: 0.3; }
      30% { opacity: 1; }
    }
    
  • 消息淡入: 新消息出现动画
  • 滚动动画: 平滑滚动到底部

🔧 技术栈

核心框架

  • Vue 3: Composition API
  • TypeScript: 完整类型支持
  • Naive UI: UI 组件库

状态管理

  • Vue Reactivity API: reactive, computed, ref
  • Custom Composable: useChatStore()

数据持久化

  • LocalStorage
    • chat-topics: 话题数据
    • chat-conversations: 对话数据

图标库

  • @vicons/tabler

📊 数据流

用户输入 → ChatLayout
  ↓
  触发 sendMessage()
  ↓
  useChatStore().sendMessageStream()
  ↓
  chatService.sendMessageStream()
  ↓
  1. 创建用户消息
  2. 保存到 conversation
  3. 创建助手消息占位符
  4. 调用 modelServiceManager
  5. 流式接收响应
  6. 实时更新 UI
  7. 更新话题信息
  ↓
  保存到 LocalStorage

🚀 使用指南

基本使用

  1. 启动应用

    npm run dev
    
  2. 配置模型服务

    • 前往"模型服务"页面
    • 添加并连接模型服务(如 OpenAI、Claude
  3. 开始对话

    • 点击左侧菜单"聊天对话"
    • 自动创建默认话题
    • 输入消息开始聊天

功能演示

创建新话题

// 方法1通过按钮
点击侧边栏"+"按钮  输入话题名称  确认

// 方法2通过代码
const store = useChatStore()
store.createTopic('我的新对话')

发送消息

const store = useChatStore()

// 普通发送
await store.sendMessage('你好,请介绍一下自己')

// 流式发送
await store.sendMessageStream(
  '请写一篇文章',
  undefined,
  (chunk) => console.log('收到:', chunk)
)

管理话题

// 置顶
store.toggleTopicPin(topicId)

// 重命名
store.updateTopic(topicId, { name: '新名称' })

// 删除
store.deleteTopic(topicId)

💡 高级特性

1. 上下文管理

系统自动管理对话上下文:

// 发送消息时,自动包含历史消息
const messages = conversation.messages
  .filter(m => m.status === 'success')
  .map(m => ({ role: m.role, content: m.content }))

2. 多格式支持

支持解析多种 AI 服务的响应格式:

  • OpenAI: choices[0].message.content
  • Claude: content[].text
  • Gemini: candidates[0].content.parts[].text
  • 自定义格式

3. 错误处理

try {
  await store.sendMessage(content)
} catch (error) {
  // 自动显示错误信息
  // 消息标记为 error 状态
  // 用户可以重试或重新生成
}

4. 流式响应

虽然当前是模拟流式,但架构已支持真实流式:

// 未来可以直接替换为真实的 SSE 或 WebSocket
await this.callModelStream(conversation, model, (chunk) => {
  onChunk(chunk)  // 实时回调
})

🔮 后续优化建议

短期(本周)

  • 实现 Markdown 渲染
  • 添加代码高亮
  • 支持消息编辑
  • 添加导出对话功能

中期(本月)

  • 实现真实的流式响应SSE
  • 支持图片消息
  • 添加语音输入
  • 实现消息引用回复
  • 添加快捷指令

长期(季度)

  • 多模态支持(图片、文件)
  • 工具调用集成
  • 知识库 RAG
  • 协作功能
  • 插件系统

📁 文件结构

web/src/
├── types/
│   └── chat.ts                 # 类型定义
├── services/
│   └── chatService.ts          # 聊天服务
├── stores/
│   └── chatStore.ts            # 状态管理
├── components/
│   └── Chat/
│       └── ChatLayout.vue      # 统一布局组件
└── SimpleApp.vue               # 主应用(已集成)

🐛 已知限制

  1. 流式响应

    • 当前是模拟流式,需要后端支持 SSE
    • 可优化为真实的流式传输
  2. Markdown 渲染

    • 当前显示纯文本
    • 需要集成 markdown-it 或类似库
  3. 代码高亮

    • 需要集成 highlight.js 或 Prism.js
  4. 图片/文件支持

    • 当前仅支持文本消息
  5. 性能

    • 大量消息时需要虚拟滚动优化

📝 对比 Cherry Studio

相似点

话题管理架构 消息流式响应 LocalStorage 持久化 上下文管理 响应式状态管理

简化点

  • 使用单一组件代替多个子组件
  • 简化的 UI 设计
  • 基础的消息渲染(无 Markdown
  • 模拟流式响应

扩展空间

  • 易于添加 Markdown 渲染
  • 易于添加工具调用
  • 易于集成 MCP 协议
  • 架构支持未来扩展

🎉 总结

成功实现了一个功能完整、架构清晰、易于扩展的聊天对话模块:

600+ 行核心服务代码 200+ 行类型定义 200+ 行状态管理 600+ 行 UI 组件 完整的 CRUD 操作 流式响应支持 LocalStorage 持久化 零编译错误

现在就刷新页面试试吧! 🚀


最后更新: 2025-10-14