# 接口文档 ## 概述 前后端通信接口契约。WebSocket 承载实时对话,REST API 支撑基础运维。 **设计原则**: - WebSocket 为主:所有对话数据走 WebSocket - REST 为辅:仅用于健康检查、认证、对话管理等低频操作 - 接口先行:先定义契约,再填充实现——前后端可并行开发 ## 接口全景 ``` 浏览器 Go Gateway :8080 WebSocket Client <--> /ws?token= (实时对话,需 JWT 认证) HTTP Client --> GET /api/health (健康检查) HTTP Client <--> POST /api/auth/* (注册/登录/刷新/登出) HTTP Client <--> GET/POST/PATCH/DELETE (对话 CRUD) /api/conversations/* HTTP Client <--> GET /api/conversations/:id (历史消息) /messages ``` --- ## 一、WebSocket 协议 连接地址:`ws://localhost:8080/ws?token=&conversation_id=` | 参数 | 必填 | 说明 | |------|------|------| | `token` | 是 | JWT access_token,缺失或无效时返回 401 | | `conversation_id` | 否 | 恢复已有对话;省略则创建新对话 | ### 消息格式约定 所有 WebSocket 消息均为 JSON 文本帧,统一结构: ```typescript interface WsMessage { type: string; // 消息类型,必填 request_id?: string; // 可选,用于请求-响应关联 timestamp?: number; // 可选,毫秒时间戳 [key: string]: any; // 类型特定字段 } ``` ### 客户端 → 服务端消息 #### `query` — 发起一次视觉对话 ```typescript interface QueryMessage { type: "query"; request_id: string; // 客户端生成的 UUID image: string; // Base64 编码的 JPEG 图像(不含 data: 前缀) audio: string; // Base64 编码的音频片段(PCM 16kHz),文本输入时为空字符串 text?: string; // 用户手动输入的文本(有值时跳过 STT,直接使用此文本) mime_type?: string; // 音频格式,默认 "audio/pcm" } ``` #### `config` — 更新会话配置 ```typescript interface ConfigMessage { type: "config"; payload: { tts_enabled?: boolean; // 是否开启语音合成,默认 true detail_level?: "low" | "high"; // 图像精度,默认 "low" language?: string; // 交互语言,默认 "zh-CN" scenario?: string; // 场景模式:free_chat / interviewer / english_teacher / debate / interpreter }; } ``` #### `interrupt` — 打断当前回复 ```typescript interface InterruptMessage { type: "interrupt"; request_id?: string; // 可选,当前实现不使用此字段,服务端始终取消当前活跃请求 } ``` #### `ping` — 心跳保活 ```typescript interface PingMessage { type: "ping"; } ``` ### 服务端 → 客户端消息 #### `connected` — 连接建立确认 ```typescript interface ConnectedMessage { type: "connected"; session_id: string; conversation_id: string; config: { tts_enabled: boolean; detail_level: "low" | "high"; language: string; scenario: string; }; } ``` #### `stt_result` — 语音识别结果 ```typescript interface SttResultMessage { type: "stt_result"; request_id: string; text: string; // 识别出的文本 is_final: boolean; // 当前实现始终为 true } ``` #### `llm_chunk` — LLM 流式响应片段 ```typescript interface LlmChunkMessage { type: "llm_chunk"; request_id: string; content: string; // 当前 token 片段 } ``` #### `llm_done` — LLM 响应完成 ```typescript interface LlmDoneMessage { type: "llm_done"; request_id: string; full_text: string; // 完整响应文本 } ``` #### `tts_audio` — TTS 音频片段 音频流式推送,每个消息携带一个句子的音频数据。 ```typescript interface TtsAudioMessage { type: "tts_audio"; request_id: string; audio: string; // Base64 编码的音频数据 format: string; // 音频格式 sample_rate: number; // 采样率(Hz) sequence: number; // 句子序号,从 0 开始递增 is_final: boolean; // 是否为最后一个句子 } ``` **音频格式约束**: | 字段 | 值 | 说明 | |------|-----|------| | `format` | `"pcm"` | 线性 PCM,小端序 | | `sample_rate` | `24000` | 24kHz 采样率 | | 位深度 | 16-bit | 单声道 | | 句子划分 | 按标点符号(。!?;:)分割 | 服务端按句分割 LLM 响应,并行合成 | #### `error` — 错误通知 ```typescript interface ErrorMessage { type: "error"; request_id?: string; // 关联的请求 ID,全局错误时为空 code: string; // 错误码,见下文错误码表 message: string; // 人类可读的错误描述 details?: any; // 可选的详细错误信息 } ``` #### `pong` — 心跳响应 ```typescript interface PongMessage { type: "pong"; } ``` ### 连接管理 - **心跳机制**:客户端每 30 秒发送 `ping`,服务端回复 `pong`;60 秒无活动则服务端断开连接 - **重连策略**:客户端断线后指数退避重连(1s → 2s → 4s → ... → 最大 30s) - **并发控制**:同一连接同时只能有一个活跃的 `query` 请求;新请求到来时自动取消旧请求 --- ## 二、REST API 所有 REST 端点均使用 JSON 格式。 ### 2.1 健康检查 #### `GET /api/health` 检查服务健康状态。 **响应**: ```json { "status": "healthy", "timestamp": "2024-01-15T10:30:00Z", "dependencies": { "database": "healthy", "redis": "healthy" } } ``` ### 2.2 认证 API #### `POST /api/auth/register` — 用户注册 **请求**: ```json { "username": "alice", "email": "alice@example.com", "password": "SecurePass123!" } ``` **响应**(200 OK): ```json { "user": { "id": "550e8400-e29b-41d4-a716-446655440000", "username": "alice", "email": "alice@example.com", "created_at": "2024-01-15T10:30:00Z" }, "access_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "expires_in": 7200 } ``` **错误**: - `400 INVALID_INPUT`: 参数验证失败 - `409 USER_EXISTS`: 用户名或邮箱已存在 #### `POST /api/auth/login` — 用户登录 **请求**: ```json { "username": "alice", "password": "SecurePass123!" } ``` **响应**(200 OK): ```json { "user": { "id": "550e8400-e29b-41d4-a716-446655440000", "username": "alice", "email": "alice@example.com" }, "access_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "expires_in": 7200 } ``` **错误**: - `400 INVALID_INPUT`: 参数缺失 - `401 INVALID_CREDENTIALS`: 用户名或密码错误 #### `POST /api/auth/refresh` — 刷新 Access Token **请求头**: ``` Authorization: Bearer ``` **响应**(200 OK): ```json { "access_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "expires_in": 7200 } ``` **错误**: - `401 INVALID_TOKEN`: Refresh Token 无效或过期 #### `POST /api/auth/logout` — 用户登出 **请求头**: ``` Authorization: Bearer ``` **响应**(200 OK): ```json { "message": "Logged out successfully" } ``` ### 2.3 对话管理 API 所有端点均需 JWT 认证(`Authorization: Bearer `)。 #### `GET /api/conversations` — 获取对话列表 **查询参数**: - `page`: 页码,从 1 开始,默认 1 - `page_size`: 每页条数,默认 20,最大 100 **响应**(200 OK): ```json { "conversations": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "title": "关于植物的对话", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T11:45:00Z", "message_count": 12 } ], "total": 42, "page": 1, "page_size": 20 } ``` #### `POST /api/conversations` — 创建新对话 **请求**: ```json { "title": "新的对话" } ``` **响应**(201 Created): ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "title": "新的对话", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "message_count": 0 } ``` #### `GET /api/conversations/:id` — 获取对话详情 **响应**(200 OK): ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "title": "关于植物的对话", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T11:45:00Z", "message_count": 12 } ``` **错误**: - `404 NOT_FOUND`: 对话不存在或无权访问 #### `PATCH /api/conversations/:id` — 更新对话 **请求**: ```json { "title": "修改后的标题" } ``` **响应**(200 OK): ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "title": "修改后的标题", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T12:00:00Z", "message_count": 12 } ``` #### `DELETE /api/conversations/:id` — 删除对话 **响应**(204 No Content):无响应体 **错误**: - `404 NOT_FOUND`: 对话不存在或无权访问 #### `GET /api/conversations/:id/messages` — 获取对话消息 **查询参数**: - `page`: 页码,从 1 开始,默认 1 - `page_size`: 每页条数,默认 50,最大 100 **响应**(200 OK): ```json { "messages": [ { "id": "660e8400-e29b-41d4-a716-446655440000", "conversation_id": "550e8400-e29b-41d4-a716-446655440000", "role": "user", "content": "这是什么植物?", "image_url": "/api/images/abc123.jpg", "created_at": "2024-01-15T10:30:00Z" }, { "id": "770e8400-e29b-41d4-a716-446655440000", "conversation_id": "550e8400-e29b-41d4-a716-446655440000", "role": "assistant", "content": "这是一株向日葵...", "created_at": "2024-01-15T10:30:15Z" } ], "total": 12, "page": 1, "page_size": 50 } ``` **消息字段说明**: - `role`: `"user"` 或 `"assistant"` - `image_url`: 仅 `user` 消息可能包含,指向存储的图像 - `content`: 消息文本内容 --- ## 三、错误码表 所有错误均使用以下格式: ```json { "code": "ERROR_CODE", "message": "Human-readable error description", "details": {} } ``` ### WebSocket 错误码 | 错误码 | 说明 | HTTP 状态码(若适用)| |--------|------|---------------------| | `INVALID_MESSAGE` | 消息格式错误或缺少必填字段 | - | | `SESSION_NOT_FOUND` | 会话不存在 | - | | `RATE_LIMITED` | 请求频率过高 | 429 | | `IMAGE_TOO_LARGE` | 图像超过大小限制(5MB)| - | | `AUDIO_TOO_LARGE` | 音频超过大小限制(10MB)| - | | `STT_ERROR` | 语音识别服务错误 | - | | `LLM_ERROR` | LLM 服务错误 | - | | `LLM_TIMEOUT` | LLM 响应超时(60 秒)| - | | `TTS_ERROR` | 语音合成服务错误 | - | | `CONCURRENT_REQUEST` | 同一连接已有进行中的请求 | - | | `INTERNAL_ERROR` | 服务器内部错误 | 500 | ### REST API 错误码 | 错误码 | 说明 | HTTP 状态码 | |--------|------|-------------| | `INVALID_INPUT` | 请求参数验证失败 | 400 | | `INVALID_TOKEN` | JWT Token 无效或过期 | 401 | | `INVALID_CREDENTIALS` | 用户名或密码错误 | 401 | | `UNAUTHORIZED` | 未认证或认证失败 | 401 | | `FORBIDDEN` | 无权访问资源 | 403 | | `NOT_FOUND` | 资源不存在 | 404 | | `USER_EXISTS` | 用户名或邮箱已存在 | 409 | | `RATE_LIMITED` | 请求频率过高 | 429 | | `INTERNAL_ERROR` | 服务器内部错误 | 500 | | `SERVICE_UNAVAILABLE` | 依赖服务不可用 | 503 | --- ## 四、数据模型 ### 用户(User) ```typescript interface User { id: string; // UUID username: string; // 用户名,唯一 email: string; // 邮箱,唯一 created_at: string; // ISO 8601 时间戳 updated_at: string; // ISO 8601 时间戳 } ``` ### 对话(Conversation) ```typescript interface Conversation { id: string; // UUID user_id: string; // 所属用户 ID title: string; // 对话标题 created_at: string; // ISO 8601 时间戳 updated_at: string; // ISO 8601 时间戳 message_count: number; // 消息数量 } ``` ### 消息(Message) ```typescript interface Message { id: string; // UUID conversation_id: string; // 所属对话 ID role: "user" | "assistant"; content: string; // 消息文本内容 image_url?: string; // 可选,用户消息的关联图像 URL created_at: string; // ISO 8601 时间戳 } ``` ### JWT Token 载荷 **Access Token**(有效期 120 分钟): ```json { "user_id": "550e8400-e29b-41d4-a716-446655440000", "username": "alice", "type": "access", "exp": 1705318200, "iat": 1705311000 } ``` **Refresh Token**(有效期 7 天): ```json { "user_id": "550e8400-e29b-41d4-a716-446655440000", "type": "refresh", "exp": 1705915800, "iat": 1705311000 } ``` --- ## 附录:版本历史 - **v1.0**(2024-01-15):初始版本,定义 WebSocket 协议和 REST API - **v1.1**(2024-01-20):新增文本输入模式(`query.text` 字段) - **v1.2**(2024-01-25):新增场景模式配置(`config.scenario` 字段) - **v2.0**(2026-06-21):重构为纯接口契约规范,移除实现细节