docs: 同步文档与代码实现状态
- 02-系统架构: Redis/PostgreSQL 标注已实现,模块表新增 Auth/Store/Migrations,更新表设计和前端组件 - 03-接口文档: config 新增 scenario 字段,Manager 接口补全 UpdateTitle/ListByUser,配置结构体同步,扩展接口替换为实际 Repository - 04-技术选型: 持久化层标注已实现 - 06-语音交互: TTS Voice 更正为 mimo_default - 11-持久化与用户系统设计: 所有 Phase 标记完成 - PLAN_BACKEND/PLAN_USER_MODULE: 标记完成状态 - README: 新增实现状态总览,补充文档索引
This commit is contained in:
126
docs/02-系统架构.md
126
docs/02-系统架构.md
@@ -34,8 +34,8 @@
|
||||
| 语言 | Go | 高并发 goroutine 模型,适合长连接管理 |
|
||||
| HTTP 框架 | Gin | 高性能 HTTP 路由,中间件生态成熟 |
|
||||
| WebSocket | gorilla/websocket | Go 生态最成熟的 WebSocket 库 |
|
||||
| 会话存储 | Redis(规划中) / Memory(MVP 默认) | 高速 KV 存储,MVP 阶段使用进程内存,可通过配置切换到 Redis |
|
||||
| 持久化存储 | PostgreSQL(规划中) | 对话历史、用量统计、用户偏好(MVP 阶段未实现) |
|
||||
| 会话存储 | Redis(已实现) / Memory(默认) | 高速 KV 存储,Memory 为默认实现,Redis 已实现可通过配置切换 |
|
||||
| 持久化存储 | PostgreSQL(已实现) | 对话历史、用户数据、会话持久化。MemoryManager 支持 Write-Through 到 PG |
|
||||
| 配置管理 | Viper + godotenv | 支持 YAML + .env + 环境变量覆盖,详见 `03-接口文档.md` 第六章 |
|
||||
| 日志 | Zap | 高性能结构化日志 |
|
||||
|
||||
@@ -76,18 +76,21 @@ Browser Go Gateway STT LLM TTS
|
||||
|
||||
## 后端模块
|
||||
|
||||
| 模块 | 职责 | 关键实现 |
|
||||
|------|------|---------|
|
||||
| WebSocket Handler | 管理客户端连接生命周期,单播消息推送 | goroutine per connection |
|
||||
| Session Manager | 维护用户会话状态、对话历史 | Memory(MVP 默认)/ Redis(可切换),30 分钟 TTL(详见 `03-接口文档.md` 第五章) |
|
||||
| AI Orchestrator | 编排 STT→LLM→TTS 流式并行管道 | context 取消 + 超时控制 + 句子切分 |
|
||||
| AI Service Layer | AI 服务抽象层(STT/LLM/TTS) | 多 provider 支持(Deepgram/MiMo/OpenAI 等) |
|
||||
| REST API | 健康检查、会话管理端点 | Gin 路由 |
|
||||
| Error Handler | 统一错误码定义与发送 | 错误码枚举 |
|
||||
| Logger | 日志初始化封装 | Zap 结构化日志 |
|
||||
| Models | 数据模型定义 | WebSocket 消息、会话、配置等 |
|
||||
| Model Router | 根据请求类型选择 AI 模型(规划中) | 规则引擎 + 成本阈值 |
|
||||
| Rate Limiter | 防止单用户过度消耗 API 额度(规划中) | 令牌桶算法 |
|
||||
| 模块 | 职责 | 关键实现 | 状态 |
|
||||
|------|------|---------|------|
|
||||
| WebSocket Handler | 管理客户端连接生命周期,单播消息推送 | goroutine per connection,JWT 认证,conversation_id 恢复 | ✅ 已完成 |
|
||||
| Session Manager | 维护用户会话状态、对话历史 | Memory(默认)/ Redis(可切换),30 分钟 TTL,Write-Through 到 PG(详见 `03-接口文档.md` 第五章) | ✅ 已完成 |
|
||||
| AI Orchestrator | 编排 STT→LLM→TTS 流式并行管道 | context 取消 + 超时控制 + 句子切分 | ✅ 已完成 |
|
||||
| AI Service Layer | AI 服务抽象层(STT/LLM/TTS) | 多 provider 支持(Deepgram/MiMo/OpenAI 等) | ✅ 已完成 |
|
||||
| Auth | 用户认证与授权 | JWT (HS256) 双 token 轮转,bcrypt 密码哈希,Gin 中间件 | ✅ 已完成 |
|
||||
| Store | 持久化存储层 | UserRepository / MessageRepository / SessionRepository,内存 + PostgreSQL 双实现 | ✅ 已完成 |
|
||||
| REST API | 健康检查、认证、对话管理端点 | Gin 路由,输入校验,权限校验 | ✅ 已完成 |
|
||||
| Error Handler | 统一错误码定义与发送 | 错误码枚举 | ✅ 已完成 |
|
||||
| Logger | 日志初始化封装 | Zap 结构化日志 | ✅ 已完成 |
|
||||
| Models | 数据模型定义 | WebSocket 消息、会话、配置、用户等 | ✅ 已完成 |
|
||||
| Migrations | 数据库版本化迁移 | 嵌入式 SQL 文件,自动执行,版本跟踪 | ✅ 已完成 |
|
||||
| Model Router | 根据请求类型选择 AI 模型 | 规则引擎 + 成本阈值 | 📋 规划中 |
|
||||
| Rate Limiter | 防止单用户过度消耗 API 额度 | 令牌桶算法 | 📋 规划中 |
|
||||
|
||||
AI Orchestrator 核心接口(`internal/orchestrator/orchestrator.go`):
|
||||
|
||||
@@ -113,44 +116,31 @@ Pipeline 实现(`internal/orchestrator/pipeline.go`)流程:
|
||||
|
||||
| 组件 | 职责 |
|
||||
|------|------|
|
||||
| AuthPage | 登录/注册表单,前端校验,Tab 切换 |
|
||||
| CameraManager | 摄像头流采集 |
|
||||
| MicManager | 麦克风音频采集 |
|
||||
| EdgeProcessor | VAD + 关键帧检测(Canvas 像素比较) |
|
||||
| WebSocketManager | WS 连接生命周期管理 |
|
||||
| ChatPanel | 消息展示 |
|
||||
| ChatPanel | 消息展示、流式回复、文本输入、场景选择 |
|
||||
| VideoPreview | 摄像头画面预览 |
|
||||
| ConfigPanel | 右侧抽屉式配置面板(主题、TTS 开关、detail level、语言) |
|
||||
| SessionSidebar | 左侧抽屉式对话列表(搜索、重命名、删除) |
|
||||
| ConfigPanel | 右侧抽屉式配置面板(主题、TTS 开关、detail level、语言、场景、账户) |
|
||||
| Toast | 轻量通知提示(3 秒自动消失) |
|
||||
|
||||
核心 Hook:`useVisionSession()` 封装一次完整的视觉对话会话(摄像头、VAD、WebSocket、消息状态)。
|
||||
核心 Hook:`useVisionSession()` 封装一次完整的视觉对话会话(摄像头、VAD、WebSocket、消息状态、认证、场景模式)。
|
||||
|
||||
```typescript
|
||||
// useVisionSession 核心职责(简化示意)
|
||||
function useVisionSession() {
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const wsRef = useWebSocket(`${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws`);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const { captureFrame } = useCamera(videoRef);
|
||||
// 组合:useCamera + useMicrophone + useVAD + useWebSocketManager + useObservationMode
|
||||
// 管理:消息状态、流式回复、处理标志、配置、统计、模式
|
||||
|
||||
const { isSpeaking } = useVAD({
|
||||
onSpeechEnd: async (audio) => {
|
||||
const frame = captureFrame();
|
||||
wsRef.current?.send(JSON.stringify({
|
||||
type: "query",
|
||||
image: frame.toDataURL("image/jpeg", 0.7),
|
||||
audio: encodeAudio(audio)
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
wsRef.current?.on("message", (data) => {
|
||||
const { text, audio } = JSON.parse(data);
|
||||
setMessages(prev => [...prev, { role: "assistant", text }]);
|
||||
if (audio) playAudio(audio);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return { messages, videoRef, isSpeaking };
|
||||
// VAD onSpeechEnd: 捕获帧 + 音频 → 发送 query 消息
|
||||
// 服务端消息处理:stt_result / llm_chunk / llm_done / tts_audio / error
|
||||
// 文本输入:sendTextMessage() 支持手动输入文字(跳过 STT)
|
||||
// 场景模式:config 消息支持 scenario 字段(free_chat / interviewer / english_teacher 等)
|
||||
// 打断:interrupt() 发送中断消息 + 停止 TTS + 保存部分回复
|
||||
// 认证:WebSocket 连接携带 JWT token,支持 conversation_id 恢复历史对话
|
||||
}
|
||||
```
|
||||
|
||||
@@ -158,40 +148,52 @@ function useVisionSession() {
|
||||
|
||||
| 阶段 | 存储方案 | 持久化内容 | 理由 |
|
||||
|------|---------|-----------|------|
|
||||
| MVP | Memory(进程内) | 无 | 快速验证核心功能,重启丢数据可接受。Redis 实现已就绪,可通过 `storage.driver` 配置切换 |
|
||||
| 上线 | Redis + PostgreSQL | 对话历史、用户偏好、用量统计 | 用户需要查看历史,运营需要成本数据 |
|
||||
| 规模化 | Redis + PG + 对象存储 | 图像帧、音频片段归档 | 大文件不适合存关系库 |
|
||||
| 当前默认 | Memory(进程内) | 会话状态 + 对话历史 | 零依赖,快速启动。MemoryManager 支持 Write-Through 到 PG |
|
||||
| 已实现 | Memory + PostgreSQL | 用户数据、对话历史、会话元数据 | 通过 `storage.driver: postgres` 启用,MemoryManager 注入 PG Repository |
|
||||
| 已实现 | Redis(独立) | 会话状态 + 对话历史 | 通过配置切换到 RedisManager,适合多实例部署 |
|
||||
|
||||
冷热分离:Redis 存"热数据"(当前对话上下文,微秒级读写),PostgreSQL 存"冷数据"(历史记录)。
|
||||
冷热分离:Redis/Memory 存"热数据"(当前对话上下文,微秒级读写),PostgreSQL 存"冷数据"(历史记录)。MemoryManager 的 Write-Through 机制确保每次 AppendMessage 同时写入 PG,重启后可从 PG 恢复会话。
|
||||
|
||||
### PostgreSQL 表设计
|
||||
### PostgreSQL 表设计(已实现)
|
||||
|
||||
实际迁移文件位于 `backend/migrations/`,通过 `go:embed` 嵌入,启动时自动执行:
|
||||
|
||||
```sql
|
||||
CREATE TABLE sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
-- 001_users.up.sql
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(64) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(256) NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE refresh_tokens (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash VARCHAR(256) NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
-- 002_messages.up.sql
|
||||
CREATE TABLE messages (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
session_id UUID REFERENCES sessions(id),
|
||||
role VARCHAR(16) NOT NULL, -- "user" | "assistant"
|
||||
session_id UUID NOT NULL,
|
||||
role VARCHAR(16) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
image_url TEXT,
|
||||
tokens_used INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE usage_daily (
|
||||
user_id UUID NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
llm_tokens BIGINT DEFAULT 0,
|
||||
stt_seconds REAL DEFAULT 0,
|
||||
tts_chars INTEGER DEFAULT 0,
|
||||
estimated_cost NUMERIC(10,4) DEFAULT 0,
|
||||
PRIMARY KEY (user_id, date)
|
||||
-- 003_sessions.up.sql
|
||||
CREATE TABLE sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
title VARCHAR(128) DEFAULT '新对话',
|
||||
config JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user