# CamTalk

<div align="center">

**多模态实时 AI 视觉对话助手**

用户通过摄像头和麦克风与 AI 交互，AI 理解视觉场景和语音输入后，以文字和语音形式给出自然回应

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Go Version](https://img.shields.io/badge/Go-1.25+-00ADD8?logo=go)](https://go.dev/)
[![React](https://img.shields.io/badge/React-18-61DAFB?logo=react)](https://react.dev/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript)](https://www.typescriptlang.org/)

[路演视频](https://www.bilibili.com/video/BV1dDJK6cE5S/) • [在线体验](http://8.161.227.145:9000) • [文档](docs/README.md)

</div>

---

![CamTalk 界面截图](docs/pictures/1.png)

> ⚠️ **在线体验提示**：由于演示环境使用 HTTP 协议，需配置 Chrome 允许非 HTTPS 下访问摄像头/麦克风：
>
> 1. 访问 `chrome://flags/#unsafely-treat-insecure-origin-as-secure`
> 2. 启用该选项，并在输入框填入 `http://8.161.227.145:9000`
> 3. 点击 **Relaunch** 重启浏览器

## ✨ 核心特性

- 🎥 **多模态理解**：摄像头视觉 + 麦克风语音双输入，AI 理解完整场景
- 🗣️ **自然对话**：基于 VAD 的端到端语音交互，低延迟流式响应
- 🚀 **实时推送**：LLM 文本流 + TTS 音频流并行推送，感知延迟 < 0.5 秒
- 🎭 **情景模式**：自由对话、面试官、英语老师等多场景支持
- 💾 **对话历史**：自动保存会话，支持搜索、重命名、删除、时间分组
- 🔐 **安全认证**：JWT 双 token 轮转 + Refresh Token Rotation 防重放
- 📊 **三级存储**：Memory → Redis → PostgreSQL 自动降级，保障可靠性
- 🌐 **国际化**：支持中文、英文、日文界面

## 🏗️ 系统架构

CamTalk 采用**三层架构**：前端轻量预处理 → Go 网关智能编排 → 云端 AI 按需调用

```mermaid
graph TB
    subgraph Browser["🌐 浏览器客户端"]
        UI["React UI 渲染"]
        VAD["VAD 语音检测"]
        Media["媒体采集"]
    end

    subgraph Gateway["⚙️ Go 网关 (Eino Graph)"]
        WS["WebSocket Handler"]
        Auth["JWT 认证"]
        Session["会话管理 (三级存储)"]
        Orch["AI 编排器 (7节点DAG)"]
    end

    subgraph AI["☁️ 云端 AI 服务"]
        STT["STT (MiMo/Deepgram)"]
        LLM["LLM (qwen3-vl-plus)"]
        TTS["TTS (MiMo/OpenAI)"]
    end

    Browser <-->|"WebSocket<br/>(JWT + query/config)"| Gateway
    Orch --> STT
    Orch --> LLM
    Orch --> TTS
```

### AI 编排流水线（Eino Graph）

基于 [CloudWeGo Eino](https://github.com/cloudwego/eino) 框架的声明式 7 节点 DAG：

```
START → STT → History → ChatModel → Msg2Str → Splitter → TTS → Done → END
```

**核心优势**：
- **流式处理**：ChatModel 逐 token 推送，Callback AOP 机制实时转发客户端
- **句子级 TTS**：Splitter 实时切分句子，TTS 逐句并行合成，无需等待完整回复
- **类型安全**：Go 泛型 + 编译期检查，Graph 拓扑错误在编译时发现

## 🛠️ 技术栈

<table>
<tr>
<td><b>层级</b></td>
<td><b>技术选型</b></td>
<td><b>说明</b></td>
</tr>
<tr>
<td><b>前端</b></td>
<td>React 18 + TypeScript + Vite</td>
<td>组件化开发，类型安全，快速热更新</td>
</tr>
<tr>
<td><b>VAD</b></td>
<td>@ricky0123/vad-web (ONNX Runtime)</td>
<td>浏览器端语音活动检测，零延迟</td>
</tr>
<tr>
<td><b>后端</b></td>
<td>Go 1.25+ + Gin + gorilla/websocket</td>
<td>高并发 goroutine，长连接管理</td>
</tr>
<tr>
<td><b>AI 编排</b></td>
<td>CloudWeGo Eino Graph</td>
<td>声明式 DAG，Stream 模式，Callback AOP</td>
</tr>
<tr>
<td><b>STT</b></td>
<td>MiMo ASR（默认）/ Deepgram</td>
<td>实时语音识别，多语言支持</td>
</tr>
<tr>
<td><b>LLM</b></td>
<td>DashScope qwen3-vl-plus</td>
<td>多模态推理（通过 eino-ext OpenAI 接入）</td>
</tr>
<tr>
<td><b>TTS</b></td>
<td>MiMo TTS（默认）/ OpenAI TTS</td>
<td>自然语音合成</td>
</tr>
<tr>
<td><b>存储</b></td>
<td>PostgreSQL 15 + Redis 7</td>
<td>三级存储架构：Memory → Redis → PG</td>
</tr>
<tr>
<td><b>认证</b></td>
<td>JWT (HS256) + bcrypt</td>
<td>双 token 轮转 + Refresh Token Rotation</td>
</tr>
<tr>
<td><b>配置</b></td>
<td>Viper + godotenv</td>
<td>YAML + .env + 环境变量覆盖</td>
</tr>
<tr>
<td><b>日志</b></td>
<td>Zap</td>
<td>高性能结构化日志 + Trace ID 追踪</td>
</tr>
</table>

## 📁 项目结构

```
CamTalk/
├── frontend/                   # 🌐 浏览器客户端
│   └── src/
│       ├── components/         # UI 组件
│       │   ├── LandingPage/    # 登录着陆页 + LoginModal
│       │   ├── CameraManager/  # 摄像头流采集
│       │   ├── MicManager/     # 麦克风音频采集 + VAD
│       │   ├── WebSocketManager/ # WS 连接生命周期
│       │   ├── ChatPanel/      # 消息展示 + 流式回复
│       │   ├── SessionSidebar/ # 对话历史侧边栏
│       │   └── ConfigPanel/    # 配置面板（主题/TTS/语言/场景）
│       ├── hooks/              # 自定义 Hooks
│       │   ├── useVisionSession.ts  # 核心会话 Hook (~500 行)
│       │   ├── useSessionList.ts    # 对话列表管理
│       │   └── useObservationMode.ts # 观察模式
│       ├── lib/                # 工具库
│       │   ├── websocket.ts    # WebSocket 单例（心跳/重连/订阅）
│       │   ├── api.ts          # REST 客户端（401拦截+刷新）
│       │   ├── auth.tsx        # AuthProvider（JWT 自动刷新）
│       │   ├── ttsPlayer.ts    # TTS 流式播放队列
│       │   └── i18n/           # 国际化（zh-CN/en-US/ja-JP）
│       └── types/              # TypeScript 类型定义
├── backend/                    # ⚙️ Go 网关
│   ├── cmd/server/             # 服务入口（main.go）
│   └── internal/
│       ├── eino/               # 🔥 Eino Graph 编排层（7节点DAG）
│       │   ├── graph.go        # Graph 构建与编译
│       │   ├── adapter.go      # EinoOrchestrator 适配器
│       │   ├── callback.go     # LLM token 推送回调
│       │   ├── state.go        # 跨节点状态管理
│       │   └── nodes_*.go      # STT/History/Splitter/TTS/Done 节点
│       ├── session/            # 会话管理（TieredManager 三级存储）
│       ├── store/              # 持久化层（Repository 接口 + PG/内存实现）
│       │   ├── user_pg.go      # PostgreSQL 实现
│       │   └── cached_user.go  # Redis 缓存装饰器
│       ├── auth/               # 认证（JWT/bcrypt/中间件）
│       ├── ai/                 # AI 服务抽象层
│       │   ├── llm/            # LLM 提示词与场景
│       │   ├── stt/            # STT 服务（MiMo/Deepgram）
│       │   └── tts/            # TTS 服务（MiMo/OpenAI）
│       ├── ws/                 # WebSocket Handler
│       ├── api/                # REST API（Auth/Conversation）
│       ├── config/             # 配置管理（Viper）
│       └── logger/             # 日志（Zap + Trace ID）
├── migrations/                 # 📊 数据库迁移（嵌入式 SQL）
├── docs/                       # 📚 设计文档
│   ├── 01-架构设计.md
│   ├── 02-接口文档.md
│   ├── 08-Eino框架与编排设计.md
│   ├── 10-鉴权体系.md
│   └── 13-日志追踪.md
├── deploy.sh                   # 🐳 部署脚本（Docker Compose）
├── docker-compose.yml          # 容器编排配置
└── CLAUDE.md                   # 🤖 Claude Code 开发指引
```

## 🚀 快速开始

### 前置条件

- **Node.js** >= 18
- **Go** >= 1.25
- **PostgreSQL** >= 15（可选 Docker）
- **Redis** >= 7（可选，用于缓存加速）

### 1. 克隆项目

```bash
git clone https://github.com/yourusername/CamTalk.git
cd CamTalk
```

### 2. 配置环境变量

```bash
# 复制环境变量模板
cp backend/.env.example backend/.env

# 编辑 .env 文件，填入以下必需配置：
# - CAMTALK_AUTH_JWT_SECRET（使用 openssl rand -hex 32 生成）
# - CAMTALK_STORAGE_DSN（PostgreSQL 连接字符串）
# - CAMTALK_AI_LLM_API_KEY（DashScope API Key）
# - CAMTALK_AI_STT_API_KEY（MiMo/Deepgram API Key）
# - CAMTALK_AI_TTS_API_KEY（MiMo/OpenAI API Key）
```

### 3. 启动后端

```bash
cd backend

# 安装依赖
go mod download

# 运行数据库迁移（自动创建表）
go run ./cmd/server migrate

# 启动服务（监听 :8080）
go run ./cmd/server
```

### 4. 启动前端

```bash
cd frontend

# 安装依赖
npm install

# 启动开发服务器（http://localhost:5173）
npm run dev
```

### 5. 访问应用

打开浏览器访问 [http://localhost:5173](http://localhost:5173)，注册账号后即可开始使用。

---

### 🐳 Docker 快速部署（生产环境）

```bash
# 一键启动全部服务（frontend + backend + postgres + redis）
./deploy.sh up

# 停止服务
./deploy.sh down

# 查看日志
./deploy.sh logs
```

部署完成后访问 [http://localhost:9000](http://localhost:9000)

### 配置优先级

```
环境变量 > config.{APP_ENV}.yaml > config.yaml > .env
```

通过 `APP_ENV=prod` 切换生产环境配置（启用限流 + 严格 CORS）

## 📡 WebSocket 协议

连接地址：`ws://localhost:8080/ws?token=<jwt>&conversation_id=<uuid>`

所有消息为 JSON 文本帧，统一信封格式：

```typescript
interface BaseMessage {
  type: string;
  request_id?: string;
  timestamp?: number;
}
```

### 客户端 → 服务端

| 消息类型 | 说明 | 示例 |
|---------|------|------|
| `query` | 发送视觉+语音查询 | `{type: "query", image: "base64...", audio: "base64..."}` |
| `config` | 更新会话配置 | `{type: "config", scenario: "interviewer", language: "en"}` |
| `interrupt` | 中断当前响应 | `{type: "interrupt", request_id: "xxx"}` |
| `ping` | 心跳保活 | `{type: "ping"}` |

### 服务端 → 客户端

| 消息类型 | 说明 | 触发时机 |
|---------|------|---------|
| `connected` | 连接成功 | WebSocket 握手后 |
| `stt_result` | STT 识别结果 | STT 节点完成 |
| `llm_chunk` | LLM 文本增量 | ChatModel 逐 token（Callback） |
| `llm_done` | LLM 推理完成 | Done 节点执行 |
| `tts_audio` | TTS 音频片段 | TTS 节点逐句合成 |
| `error` | 错误通知 | 任意节点失败 |
| `pong` | 心跳响应 | 响应 `ping` |

**心跳机制**：
- 客户端每 30 秒发送 `ping`
- 服务端 60 秒无消息自动断连
- 断连后自动重连（指数退避 1s → 30s）

完整协议定义见 [docs/02-接口文档.md](docs/02-接口文档.md)

## 🔐 认证体系

CamTalk 采用 **JWT 双 token 轮转 + Refresh Token Rotation** 安全机制：

### 双 Token 设计

| Token | 有效期 | 存储位置 | 用途 |
|-------|-------|---------|------|
| `access_token` | 120 分钟 | 前端内存（推荐）/ localStorage | 访问受保护资源 |
| `refresh_token` | 7 天 | httpOnly Cookie（推荐）/ localStorage | 刷新 access_token |

### Refresh Token Rotation

每次刷新 token 时：
1. 验证 `refresh_token` 签名和有效期
2. 查询数据库中的 SHA256 哈希
3. **如果哈希不存在** → 检测到 token 复用 → **吊销该用户所有 token**
4. 删除旧 refresh_token，生成新 token pair
5. 返回新 access_token + refresh_token

**防重放攻击**：旧 refresh_token 立即失效，复用时触发全局吊销，强制所有设备重新登录。

### REST API 端点

- `POST /api/auth/register` — 用户注册
- `POST /api/auth/login` — 用户登录
- `POST /api/auth/refresh` — 刷新 token
- `POST /api/auth/logout` — 登出（需认证）
- `GET /api/conversations` — 获取对话列表（需认证）
- `POST /api/conversations` — 创建对话（需认证）
- `GET /api/health` — 健康检查

详细设计见 [docs/10-鉴权体系.md](docs/10-鉴权体系.md)

## 💾 三级存储架构

**TieredManager** 实现会话状态的三级存储，平衡性能与可靠性：

```
┌─────────────┐
│  L1 Memory  │ ← 微秒级读写，进程内缓存
├─────────────┤
│  L2 Redis   │ ← 毫秒级访问，跨实例共享
├─────────────┤
│ L3 PostgreSQL│ ← 持久化存储，数据可靠性
└─────────────┘
```

**特性**：
- ✅ **自动降级**：Redis 故障时自动切换到 Memory + PostgreSQL 模式
- ✅ **灵活配置**：支持单级（Memory）、双级（Memory + PG）、完整三级
- ✅ **TTL 管理**：会话默认 30 分钟过期，自动清理
- ✅ **写穿透**：数据先写 L1，异步同步到 L2/L3

## 📊 数据库设计

系统使用 PostgreSQL 存储持久化数据：

### 核心表

| 表名 | 说明 | 关键字段 |
|------|------|---------|
| `users` | 用户账户 | `id (UUID)`, `username (UNIQUE)`, `password_hash (bcrypt)` |
| `sessions` | 对话会话 | `id (UUID)`, `user_id (FK)`, `title`, `config (JSONB)` |
| `messages` | 消息记录 | `id (BIGSERIAL)`, `session_id (FK)`, `role`, `content`, `tokens_used` |
| `refresh_tokens` | 刷新令牌 | `token_hash (PK, SHA256)`, `user_id (FK)`, `expires_at` |

**关系**：`users 1:N sessions 1:N messages`，`users 1:N refresh_tokens`

**迁移管理**：使用嵌入式 SQL 文件（`backend/migrations/`），应用启动时自动执行。

## 🛡️ 安全特性

- 🔒 **密码安全**：bcrypt (cost=10) 哈希，自动生成盐值
- 🔑 **Token 安全**：JWT HS256 签名，refresh_token SHA256 哈希存储
- 🚫 **防重放攻击**：Refresh Token Rotation + 复用检测自动吊销
- 🌐 **传输安全**：生产环境强制 HTTPS，开发环境 Vite proxy 同源代理
- 🚦 **限流保护**：令牌桶算法（生产环境启用），防暴力破解
- 🔍 **日志追踪**：全链路 Trace ID，请求/响应/错误统一记录

## 🌍 部署架构

```
┌─────────────┐
│   Nginx     │ ← 反向代理（静态资源 + API + WebSocket）
└──────┬──────┘
       │
┌──────┴───────────────────┐
│  Go Gateway 集群          │
│  ├─ Gateway-1            │
│  ├─ Gateway-2            │
│  └─ Gateway-N            │
└───┬────────────┬─────────┘
    │            │
┌───┴────┐  ┌───┴────────┐
│ Redis  │  │ PostgreSQL │
└────────┘  └────────────┘
    │
┌───┴────────────────────┐
│  外部 AI 服务           │
│  ├─ DashScope (LLM)   │
│  ├─ MiMo (STT/TTS)    │
│  └─ Deepgram (可选)    │
└───────────────────────┘
```

**跨域策略**：Nginx 统一反代前后端到同一域名，无跨域问题。

**水平扩展**：Gateway 无状态设计，会话状态存储在 Redis/PostgreSQL，支持多实例部署。

## 📖 文档
|------|------|
| [01-架构设计](docs/01-架构设计.md) | 三层架构、技术栈、数据库设计、部署方案 |
| [02-接口文档](docs/02-接口文档.md) | WebSocket 协议、REST API、AI 服务层、编排器、配置管理 |
## 📖 文档

### 核心设计文档

| 文档 | 内容 |
|------|------|
| [01-架构设计](docs/01-架构设计.md) | 三层架构、技术栈、数据库设计、部署方案 |
| [02-接口文档](docs/02-接口文档.md) | WebSocket 协议、REST API、AI 服务层、编排器、配置管理 |
| [08-Eino框架与编排设计](docs/08-Eino框架与编排设计.md) | Eino Graph 7 节点 DAG、节点实现、流式处理、Callback AOP |
| [10-鉴权体系](docs/10-鉴权体系.md) | JWT 双 token 轮转、Refresh Token Rotation、密码安全、中间件 |
| [11-令牌桶限流](docs/11-令牌桶限流.md) | 限流算法、配置策略、生产环境保护 |
| [13-日志追踪](docs/13-日志追踪.md) | Zap 日志、Trace ID 全链路追踪、日志级别 |

### 功能文档

| 文档 | 内容 |
|------|------|
| [03-技术选型](docs/03-技术选型.md) | AI 服务栈、持久化层、前端边缘处理选型 |
| [04-用户故事](docs/04-用户故事.md) | 用户场景与优先级 |
| [05-语音交互](docs/05-语音交互.md) | VAD → STT → LLM → TTS 全链路 |
| [06-视觉理解](docs/06-视觉理解.md) | 帧采样、关键帧检测、多模态输入 |
| [07-成本控制](docs/07-成本控制.md) | 采样策略、端云协同、模型分级 |
| [09-情景切换](docs/09-情景切换.md) | 情景模式设计与实现 |
| [12-自定义情景](docs/12-自定义情景.md) | 用户自定义情景功能（规划中） |

## 🤝 贡献指南

欢迎提交 Issue 和 Pull Request！

### 开发规范

- **提交信息**：遵循 [Conventional Commits](https://www.conventionalcommits.org/)，中文描述（例：`feat: 添加 WebSocket 心跳`）
- **Go 代码**：遵循标准 Go 规范，使用 `golangci-lint` 检查
- **TypeScript 代码**：严格模式，使用 ESLint + Prettier
- **文档优先**：开发前先读 `docs/` 设计文档，代码与文档不一致时优先更新文档

### 本地开发环境

```bash
# 安装开发工具
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

# 运行代码检查
cd backend
golangci-lint run

# 运行测试
go test ./...

# 前端测试
cd frontend
npm test
```

## 🐛 问题反馈

遇到问题？请提交 [Issue](https://github.com/yourusername/CamTalk/issues)，并提供以下信息：

- 操作系统版本
- Go / Node.js 版本
- 错误日志（后端日志 + 浏览器控制台）
- 复现步骤

## 📝 版权声明

MIT License © 2024 XEngineers

---

<div align="center">

**Built with ❤️ using Go, React, and AI**

[⬆️ 回到顶部](#camtalk)

</div>
