Reviewed-on: http://8.161.227.145:3000/XEngineers/CamTalk/pulls/207
CamTalk
⚠️ 在线体验提示:由于演示环境使用 HTTP 协议,需配置 Chrome 允许非 HTTPS 下访问摄像头/麦克风:
- 访问
chrome://flags/#unsafely-treat-insecure-origin-as-secure- 启用该选项,并在输入框填入
http://8.161.227.145:9000- 点击 Relaunch 重启浏览器
✨ 核心特性
- 🎥 多模态理解:摄像头视觉 + 麦克风语音双输入,AI 理解完整场景
- 🗣️ 自然对话:基于 VAD 的端到端语音交互,低延迟流式响应
- 🚀 实时推送:LLM 文本流 + TTS 音频流并行推送,感知延迟 < 0.5 秒
- 🎭 情景模式:自由对话、面试官、英语老师等多场景支持
- 💾 对话历史:自动保存会话,支持搜索、重命名、删除、时间分组
- 🔐 安全认证:JWT 双 token 轮转 + Refresh Token Rotation 防重放
- 📊 三级存储:Memory → Redis → PostgreSQL 自动降级,保障可靠性
- 🌐 国际化:支持中文、英文、日文界面
🏗️ 系统架构
CamTalk 采用三层架构:前端轻量预处理 → Go 网关智能编排 → 云端 AI 按需调用
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 框架的声明式 7 节点 DAG:
START → STT → History → ChatModel → Msg2Str → Splitter → TTS → Done → END
核心优势:
- 流式处理:ChatModel 逐 token 推送,Callback AOP 机制实时转发客户端
- 句子级 TTS:Splitter 实时切分句子,TTS 逐句并行合成,无需等待完整回复
- 类型安全:Go 泛型 + 编译期检查,Graph 拓扑错误在编译时发现
🛠️ 技术栈
| 层级 | 技术选型 | 说明 |
| 前端 | React 18 + TypeScript + Vite | 组件化开发,类型安全,快速热更新 |
| VAD | @ricky0123/vad-web (ONNX Runtime) | 浏览器端语音活动检测,零延迟 |
| 后端 | Go 1.25+ + Gin + gorilla/websocket | 高并发 goroutine,长连接管理 |
| AI 编排 | CloudWeGo Eino Graph | 声明式 DAG,Stream 模式,Callback AOP |
| STT | MiMo ASR(默认)/ Deepgram | 实时语音识别,多语言支持 |
| LLM | DashScope qwen3-vl-plus | 多模态推理(通过 eino-ext OpenAI 接入) |
| TTS | MiMo TTS(默认)/ OpenAI TTS | 自然语音合成 |
| 存储 | PostgreSQL 15 + Redis 7 | 三级存储架构:Memory → Redis → PG |
| 认证 | JWT (HS256) + bcrypt | 双 token 轮转 + Refresh Token Rotation |
| 配置 | Viper + godotenv | YAML + .env + 环境变量覆盖 |
| 日志 | Zap | 高性能结构化日志 + Trace ID 追踪 |
📁 项目结构
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. 克隆项目
git clone https://github.com/yourusername/CamTalk.git
cd CamTalk
2. 配置环境变量
# 复制环境变量模板
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. 启动后端
cd backend
# 安装依赖
go mod download
# 运行数据库迁移(自动创建表)
go run ./cmd/server migrate
# 启动服务(监听 :8080)
go run ./cmd/server
4. 启动前端
cd frontend
# 安装依赖
npm install
# 启动开发服务器(http://localhost:5173)
npm run dev
5. 访问应用
打开浏览器访问 http://localhost:5173,注册账号后即可开始使用。
6. 代码检查与测试
# 安装 Go 代码检查工具
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# 运行后端代码检查
cd backend
golangci-lint run
# 后端单元测试
go test ./...
# 后端集成测试(需要 PostgreSQL)
go test -tags=integration ./...
# 前端代码检查
cd frontend
npm run lint
# 前端测试
npm test
远程部署
方式一:Docker Compose(推荐)
# 1. 克隆代码到服务器
git clone https://github.com/yourusername/CamTalk.git
cd CamTalk
# 2. 配置环境变量
cp backend/.env.example backend/.env
# 编辑 .env 文件,填入生产环境配置
# 3. 一键部署(frontend + backend + postgres + redis)
./deploy.sh up
# 4. 查看日志
./deploy.sh logs
# 5. 停止服务
./deploy.sh down
部署完成后访问 http://localhost:9000
方式二:手动部署
# 1. 构建前端
cd frontend
npm install
npm run build # 输出到 dist/
# 2. 构建后端
cd backend
go build -o camtalk ./cmd/server
# 3. 配置 Nginx
# 参考 nginx.conf.example 配置反向代理
# 4. 启动服务
APP_ENV=prod ./camtalk
# 5. 使用 systemd 管理(可选)
sudo systemctl enable camtalk
sudo systemctl start camtalk
环境变量检查清单
部署前确保已配置以下环境变量:
- ✅
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(STT 服务 API Key) - ✅
CAMTALK_AI_TTS_API_KEY(TTS 服务 API Key) - ✅
APP_ENV=prod(启用生产环境配置)
配置优先级
环境变量 > config.{APP_ENV}.yaml > config.yaml > .env
通过 APP_ENV=prod 切换生产环境配置(启用限流 + 严格 CORS)
📡 WebSocket 协议
连接地址:ws://localhost:8080/ws?token=<jwt>&conversation_id=<uuid>
所有消息为 JSON 文本帧,统一信封格式:
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
🔐 认证体系
CamTalk 采用 JWT 双 token 轮转 + Refresh Token Rotation 安全机制:
双 Token 设计
| Token | 有效期 | 存储位置 | 用途 |
|---|---|---|---|
access_token |
120 分钟 | 前端内存(推荐)/ localStorage | 访问受保护资源 |
refresh_token |
7 天 | httpOnly Cookie(推荐)/ localStorage | 刷新 access_token |
Refresh Token Rotation
每次刷新 token 时:
- 验证
refresh_token签名和有效期 - 查询数据库中的 SHA256 哈希
- 如果哈希不存在 → 检测到 token 复用 → 吊销该用户所有 token
- 删除旧 refresh_token,生成新 token pair
- 返回新 access_token + refresh_token
防重放攻击:旧 refresh_token 立即失效,复用时触发全局吊销,强制所有设备重新登录。
REST API 端点
POST /api/auth/register— 用户注册POST /api/auth/login— 用户登录POST /api/auth/refresh— 刷新 tokenPOST /api/auth/logout— 登出(需认证)GET /api/conversations— 获取对话列表(需认证)POST /api/conversations— 创建对话(需认证)GET /api/health— 健康检查
详细设计见 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-架构设计 | 三层架构、技术栈、数据库设计、部署方案 |
| 02-接口文档 | WebSocket 协议、REST API、AI 服务层、编排器、配置管理 |
| 08-Eino框架与编排设计 | Eino Graph 7 节点 DAG、节点实现、流式处理、Callback AOP |
| 10-鉴权体系 | JWT 双 token 轮转、Refresh Token Rotation、密码安全、中间件 |
| 11-令牌桶限流 | 限流算法、配置策略、生产环境保护 |
| 13-日志追踪 | Zap 日志、Trace ID 全链路追踪、日志级别 |
功能文档
| 文档 | 内容 |
|---|---|
| 03-技术选型 | AI 服务栈、持久化层、前端边缘处理选型 |
| 04-用户故事 | 用户场景与优先级 |
| 05-语音交互 | VAD → STT → LLM → TTS 全链路 |
| 06-视觉理解 | 帧采样、关键帧检测、多模态输入 |
| 07-成本控制 | 采样策略、端云协同、模型分级 |
| 09-情景切换 | 情景模式设计与实现 |
| 12-自定义情景 | 用户自定义情景功能(规划中) |
🐛 问题反馈
遇到问题?请提交 Issue,并提供以下信息:
- 操作系统版本
- Go / Node.js 版本
- 错误日志(后端日志 + 浏览器控制台)
- 复现步骤
📝 版权声明
MIT License © 2024 XEngineers
Built with ❤️ using Go, React, and AI
