# 架构设计

## 项目概述

CamTalk 是一款**多模态实时 AI 视觉对话助手**。用户通过摄像头和麦克风与 AI 交互，AI 理解视觉场景和语音输入后，以文字和语音形式给出自然回应。

核心挑战在于三个维度之间的张力：

| 维度 | 关键问题 |
|------|---------|
| 视觉理解 | 如何准确理解摄像头画面中的人物、物体、场景？ |
| 语音交互 | 如何让对话像真人交流一样自然、低延迟？ |
| 成本控制 | 实时视频流 + LLM 推理，如何避免账单爆炸？ |

## 系统架构

三层架构：**前端做轻量预处理，后端做智能编排，云端 AI 服务按需调用**。

```mermaid
graph TB
    subgraph Browser["浏览器客户端"]
        UI["UI 渲染层<br/>React 18 + TypeScript"]
        Edge["边缘预处理层<br/>VAD / 关键帧检测"]
        Media["媒体采集层<br/>Camera / Microphone"]
    end

    subgraph Gateway["Go 网关"]
        WS["WebSocket Handler<br/>连接管理 / 消息分发"]
        Session["Session Manager<br/>会话状态 / 对话历史"]
        Orch["AI Orchestrator<br/>Eino Graph 声明式编排"]
        Auth["Auth 模块<br/>JWT / bcrypt"]
        REST["REST API<br/>健康检查 / 对话管理"]
        Store["Store 层<br/>Repository 接口"]
    end

    subgraph AI["云端 AI 服务"]
        STT["STT<br/>Deepgram / MiMo ASR"]
        LLM["LLM<br/>GPT-4o / 通义千问"]
        TTS["TTS<br/>OpenAI TTS / MiMo TTS"]
    end

    subgraph Storage["存储层"]
        Mem["Memory<br/>进程内缓存"]
        Redis["Redis<br/>会话状态"]
        PG["PostgreSQL<br/>持久化存储"]
    end

    Media --> Edge
    Edge -->|"query (image+audio)"| WS
    UI <-->|"WebSocket"| WS
    WS --> Session
    WS --> Orch
    Orch --> STT
    Orch --> LLM
    Orch --> TTS
    Session --> Store
    Store --> Mem
    Store --> Redis
    Store --> PG
    REST --> Session
    WS --> Auth
```

> 为什么单独加一层 Go 网关，而不是让前端直连 AI API？1）API Key 安全性；2）统一的速率限制和成本管控；3）多模型路由逻辑集中在一处便于维护。

## 核心交互流程

一次完整的"用户提问 → AI 回答"流程：

```mermaid
sequenceDiagram
    participant B as 浏览器
    participant G as Go 网关（Eino Graph）
    participant S as STT
    participant L as LLM（ChatModel）
    participant T as TTS

    B->>B: VAD 检测到语音结束
    B->>G: query {image, audio}
    Note over G: EinoOrchestrator 启动 Graph.Stream()

    G->>S: STT Lambda：音频 → 文本
    S-->>G: 识别文本
    G-->>B: stt_result {text}

    G->>G: History Lambda：组装提示词 + 历史 + 多模态消息

    G->>L: ChatModel Node：流式推理
    loop LLM 流式输出（Callback OnEndWithStreamOutput）
        L-->>G: token delta
        G-->>B: llm_chunk {delta}
    end

    G->>G: Msg2Str + Splitter Lambda：句子切分
    G->>T: TTS Lambda：逐句合成
    T-->>G: 音频 chunk
    G-->>B: tts_audio {audio}

    G->>G: Done Lambda：发送完成通知
    G-->>B: llm_done {full_text, tokens}
    G-->>B: tts_audio {final: true}
```

**关键优化**：Eino Graph 以 Stream 模式运行，ChatModel 的 token 流通过 Callback 的 `OnEndWithStreamOutput` 实时推送到客户端（`llm_chunk`），同时 Splitter 节点将 token 流切分为句子，TTS 节点逐句合成并推送音频。LLM 文本流和 TTS 音频流**并行推送**，用户感知延迟大幅降低。

## 技术栈

### 前端

| 技术 | 选型 | 选择理由 |
|------|------|---------|
| 框架 | React 18 + TypeScript | 组件化开发，类型安全，生态成熟 |
| 构建 | Vite | 开发热更新快，构建产物小 |
| 实时通信 | WebSocket（原生 API） + 自封装连接管理 | 浏览器原生支持，封装心跳/重连/消息分发 |
| 语音检测 | @ricky0123/vad-web | 基于 WebRTC VAD，纯前端零延迟 |
| 媒体采集 | MediaDevices API | 浏览器原生摄像头/麦克风访问 |

### 后端

| 技术 | 选型 | 选择理由 |
|------|------|---------|
| 语言 | Go | 高并发 goroutine 模型，适合长连接管理 |
| HTTP 框架 | Gin | 高性能 HTTP 路由，中间件生态成熟 |
| WebSocket | gorilla/websocket | Go 生态最成熟的 WebSocket 库 |
| 会话存储 | Memory / Redis / PostgreSQL 三级存储 | 进程内存零依赖，Redis 支持多实例，PG 持久化。TieredManager 自动降级 |
| AI 编排 | CloudWeGo Eino Graph | 声明式 DAG 编排，Stream 模式，Callback AOP |
| 持久化存储 | PostgreSQL | 对话历史、用户数据、会话元数据 |
| 配置管理 | Viper + godotenv | 支持 YAML + .env + 环境变量覆盖 |
| 日志 | Zap | 高性能结构化日志 |

### AI 服务

| 能力 | 默认方案 | 备选方案 |
|------|---------|---------|
| 多模态 LLM | DashScope qwen3-vl-plus | GPT-4o 等 OpenAI 兼容模型 |
| 语音识别 STT | MiMo ASR（小米） | Deepgram |
| 语音合成 TTS | MiMo TTS（小米） | OpenAI TTS |

> Go 网关的 AI 服务层统一封装不同服务商的调用接口，通过配置切换 provider。LLM 通过 Eino 框架的 `eino-ext/components/model/openai` 组件接入，支持任何 OpenAI 兼容接口。

## 后端模块

```mermaid
graph LR
    subgraph Entry["入口层"]
        Main["main.go<br/>依赖注入 / 启动"]
    end

    subgraph Transport["传输层"]
        WSH["WebSocket Handler<br/>连接管理 / 认证"]
        APH["REST API Handlers<br/>Auth / Conversation / Health"]
    end

    subgraph Business["业务层"]
        SM["Session Manager<br/>会话生命周期"]
        ORCH["EinoOrchestrator<br/>Eino Graph 编排"]
        AS["Auth Service<br/>注册/登录/刷新/登出"]
    end

    subgraph Eino_Layer["Eino 编排层"]
        PG["PipelineGraph<br/>7 节点 DAG"]
        CB["Callback Handler<br/>LLM token 推送"]
        ST["PipelineState<br/>跨节点状态"]
    end

    subgraph AI_Layer["AI 服务层"]
        STT_S["STT Service<br/>MiMo / Deepgram"]
        LLM_S["ChatModel<br/>eino-ext OpenAI 兼容"]
        TTS_S["TTS Service<br/>MiMo / OpenAI"]
    end

    subgraph Data["数据层"]
        UR["UserRepository"]
        MR["MessageRepository"]
        SR["SessionRepository"]
    end

    Main --> WSH
    Main --> APH
    Main --> SM
    Main --> ORCH
    Main --> AS

    WSH --> SM
    WSH --> ORCH
    APH --> SM
    APH --> AS
    ORCH --> PG
    PG --> CB
    PG --> ST
    PG --> STT_S
    PG --> LLM_S
    PG --> TTS_S
    SM --> MR
    SM --> SR
    AS --> UR
```

| 模块 | 职责 |
|------|------|
| WebSocket Handler | 管理客户端连接生命周期，JWT 认证，conversation_id 恢复，单播消息推送 |
| Session Manager | 维护用户会话状态、对话历史，三级存储架构，30 分钟 TTL |
| Eino 编排层 | 基于 CloudWeGo Eino Graph 的声明式 AI 编排，7 节点 DAG 流水线，Stream 模式调用 |
| AI Orchestrator | EinoOrchestrator 适配器，包装 Eino Graph 实现 Orchestrator 接口 |
| AI Service Layer | AI 服务抽象层，多 provider 支持（Deepgram/MiMo/OpenAI 等） |
| Auth | 用户认证与授权，JWT 双 token 轮转，bcrypt 密码哈希 |
| Store | 持久化存储层，Repository 接口与实现（内存 + PostgreSQL） |
| REST API | 健康检查、认证、对话管理端点 |
| Logger | Zap 结构化日志 |
| Models | 数据模型定义 |
| Migrations | 数据库版本化迁移 |
| Model Router | 根据请求类型选择 AI 模型（待实现） |
| Rate Limiter | 令牌桶限流，详见 [11-令牌桶限流.md](./11-令牌桶限流.md) |

## 前端组件

| 组件 | 职责 |
|------|------|
| LandingPage | 未登录时的着陆页，内嵌 LoginModal 登录/注册弹窗 |
| CameraManager | 摄像头流采集 |
| MicManager | 麦克风音频采集 |
| EdgeProcessor | VAD + 关键帧检测 |
| WebSocketManager | WebSocket 连接生命周期管理 |
| ChatPanel | 消息展示、流式回复、文本输入、场景选择 |
| VideoPreview | 摄像头画面预览 |
| SessionSidebar | 左侧对话列表（搜索、重命名、删除、时间分组） |
| ConfigPanel | 右侧配置面板（主题、TTS 开关、detail level、语言、场景、登出） |
| Toast | 轻量通知提示 |

核心 Hook：`useVisionSession()` 封装完整的视觉对话会话（摄像头、VAD、WebSocket、消息状态、认证、场景模式）。`useSessionList()` 通过 REST API 管理对话列表 CRUD。

### 前端会话状态模型（三态）

前端 UI 存在三个会话状态，由 `isConnected` 和 `isCameraOn` 联合决定：

```
┌──────────┐    startSession()    ┌──────────┐
│  initial  │ ──────────────────→ │  video   │
│  初始态    │                     │  视频通话  │
└──────────┘                      └──────────┘
      ↑                                │
      │ stopSession()            stopVideo()
      │                                │
      │                                ▼
      │                         ┌──────────┐
      └──────────────────────── │ textOnly │
                                │ 文字对话  │
                                └──────────┘
                                      │
                                startSession()
                                      │
                                      ▼
                                ┌──────────┐
                                │  video   │
                                └──────────┘
```

| 状态 | 条件 | WebSocket | 摄像头 | 消息 | 文字输入 |
|------|------|-----------|--------|------|---------|
| `initial` | `!isConnected && messages.length === 0` | 断开 | 关闭 | 空 | 可用（自动连接） |
| `video` | `isConnected && isCameraOn` | 连接 | 开启 | 有 | 可用 |
| `textOnly` | `isConnected && !isCameraOn` | 连接 | 关闭 | 保留 | 可用 |

- **`stopVideo()`**：停止摄像头/麦克风/VAD，保持 WebSocket 连接和消息历史，用户可继续文字对话
- **`stopSession()`**：完全断开 WebSocket、清空消息、重置状态，回到初始态

## 数据库设计

### ER 关系

```mermaid
erDiagram
    users ||--o{ sessions : "1:N"
    users ||--o{ refresh_tokens : "1:N"
    sessions ||--o{ messages : "1:N"

    users {
        uuid id PK
        varchar username UK
        varchar password_hash
        timestamptz created_at
        timestamptz updated_at
    }

    sessions {
        uuid id PK
        uuid user_id FK
        varchar title
        jsonb config
        timestamptz created_at
        timestamptz updated_at
    }

    messages {
        bigserial id PK
        uuid session_id FK
        varchar role
        text content
        integer tokens_used
        timestamptz created_at
    }

    refresh_tokens {
        bigserial id PK
        uuid user_id FK
        varchar token_hash UK
        timestamptz expires_at
        timestamptz created_at
    }
```

系统采用关系型数据库存储持久化数据，包括用户账户、对话会话、消息记录和刷新令牌。数据库表定义详见 `backend/migrations/` 目录下的 SQL 迁移文件。

### 存储策略

系统采用**三级存储架构**（TieredManager）实现会话状态管理，平衡性能与可靠性：

- **L1 Memory**：进程内缓存，提供微秒级读写性能
- **L2 Redis**：分布式缓存层，支持多实例部署，提供毫秒级访问
- **L3 PostgreSQL**：持久化存储层，确保数据可靠性

会话数据按 TTL（默认 30 分钟）在三级存储间流转，支持 Redis 故障时自动降级到 Memory + PostgreSQL 模式。配置灵活，可根据部署规模选择单级（Memory）、双级（Memory + PostgreSQL）或完整三级存储方案。

## 认证设计

系统采用 **JWT 双 token 轮转认证机制**，结合 bcrypt 密码哈希和 Refresh Token Rotation 安全策略。

核心机制包括：双 token 轮转（access_token 15 分钟 + refresh_token 7 天）、密码安全（bcrypt cost=10）、token 安全（SHA256 哈希存储、复用检测）、WebSocket 连接认证（基于 access_token 的 HTTP Upgrade 校验）等。认证流程、安全机制、配置要求等详细设计见 [10-鉴权体系.md](./10-鉴权体系.md)。

## 部署架构

系统采用分层部署架构，支持单实例和多实例水平扩展：

```mermaid
graph TB
    User["用户浏览器"] --> Nginx
    
    subgraph Nginx["Nginx 反向代理"]
        Static["/ → 前端静态资源"]
        API["/api/* → Go Gateway"]
        WS_Proxy["/ws → Go Gateway"]
    end
    
    subgraph Gateway_Pool["Go Gateway 实例"]
        G1["Gateway-1"]
        G2["Gateway-2"]
        GN["Gateway-N"]
    end
    
    Nginx --> G1
    Nginx --> G2
    Nginx --> GN
    
    G1 --> Redis
    G2 --> Redis
    GN --> Redis
    
    G1 --> PG_DB["PostgreSQL"]
    G2 --> PG_DB
    GN --> PG_DB
    
    G1 --> AI_Services["AI Services（外部 API）"]
    G2 --> AI_Services
    GN --> AI_Services
```

**跨域策略**：Nginx 将前端（`/`）、REST API（`/api/*`）、WebSocket（`/ws`）统一反代到同一域名，浏览器无跨域问题。

**开发环境**：前端 Vite :5173 通过 `server.proxy` 转发 `/ws` 和 `/api` 到后端 :8080，无需硬编码端口。
