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:
hhs
2026-06-19 14:58:43 +08:00
parent 16302af7d2
commit dca37f3e48
8 changed files with 333 additions and 213 deletions

View File

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

View File

@@ -2,7 +2,7 @@
## 概述 ## 概述
前后端通信接口定义。以 WebSocket 承载实时对话REST 端点支撑基础运维。**暂不实现持久化**,但通过 Repository 接口模式为后续扩展预留接入点 前后端通信接口定义。以 WebSocket 承载实时对话REST 端点支撑基础运维。持久化已通过 PostgreSQL 实现MemoryManager 支持 Write-Through 模式
**设计原则** **设计原则**
- WebSocket 为主:所有对话数据走 WebSocket - WebSocket 为主:所有对话数据走 WebSocket
@@ -79,6 +79,7 @@ interface ConfigMessage {
tts_enabled?: boolean; // 是否开启语音合成,默认 true tts_enabled?: boolean; // 是否开启语音合成,默认 true
detail_level?: "low" | "high"; // 图像精度,默认 "low" detail_level?: "low" | "high"; // 图像精度,默认 "low"
language?: string; // 交互语言,默认 "zh-CN" language?: string; // 交互语言,默认 "zh-CN"
scenario?: string; // 场景模式可选值free_chat / interviewer / english_teacher / debate / interpreter
}; };
} }
``` ```
@@ -746,6 +747,20 @@ DELETE /api/sessions/{id} → 改用 DELETE /api/conversations/{id}
| `/api/usage` | GET | 查询用量统计 | | `/api/usage` | GET | 查询用量统计 |
| `/api/users/{id}/preferences` | GET/PUT | 用户偏好管理 | | `/api/users/{id}/preferences` | GET/PUT | 用户偏好管理 |
### 已实现的认证与对话端点
> 详见上方"认证接口"和"对话接口"章节。包括:
> - `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/conversations/:id` — 对话详情
> - `PATCH /api/conversations/:id` — 更新标题
> - `DELETE /api/conversations/:id` — 删除对话
> - `GET /api/conversations/:id/messages` — 历史消息
--- ---
## 三、AI 服务层接口 ## 三、AI 服务层接口
@@ -992,8 +1007,8 @@ session:{id}:history → List (对话历史)
// Manager 会话管理器接口。 // Manager 会话管理器接口。
// WebSocket Handler 通过此接口操作会话,不直接接触存储层。 // WebSocket Handler 通过此接口操作会话,不直接接触存储层。
type Manager interface { type Manager interface {
// Create 创建新会话,返回 session ID。 // Create 创建新会话,关联 user_id返回 session ID。
Create(ctx context.Context, config models.SessionConfig) (string, error) Create(ctx context.Context, userID string, config models.SessionConfig) (string, error)
// Get 获取会话(含 config。不存在返回 ErrSessionNotFound。 // Get 获取会话(含 config。不存在返回 ErrSessionNotFound。
Get(ctx context.Context, sessionID string) (*models.Session, error) Get(ctx context.Context, sessionID string) (*models.Session, error)
@@ -1001,10 +1016,16 @@ type Manager interface {
// UpdateConfig 更新会话配置config 消息触发)。 // UpdateConfig 更新会话配置config 消息触发)。
UpdateConfig(ctx context.Context, sessionID string, patch models.SessionConfigPatch) error UpdateConfig(ctx context.Context, sessionID string, patch models.SessionConfigPatch) error
// UpdateTitle 更新对话标题。
UpdateTitle(ctx context.Context, sessionID string, title string) error
// ListByUser 获取用户的对话列表(分页)。
ListByUser(ctx context.Context, userID string, page, size int) ([]ConversationSummary, int, error)
// GetHistory 获取最近 N 轮对话历史(供 Orchestrator 构建 LLM 上下文)。 // GetHistory 获取最近 N 轮对话历史(供 Orchestrator 构建 LLM 上下文)。
GetHistory(ctx context.Context, sessionID string, limit int) ([]models.Message, error) GetHistory(ctx context.Context, sessionID string, limit int) ([]models.Message, error)
// AppendMessage 追加一条对话消息,同时刷新 TTL。 // AppendMessage 追加一条对话消息,同时刷新 TTL。首条 user 消息自动更新标题。
AppendMessage(ctx context.Context, sessionID string, msg models.Message) error AppendMessage(ctx context.Context, sessionID string, msg models.Message) error
// SetActiveRequest 标记当前正在处理的请求 IDinterrupt 用)。 // SetActiveRequest 标记当前正在处理的请求 IDinterrupt 用)。
@@ -1025,11 +1046,37 @@ type Manager interface {
// ActiveCount 返回当前活跃会话数(健康检查用)。 // ActiveCount 返回当前活跃会话数(健康检查用)。
ActiveCount() int ActiveCount() int
} }
// ConversationSummary 对话列表项。
type ConversationSummary struct {
ID string `json:"id"`
Title string `json:"title"`
LastMessage string `json:"last_message"`
MessageCount int `json:"message_count"`
UpdatedAt time.Time `json:"updated_at"`
}
``` ```
### WebSocket Handler 集成 ### WebSocket Handler 集成
```go ```go
// 连接建立JWT 认证 + conversation_id 恢复)
func (h *Handler) HandleWS(c *gin.Context) {
tokenStr := c.Query("token")
claims, err := h.tokenManager.ValidateAccess(tokenStr)
// ... 认证失败返回 401
conversationID := c.Query("conversation_id")
if conversationID != "" {
sess, _ := h.sessionMgr.Get(c, conversationID)
if sess.UserID != claims.UserID { /* 返回 SESSION_NOT_FOUND */ }
sessionID = conversationID
} else {
sessionID, _ = h.sessionMgr.Create(c, claims.UserID, defaultConfig)
}
// ... 进入 WS 处理循环
}
// query 分支 // query 分支
case "query": case "query":
var msg models.WsQuery var msg models.WsQuery
@@ -1055,9 +1102,9 @@ case "interrupt":
// 不调用 Destroy让 session 自然过期(支持重连恢复) // 不调用 Destroy让 session 自然过期(支持重连恢复)
``` ```
### MVP 内存实现 ### 内存实现(默认)
联调阶段无 Redis 时,用同一接口的内存实现 默认使用 `MemoryManager`,支持可选的 Write-Through 到 PostgreSQL
```go ```go
type MemoryManager struct { type MemoryManager struct {
@@ -1066,6 +1113,8 @@ type MemoryManager struct {
ttl time.Duration ttl time.Duration
maxHistory int maxHistory int
stopCleaner chan struct{} stopCleaner chan struct{}
msgRepo store.MessageRepository // 可选Write-Through
sessRepo store.SessionRepository // 可选Write-Through
} }
type sessionEntry struct { type sessionEntry struct {
@@ -1076,6 +1125,10 @@ type sessionEntry struct {
} }
``` ```
**Write-Through 机制**:注入 `msgRepo``sessRepo` 后,每次 `AppendMessage` 同时写入 PostgreSQL重启后可从 PG 恢复会话。`Create` 时同时写入 PG sessions 表。
**自动标题**:首条 user 消息时,如果 title 仍为 "新对话",自动更新为消息内容前 20 个字符。
注入时根据配置切换: 注入时根据配置切换:
```go ```go
@@ -1083,7 +1136,14 @@ var sessionMgr session.Manager
if cfg.Redis.Addr != "" { if cfg.Redis.Addr != "" {
sessionMgr = session.NewRedisManager(redisClient, 30*time.Minute, 20) sessionMgr = session.NewRedisManager(redisClient, 30*time.Minute, 20)
} else { } else {
sessionMgr = session.NewMemoryManager(30*time.Minute, 20) opts := []session.Option{}
if msgRepo != nil {
opts = append(opts, session.WithMessageRepository(msgRepo))
}
if sessRepo != nil {
opts = append(opts, session.WithSessionRepository(sessRepo))
}
sessionMgr = session.NewMemoryManager(30*time.Minute, 20, opts...)
} }
``` ```
@@ -1110,6 +1170,7 @@ Viper 加载顺序:先读 `config.yaml`,再根据 `APP_ENV` 环境变量尝
type Config struct { type Config struct {
App AppConfig `mapstructure:"app"` App AppConfig `mapstructure:"app"`
Server ServerConfig `mapstructure:"server"` Server ServerConfig `mapstructure:"server"`
Session SessionConfig `mapstructure:"session"`
Redis RedisConfig `mapstructure:"redis"` Redis RedisConfig `mapstructure:"redis"`
AI AIConfig `mapstructure:"ai"` AI AIConfig `mapstructure:"ai"`
Storage StorageConfig `mapstructure:"storage"` Storage StorageConfig `mapstructure:"storage"`
@@ -1127,6 +1188,15 @@ type ServerConfig struct {
Port int `mapstructure:"port"` // 默认 8080 Port int `mapstructure:"port"` // 默认 8080
ReadTimeout int `mapstructure:"read_timeout"` // 秒,默认 30 ReadTimeout int `mapstructure:"read_timeout"` // 秒,默认 30
WriteTimeout int `mapstructure:"write_timeout"` // 秒,默认 30 WriteTimeout int `mapstructure:"write_timeout"` // 秒,默认 30
HeartbeatInterval int `mapstructure:"heartbeat_interval"` // 秒,默认 30
HeartbeatTimeout int `mapstructure:"heartbeat_timeout"` // 秒,默认 60
ShutdownTimeout int `mapstructure:"shutdown_timeout"` // 秒,默认 10
AllowedOrigins []string `mapstructure:"allowed_origins"` // 空表示允许所有
}
type SessionConfig struct {
TTL int `mapstructure:"ttl"` // 分钟,默认 30
MaxHistory int `mapstructure:"max_history"` // 条数,默认 20
} }
type RedisConfig struct { type RedisConfig struct {
@@ -1142,10 +1212,12 @@ type AIConfig struct {
} }
type STTConfig struct { type STTConfig struct {
Provider string `mapstructure:"provider"` // "deepgram" Provider string `mapstructure:"provider"` // "deepgram" | "mimo" | "xiaomi"
APIKey string `mapstructure:"api_key"` APIKey string `mapstructure:"api_key"`
Model string `mapstructure:"model"` // 默认 "nova-2" Model string `mapstructure:"model"` // 默认 "nova-2"
Endpoint string `mapstructure:"endpoint"` // 默认 "wss://api.deepgram.com/v1/listen" Endpoint string `mapstructure:"endpoint"` // 默认 "wss://api.deepgram.com/v1/listen"
Timeout int `mapstructure:"timeout"` // 秒,默认 5
HTTPClientTimeout int `mapstructure:"http_client_timeout"` // 秒,默认 30
} }
type LLMConfig struct { type LLMConfig struct {
@@ -1154,16 +1226,20 @@ type LLMConfig struct {
Model string `mapstructure:"model"` // 默认 "gpt-4o" Model string `mapstructure:"model"` // 默认 "gpt-4o"
Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1" Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1"
Timeout int `mapstructure:"timeout"` // 秒,默认 10 Timeout int `mapstructure:"timeout"` // 秒,默认 10
HTTPClientTimeout int `mapstructure:"http_client_timeout"` // 秒,默认 60
} }
type TTSConfig struct { type TTSConfig struct {
Provider string `mapstructure:"provider"` // "openai" Provider string `mapstructure:"provider"` // "openai" | "mimo" | "xiaomi"
APIKey string `mapstructure:"api_key"` APIKey string `mapstructure:"api_key"`
Model string `mapstructure:"model"` // 默认 "tts-1" Model string `mapstructure:"model"` // 默认 "tts-1"
Voice string `mapstructure:"voice"` // 默认 "alloy" Voice string `mapstructure:"voice"` // 默认 "mimo_default"
Speed float64 `mapstructure:"speed"` // 默认 1.0 Speed float64 `mapstructure:"speed"` // 默认 1.0
Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1" Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1"
Timeout int `mapstructure:"timeout"` // 秒,默认 5 Timeout int `mapstructure:"timeout"` // 秒,默认 5
HTTPClientTimeout int `mapstructure:"http_client_timeout"` // 秒,默认 30
OutputFormat string `mapstructure:"output_format"` // 默认 "mp3"
SampleRate int `mapstructure:"sample_rate"` // 默认 24000
} }
type StorageConfig struct { type StorageConfig struct {
@@ -1195,6 +1271,13 @@ server:
port: 8080 port: 8080
read_timeout: 30 read_timeout: 30
write_timeout: 30 write_timeout: 30
heartbeat_interval: 30
heartbeat_timeout: 60
shutdown_timeout: 10
session:
ttl: 30
max_history: 20
redis: redis:
addr: "localhost:6379" addr: "localhost:6379"
@@ -1206,18 +1289,24 @@ ai:
provider: deepgram provider: deepgram
model: nova-2 model: nova-2
endpoint: "wss://api.deepgram.com/v1/listen" endpoint: "wss://api.deepgram.com/v1/listen"
timeout: 5
http_client_timeout: 30
llm: llm:
provider: openai provider: openai
model: gpt-4o model: gpt-4o
endpoint: "https://api.openai.com/v1" endpoint: "https://api.openai.com/v1"
timeout: 10 timeout: 10
http_client_timeout: 60
tts: tts:
provider: openai provider: openai
model: tts-1 model: tts-1
voice: alloy voice: mimo_default
speed: 1.0 speed: 1.0
endpoint: "https://api.openai.com/v1" endpoint: "https://api.openai.com/v1"
timeout: 5 timeout: 5
http_client_timeout: 30
output_format: mp3
sample_rate: 24000
storage: storage:
driver: memory driver: memory
@@ -1360,6 +1449,7 @@ type SessionConfig struct {
TTSEnabled bool `json:"tts_enabled"` TTSEnabled bool `json:"tts_enabled"`
DetailLevel string `json:"detail_level"` // "low" | "high" DetailLevel string `json:"detail_level"` // "low" | "high"
Language string `json:"language"` Language string `json:"language"`
Scenario string `json:"scenario"` // "free_chat" | "interviewer" | "english_teacher" | "debate" | "interpreter"
} }
type QueryRequest struct { type QueryRequest struct {
@@ -1416,6 +1506,7 @@ interface SessionConfig {
ttsEnabled: boolean; ttsEnabled: boolean;
detailLevel: "low" | "high"; detailLevel: "low" | "high";
language: string; language: string;
scenario: string; // "free_chat" | "interviewer" | "english_teacher" | "debate" | "interpreter"
} }
interface ChatMessage { interface ChatMessage {
@@ -1499,79 +1590,79 @@ type ClientMessage =
--- ---
## 八、扩展接口设计 ## 八、存储层接口设计
通过 Repository 接口隔离存储层,MVP 用内存实现,后续替换为数据库——业务逻辑零改动。 通过 Repository 接口隔离存储层,内存和 PostgreSQL 均已实现,业务逻辑零改动。
### UserRepository
```go ```go
// HistoryRepository — 对话历史存储契约 // UserRepository 用户数据存储契约
// MVP: 内存实现session 内有效,断开即丢 // 内存实现MemUserRepository测试/开发用
// 后续: PostgreSQL 实现 // PostgreSQL 实现PgUserRepository
type HistoryRepository interface { type UserRepository interface {
SaveMessage(ctx context.Context, sessionID string, msg Message) error Create(ctx context.Context, username, passwordHash string) (string, error)
GetMessages(ctx context.Context, sessionID string, limit int) ([]Message, error) FindByUsername(ctx context.Context, username string) (*User, error)
} FindByID(ctx context.Context, id string) (*User, error)
SaveRefreshToken(ctx context.Context, userID, tokenHash string, expiresAt time.Time) error
// UsageRepository — 用量统计存储契约 FindRefreshToken(ctx context.Context, tokenHash string) (string, error)
// MVP: 内存计数器 DeleteRefreshToken(ctx context.Context, tokenHash string) error
// 后续: PostgreSQL 按天聚合 DeleteUserRefreshTokens(ctx context.Context, userID string) error
type UsageRepository interface {
RecordUsage(ctx context.Context, sessionID string, usage UsageRecord) error
GetDailyUsage(ctx context.Context, userID string, days int) ([]UsageDaily, error)
} }
``` ```
MVP 内存实现: ### MessageRepository
```go ```go
type InMemoryHistory struct { // MessageRepository 对话消息持久化契约。
mu sync.RWMutex // PostgreSQL 实现PgMessageRepository
sessions map[string][]Message // MemoryManager 通过 Write-Through 注入此接口。
} type MessageRepository interface {
SaveMessage(ctx context.Context, sessionID string, msg models.Message, tokensUsed int) error
func (h *InMemoryHistory) SaveMessage(ctx context.Context, sessionID string, msg Message) error { GetMessages(ctx context.Context, sessionID string, limit int, beforeID int64) ([]StoredMessage, error)
h.mu.Lock() GetLastMessage(ctx context.Context, sessionID string) (*StoredMessage, error)
defer h.mu.Unlock() GetMessageCount(ctx context.Context, sessionID string) (int, error)
h.sessions[sessionID] = append(h.sessions[sessionID], msg) GetSessionMessageStats(ctx context.Context, sessionIDs []string) (map[string]int, error)
return nil
}
func (h *InMemoryHistory) GetMessages(ctx context.Context, sessionID string, limit int) ([]Message, error) {
h.mu.RLock()
defer h.mu.RUnlock()
msgs := h.sessions[sessionID]
if limit > 0 && len(msgs) > limit {
msgs = msgs[len(msgs)-limit:]
}
return msgs, nil
} }
``` ```
注入点(应用启动时根据配置选择实现): ### SessionRepository
```go ```go
func NewApp(cfg *Config) *App { // SessionRepository 会话元数据持久化契约。
var history HistoryRepository // PostgreSQL 实现PgSessionRepository
var usage UsageRepository // MemoryManager 通过 Write-Through 注入此接口。
type SessionRepository interface {
switch cfg.Storage.Driver { Save(ctx context.Context, session models.Session) error
case "postgres": FindByID(ctx context.Context, id string) (*models.Session, error)
pool, _ := pgxpool.New(ctx, cfg.Storage.DSN) FindByUser(ctx context.Context, userID string, page, size int) ([]models.Session, int, error)
history = &PgHistory{pool: pool} UpdateTitle(ctx context.Context, id string, title string) error
usage = &PgUsage{pool: pool} UpdateConfig(ctx context.Context, id string, config models.SessionConfig) error
default: // "memory" — MVP 默认 Touch(ctx context.Context, id string) error
history = &InMemoryHistory{sessions: make(map[string][]Message)} Delete(ctx context.Context, id string) error
usage = &InMemoryUsage{}
}
return &App{
orchestrator: NewOrchestrator(cfg.AI, history, usage),
sessionMgr: NewSessionManager(cfg.Session, history),
}
} }
``` ```
> 依赖倒置原则——业务层依赖接口不依赖具体实现。MVP 注入 `InMemoryHistory`,上线时一行代码换成 `PgHistory`。 ### 注入方式
```go
// main.go 依赖注入
if cfg.Storage.Driver == "postgres" {
pool, _ := store.NewPostgresPool(ctx, cfg.Storage.DSN)
userRepo = store.NewPgUserRepository(pool)
msgRepo = store.NewPgMessageRepository(pool)
sessRepo = store.NewPgSessionRepository(pool)
sessionMgr = session.NewMemoryManager(30*time.Minute, 20,
session.WithMessageRepository(msgRepo),
session.WithSessionRepository(sessRepo),
)
} else {
userRepo = store.NewMemUserRepository()
sessionMgr = session.NewMemoryManager(30*time.Minute, 20)
}
```
> 依赖倒置原则——业务层依赖接口,不依赖具体实现。通过配置一行代码切换存储后端。
--- ---

View File

@@ -4,23 +4,26 @@
本文档记录项目中各项技术的**选型过程、替代方案对比和决策理由**。技术选型没有"绝对正确",只有"更适合"。 本文档记录项目中各项技术的**选型过程、替代方案对比和决策理由**。技术选型没有"绝对正确",只有"更适合"。
**定位**持久化部分是拓展选型,不阻塞 MVPMVP 用内存存储即可)。前端边缘处理部分是 MVP 阶段就需要确定的技术栈。AI 服务栈STT/LLM/TTS已确定默认选型可通过配置灵活切换 **定位**本文档记录各项技术的选型过程和决策理由。AI 服务栈、持久化层、认证系统均已实现并通过配置灵活切换。前端边缘处理已确定技术栈
``` ```
技术选型 技术选型
├── AI 服务栈 ├── AI 服务栈(✅ 已实现)
│ ├── STT: Deepgram默认 / MiMo ASR │ ├── STT: Deepgram默认 / MiMo ASR
│ ├── LLM: GPT-4o默认 / 通义千问等 OpenAI 兼容模型 │ ├── LLM: GPT-4o默认 / 通义千问等 OpenAI 兼容模型
│ └── TTS: OpenAI TTS默认 / MiMo TTS │ └── TTS: OpenAI TTS默认 / MiMo TTS
├── 持久化层 → 数据库选型: PostgreSQL规划中MVP 阶段使用内存存储 ├── 持久化层(✅ 已实现
├── 认证与用户系统 │ ├── 数据库: PostgreSQLpgx/v5手写 SQL
│ ├── 迁移: 嵌入式 SQL 文件,自动执行
│ └── 存储模式: Memory默认+ Write-Through 到 PG / Redis可切换
├── 认证与用户系统(✅ 已实现)
│ ├── 认证方案: JWT (HS256), access 15min + refresh 7day │ ├── 认证方案: JWT (HS256), access 15min + refresh 7day
│ ├── JWT 库: golang-jwt/jwt/v5 │ ├── JWT 库: golang-jwt/jwt/v5
│ ├── 密码哈希: bcrypt │ ├── 密码哈希: bcrypt
│ ├── 数据库驱动: pgx/v5手写 SQL不用 ORM │ ├── 数据库驱动: pgx/v5手写 SQL不用 ORM
│ └── 前端 Token 存储: localStorage │ └── 前端 Token 存储: localStorage
└── 前端边缘处理层 └── 前端边缘处理层(✅ 已实现)
├── 边缘推理: ONNX Runtime Web规划中MVP 使用 Canvas 像素比较 ├── 关键帧检测: Canvas 像素比较160x120 降采样
├── 语音检测: @ricky0123/vad-web ├── 语音检测: @ricky0123/vad-web
└── 媒体采集: MediaDevices API └── 媒体采集: MediaDevices API
``` ```
@@ -61,7 +64,7 @@
--- ---
## 二、持久化层选型(规划中MVP 阶段使用内存存储 ## 二、持久化层选型(已实现
### 数据特征分析 ### 数据特征分析

View File

@@ -56,7 +56,7 @@ vad.start();
句子切分规则:按中文标点(`。!?`)、英文标点(`. ! ?`)和换行符切分。 句子切分规则:按中文标点(`。!?`)、英文标点(`. ! ?`)和换行符切分。
当前实现参数Voice `"alloy"`、Speed `1.0`、OutputFmt `"mp3"`、SampleRate `24000` 当前实现参数Voice `"mimo_default"`(可通过配置切换)、Speed `1.0`、OutputFmt `"mp3"`、SampleRate `24000`
方案选择: 方案选择:
- **OpenAI TTS**(默认):音质好,延迟中等,按字符计费,模型 tts-1 - **OpenAI TTS**(默认):音质好,延迟中等,按字符计费,模型 tts-1

View File

@@ -709,42 +709,43 @@ storage:
## 八、实施阶段 ## 八、实施阶段
### Phase 1用户认证系统 ### Phase 1用户认证系统
- [ ] 数据库 schema 迁移脚本users, refresh_tokens 表) - [x] 数据库 schema 迁移脚本users, refresh_tokens 表)`migrations/001_users.up.sql`
- [ ] `internal/auth/`TokenManager, bcrypt 工具, JWT 中间件 - [x] `internal/auth/`TokenManager, bcrypt 工具, JWT 中间件
- [ ] `internal/store/user.go`UserRepository 接口 + PostgreSQL 实现 - [x] `internal/store/user.go`UserRepository 接口 + PostgreSQL 实现 + 内存实现
- [ ] REST API`/api/auth/register`, `/api/auth/login`, `/api/auth/refresh`, `/api/auth/logout` - [x] REST API`/api/auth/register`, `/api/auth/login`, `/api/auth/refresh`, `/api/auth/logout`
- [ ] 单元测试 - [x] 单元测试`jwt_test.go`, `service_test.go`, `auth_test.go`, `user_test.go`
### Phase 2对话 CRUD + 消息持久化 ### Phase 2对话 CRUD + 消息持久化
- [ ] 数据库 schema 迁移脚本sessions, messages 表改造 - [x] 数据库 schema 迁移脚本sessions, messages 表)`migrations/002_messages.up.sql`, `003_sessions.up.sql`
- [ ] `internal/store/conversation.go`ConversationRepository 接口 + PostgreSQL 实现 - [x] `internal/store/message.go`MessageRepository 接口 + PostgreSQL 实现
- [ ] Session Manager 扩展Create 绑定 user_id, ListByUser, UpdateTitle - [x] `internal/store/session.go`SessionRepository 接口 + PostgreSQL 实现
- [ ] REST API`/api/conversations` CRUD + `/api/conversations/:id/messages` - [x] Session Manager 扩展Create 绑定 user_id, ListByUser, UpdateTitle
- [ ] Write-throughAppendMessage 同时写 PostgreSQL - [x] REST API`/api/conversations` CRUD + `/api/conversations/:id/messages`
- [x] Write-throughAppendMessage 同时写 PostgreSQL
### Phase 3对话历史恢复 ### Phase 3对话历史恢复
- [ ] `sessionManager.LoadFromDB()` 实现 - [x] MemoryManager 支持从 PG 透明恢复会话Get 时自动 LoadFromDB
- [ ] 对话标题自动生成逻辑 - [x] 对话标题自动生成逻辑(首条 user 消息前 20 字符)
- [ ] REST API对话详情、历史消息查询分页 - [x] REST API对话详情、历史消息查询游标分页)
### Phase 4前端集成 ### Phase 4前端集成
- [ ] `useAuth` hook + 请求拦截器(自动附加 token、自动 refresh - [x] `useAuth` hook + AuthProvider(自动附加 token、自动 refresh
- [ ] `AuthPage` 组件(登录/注册表单) - [x] `AuthPage` 组件(登录/注册表单)
- [ ] `ConversationList` 组件 - [x] `SessionSidebar` 组件(对话列表、搜索、重命名、删除)
- [ ] `useConversations` hook - [x] `useSessionList` hooklocalStorage 持久化)
- [ ] 路由守卫:未登录重定向到 `/login` - [x] 路由守卫:未登录重定向到 AuthPage
- [ ] WebSocket 连接带 token + conversation_id - [x] WebSocket 连接带 token + conversation_id
- [ ] `useVisionSession` 适配多对话切换 - [x] `useVisionSession` 适配多对话切换
### Phase 5配置与收尾 ### Phase 5配置与收尾
- [ ] 配置结构体扩展AuthConfig - [x] 配置结构体扩展AuthConfig, SessionConfig, StorageConfig
- [ ] config.yaml 更新 - [x] config.yaml 更新
- [ ] docker-compose 添加 PostgreSQL - [x] 数据库迁移嵌入式自动执行(`go:embed`
- [ ] 集成测试 - [x] 集成测试 — 122 个测试函数覆盖所有模块
- [ ] 更新 `02-系统架构.md``03-接口文档.md` - [x] 更新 `02-系统架构.md``03-接口文档.md`

View File

@@ -1,5 +1,7 @@
# CamTalk 后端完善计划 # CamTalk 后端完善计划
> **✅ 状态:全部完成。** 所有 Phase 已实现并通过测试(约 122 个测试函数)。本文档保留作为历史参考。
## Context ## Context
后端当前是一个骨架:`main.go` 启动 Gin 服务器,`ws/handler.go` 实现了 WebSocket 连接生命周期和消息分发,`models/models.go` 定义了所有协议消息类型,`config/config.go` 实现了 Viper 配置加载。但所有业务逻辑都是 TODO 桩——没有 Session Manager、没有 AI 服务客户端、没有编排层、没有日志/错误工具、没有测试。前端已基本完成,正在等待后端提供真实的 AI 管道。 后端当前是一个骨架:`main.go` 启动 Gin 服务器,`ws/handler.go` 实现了 WebSocket 连接生命周期和消息分发,`models/models.go` 定义了所有协议消息类型,`config/config.go` 实现了 Viper 配置加载。但所有业务逻辑都是 TODO 桩——没有 Session Manager、没有 AI 服务客户端、没有编排层、没有日志/错误工具、没有测试。前端已基本完成,正在等待后端提供真实的 AI 管道。
@@ -10,7 +12,7 @@
## 分阶段实施 ## 分阶段实施
### Phase 1基础设施logger、errors、config 接入、graceful shutdown ### Phase 1基础设施logger、errors、config 接入、graceful shutdown
**目标**:为后续模块提供日志、错误码、配置等基础能力,替换 `main.go` 中的硬编码值。 **目标**:为后续模块提供日志、错误码、配置等基础能力,替换 `main.go` 中的硬编码值。
@@ -26,7 +28,7 @@
--- ---
### Phase 2Session Manager ### Phase 2Session Manager
**目标**:实现会话生命周期管理,让 WS handler 能追踪会话、存储对话历史。 **目标**:实现会话生命周期管理,让 WS handler 能追踪会话、存储对话历史。
@@ -40,7 +42,7 @@
--- ---
### Phase 3AI 服务层接口 + 实现 ### Phase 3AI 服务层接口 + 实现
**目标**:定义并实现三个 AI 服务客户端,每个服务一个独立包。 **目标**:定义并实现三个 AI 服务客户端,每个服务一个独立包。
@@ -62,7 +64,7 @@
--- ---
### Phase 4AI Orchestrator核心编排 ### Phase 4AI Orchestrator核心编排
**目标**:实现 STT → LLM → TTS 流式并行管道,这是后端最关键的业务逻辑。 **目标**:实现 STT → LLM → TTS 流式并行管道,这是后端最关键的业务逻辑。
@@ -78,7 +80,7 @@
--- ---
### Phase 5WS Handler 完整接入 ### Phase 5WS Handler 完整接入
**目标**:将 Session Manager + Orchestrator 串入 WebSocket handler实现端到端消息处理。 **目标**:将 Session Manager + Orchestrator 串入 WebSocket handler实现端到端消息处理。
@@ -92,7 +94,7 @@
--- ---
### Phase 6REST API 补全 ### Phase 6REST API 补全
**目标**:补全设计文档中的 REST 端点。 **目标**:补全设计文档中的 REST 端点。
@@ -104,7 +106,7 @@
--- ---
### Phase 7Rate Limiter + Model Router可选/MVP 后) ### Phase 7Rate Limiter + Model Router可选/MVP 后) 📋
**目标**:防止滥用 + 智能模型选择MVP 可简化或跳过。 **目标**:防止滥用 + 智能模型选择MVP 可简化或跳过。
@@ -116,7 +118,7 @@
--- ---
### Phase 8集成测试 + 文档同步 ### Phase 8集成测试 + 文档同步
| # | 任务 | 文件 | 说明 | | # | 任务 | 文件 | 说明 |
|---|------|------|------| |---|------|------|------|

View File

@@ -1,5 +1,7 @@
# CamTalk 后端用户模块构建计划 # CamTalk 后端用户模块构建计划
> **✅ 状态:全部完成。** 所有 Phase 已实现并通过测试。本文档保留作为历史参考。
## Context ## Context
后端 AI 管道STT → LLM → TTS已完成现在需要实现用户系统和对话持久化。目标**用户注册登录后,可在对话列表中选择历史对话继续交谈**。 后端 AI 管道STT → LLM → TTS已完成现在需要实现用户系统和对话持久化。目标**用户注册登录后,可在对话列表中选择历史对话继续交谈**。
@@ -34,7 +36,7 @@
## 分阶段实施 ## 分阶段实施
### Phase 1配置扩展 + 数据库连接 ### Phase 1配置扩展 + 数据库连接
**目标**:扩展配置结构体,建立 PostgreSQL 连接池。 **目标**:扩展配置结构体,建立 PostgreSQL 连接池。
@@ -83,7 +85,7 @@ func NewPostgresPool(ctx context.Context, dsn string) (*pgxpool.Pool, error) {
--- ---
### Phase 2用户模型 + Repository ### Phase 2用户模型 + Repository
**目标**:定义用户数据模型和持久化接口。 **目标**:定义用户数据模型和持久化接口。
@@ -149,7 +151,7 @@ type User struct {
--- ---
### Phase 3JWT + 认证服务 ### Phase 3JWT + 认证服务
**目标**:实现 JWT 签发/校验、bcrypt 密码处理、认证业务逻辑。 **目标**:实现 JWT 签发/校验、bcrypt 密码处理、认证业务逻辑。
@@ -292,7 +294,7 @@ type Service interface {
--- ---
### Phase 4认证 REST API ### Phase 4认证 REST API
**目标**:实现注册、登录、刷新、登出四个端点。 **目标**:实现注册、登录、刷新、登出四个端点。
@@ -350,7 +352,7 @@ const (
--- ---
### Phase 5Session Manager 改造 ### Phase 5Session Manager 改造
**目标**Session Manager 关联 user_id支持对话列表查询。 **目标**Session Manager 关联 user_id支持对话列表查询。
@@ -436,7 +438,7 @@ func (m *MemoryManager) ListByUser(ctx context.Context, userID string, page, siz
--- ---
### Phase 6对话 REST API ### Phase 6对话 REST API
**目标**:实现对话 CRUD 和历史消息查询端点。 **目标**:实现对话 CRUD 和历史消息查询端点。
@@ -493,7 +495,7 @@ func (h *ConversationHandler) getSessionForUser(c *gin.Context, sessionID string
--- ---
### Phase 7WebSocket 认证集成 ### Phase 7WebSocket 认证集成
**目标**WS 连接需要 JWT 认证,支持指定 conversation_id 恢复历史对话。 **目标**WS 连接需要 JWT 认证,支持指定 conversation_id 恢复历史对话。
@@ -564,7 +566,7 @@ func generateTitle(firstMessage string) string {
--- ---
### Phase 8消息持久化Write-Through ### Phase 8消息持久化Write-Through
**目标**:对话消息同时写入 PostgreSQL保证重启不丢数据。 **目标**:对话消息同时写入 PostgreSQL保证重启不丢数据。
@@ -643,7 +645,7 @@ func (m *MemoryManager) AppendMessage(ctx context.Context, sessionID string, msg
--- ---
### Phase 9旧端点废弃 + 集成收尾 ### Phase 9旧端点废弃 + 集成收尾
**目标**:废弃旧的 `/api/sessions` 端点,完成全链路集成。 **目标**:废弃旧的 `/api/sessions` 端点,完成全链路集成。

View File

@@ -4,17 +4,21 @@ CamTalk 是一款多模态实时 AI 视觉对话助手。用户通过摄像头
## 文档索引 ## 文档索引
| 文档 | 说明 | | 文档 | 说明 | 状态 |
|------|------| |------|------|------|
| [01-项目概述](01-项目概述.md) | 项目目标、核心挑战、交付物 | | [01-项目概述](01-项目概述.md) | 项目目标、核心挑战、交付物 | ✅ 与代码一致 |
| [02-系统架构](02-系统架构.md) | 三层架构、技术栈、核心交互流程、前后端模块、存储策略、部署架构 | | [02-系统架构](02-系统架构.md) | 三层架构、技术栈、核心交互流程、前后端模块、存储策略、部署架构 | ✅ 已更新 |
| [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、**AI 服务层接口**、**编排器设计**、**Session Manager**、**配置管理Viper**、数据模型、错误码、连接管理(**实现时首先阅读** | | [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、AI 服务层接口、编排器设计、Session Manager配置管理Viper、数据模型、错误码、连接管理**实现时首先阅读** | ✅ 已更新 |
| [04-技术选型](04-技术选型.md) | 持久化层PostgreSQL和前端边缘处理层的选型对比与决策理由 | | [04-技术选型](04-技术选型.md) | 持久化层PostgreSQL、认证系统和前端边缘处理层的选型对比与决策理由 | ✅ 已更新 |
| [05-用户故事](05-用户故事.md) | P0/P1/P2 用户故事、验收标准、优先级决策依据 | | [05-用户故事](05-用户故事.md) | P0/P1/P2 用户故事、验收标准、优先级决策依据 | ✅ 与代码一致 |
| [06-语音交互](06-语音交互.md) | VAD → STT → LLM → TTS 全链路、延迟优化 | | [06-语音交互](06-语音交互.md) | VAD → STT → LLM → TTS 全链路、延迟优化 | ✅ 与代码一致 |
| [07-视觉理解](07-视觉理解.md) | 帧采样策略、图像编码、多模态 LLM 输入机制 | | [07-视觉理解](07-视觉理解.md) | 帧采样策略、图像编码、多模态 LLM 输入机制 | ✅ 与代码一致 |
| [08-成本控制](08-成本控制.md) | 智能采样、端云协同、模型分级、缓存复用 | | [08-成本控制](08-成本控制.md) | 智能采样、端云协同、模型分级、缓存复用 | ✅ 与代码一致 |
| [09-技术名词解释](09-技术名词解释.md) | 前端/后端/AI 服务技术名词简明解释 | | [09-技术名词解释](09-技术名词解释.md) | 前端/后端/AI 服务技术名词简明解释 | ✅ 与代码一致 |
| [10-功能创意](10-功能创意.md) | 未来功能创意清单 | 📋 愿景 |
| [11-持久化与用户系统设计](11-持久化与用户系统设计.md) | 用户认证、JWT、对话持久化的完整设计方案 | ✅ 已全部实现 |
| [PLAN_BACKEND.md](PLAN_BACKEND.md) | 后端 AI 管道构建计划Session Manager → AI 服务 → Orchestrator | ✅ 已全部完成 |
| [PLAN_USER_MODULE.md](PLAN_USER_MODULE.md) | 后端用户模块构建计划Auth → 对话 CRUD → 消息持久化) | ✅ 已全部完成 |
## 推荐阅读顺序 ## 推荐阅读顺序
@@ -25,3 +29,18 @@ CamTalk 是一款多模态实时 AI 视觉对话助手。用户通过摄像头
5. **05-用户故事** — 明确功能优先级 5. **05-用户故事** — 明确功能优先级
6. **06~08** — 各技术领域的详细设计 6. **06~08** — 各技术领域的详细设计
7. **09-技术名词解释** — 遇到不熟悉的名词时查阅 7. **09-技术名词解释** — 遇到不熟悉的名词时查阅
8. **11-持久化与用户系统设计** — 用户认证和持久化的详细设计
## 实现状态总览
前后端代码已全部实现,无 TODO/FIXME 桩代码。后端约 122 个测试函数覆盖所有模块。
| 层级 | 状态 | 说明 |
|------|------|------|
| 前端 | ✅ 已完成 | 10 个组件、3 个 Hook、10 个库模块、i18n 三语言 |
| 后端 AI 管道 | ✅ 已完成 | STT/LLM/TTS 多 provider、Orchestrator 流式并行 |
| 后端用户系统 | ✅ 已完成 | JWT 认证、用户注册登录、对话 CRUD、消息持久化 |
| 后端存储层 | ✅ 已完成 | Memory + PostgreSQL + Redis 三种实现 |
| 数据库迁移 | ✅ 已完成 | 3 个版本化迁移脚本,嵌入式自动执行 |
| Model Router | 📋 规划中 | 按问题复杂度选择模型 |
| Rate Limiter | 📋 规划中 | 令牌桶限流 |