70f8b30d04
新增 docs/api/gateway-api.md:面向客户端开发的网关 API 统一文档,覆盖全部 16 个模块。 新增 docs/api/backend-services/:后端服务详细文档 (ai-core, memory-service, voice-service, iot-debug, tool-engine)。 更新 .gitignore:docs/api/ 例外允许推送,其他 docs/ 内容仍忽略。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1077 lines
24 KiB
Markdown
1077 lines
24 KiB
Markdown
# Cyrene Gateway API 文档
|
||
|
||
**版本:** v1 | **Base URL:** `http://<gateway-host>:<port>/api/v1`
|
||
|
||
所有需要认证的接口在 HTTP Header 中携带 JWT:
|
||
```
|
||
Authorization: Bearer <jwt_token>
|
||
```
|
||
|
||
WebSocket 通过 query 参数传 token:`/ws/chat?token=<jwt_token>`
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [认证](#1-认证)
|
||
2. [WebSocket 实时通信](#2-websocket-实时通信)
|
||
3. [会话管理](#3-会话管理)
|
||
4. [消息搜索](#4-消息搜索)
|
||
5. [语音 STT / TTS](#5-语音-stt--tts)
|
||
6. [文件管理](#6-文件管理)
|
||
7. [图片分析](#7-图片分析)
|
||
8. [知识库](#8-知识库)
|
||
9. [记忆管理](#9-记忆管理)
|
||
10. [自动化规则与场景](#10-自动化规则与场景)
|
||
11. [通知推送](#11-通知推送)
|
||
12. [提醒管理](#12-提醒管理)
|
||
13. [每日简报](#13-每日简报)
|
||
14. [Webhook 第三方接入](#14-webhook-第三方接入)
|
||
15. [Admin 管理](#15-admin-管理)
|
||
16. [健康检查](#16-健康检查)
|
||
|
||
---
|
||
|
||
## 1. 认证
|
||
|
||
### POST /auth/register — 注册
|
||
|
||
Auth: 无。IP 限流 ~5/min。仅 `REGISTRATION_ENABLED=true` 时可用(默认关闭)。
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"username": "string (3-32 chars, ^[a-zA-Z0-9_]+$)",
|
||
"password": "string (6-64 chars)",
|
||
"email": "string (需含 @)",
|
||
"nickname": "string (1-32 chars)",
|
||
"verify_code": "string (6 chars, 开发阶段固定 000000)"
|
||
}
|
||
|
||
// 响应 201
|
||
{
|
||
"user_id": "user_<username>",
|
||
"token": "JWT",
|
||
"refresh_token": "JWT (30天)",
|
||
"expires": 1717000000,
|
||
"nickname": "string"
|
||
}
|
||
```
|
||
|
||
错误: 400 `用户名格式无效`, 400 `邮箱格式无效`, 400 `验证码错误`, 403 `当前不开放公开注册`, 409 `用户名已被注册`
|
||
|
||
---
|
||
|
||
### POST /auth/login — 登录
|
||
|
||
Auth: 无。IP 限流 ~5/min。
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"username": "string",
|
||
"password": "string"
|
||
}
|
||
|
||
// 响应 200
|
||
{
|
||
"user_id": "admin",
|
||
"nickname": "string",
|
||
"token": "JWT",
|
||
"refresh_token": "JWT (30天)",
|
||
"expires": 1717000000
|
||
}
|
||
```
|
||
|
||
错误: 400 `用户名格式无效`, 401 `用户名或密码错误`
|
||
|
||
---
|
||
|
||
### POST /auth/refresh — 刷新 Token
|
||
|
||
Auth: JWT(可接受已过期的 token,或在 body 中提供 refresh_token)。
|
||
|
||
```json
|
||
// 请求(可选)
|
||
{ "refresh_token": "string" }
|
||
|
||
// 响应 200
|
||
{
|
||
"token": "新 JWT",
|
||
"refresh_token": "新 JWT (30天)",
|
||
"expires": 1717000000
|
||
}
|
||
```
|
||
|
||
错误: 401 `刷新令牌无效或已过期`, 401 `未提供认证令牌`
|
||
|
||
---
|
||
|
||
## 2. WebSocket 实时通信
|
||
|
||
### GET /ws/chat — 建立连接
|
||
|
||
```
|
||
ws://<gateway>/ws/chat?token=<jwt>&session_id=<optional>&client_id=<optional>&device_name=<optional>
|
||
```
|
||
|
||
| Query 参数 | 必填 | 说明 |
|
||
|-----------|------|------|
|
||
| `token` | 是* | JWT(也可用 `Authorization: Bearer` header) |
|
||
| `session_id` | 否 | 不传自动生成 `session_` + 12 随机字符 |
|
||
| `client_id` | 否 | 多端标识 |
|
||
| `device_name` | 否 | 设备名 |
|
||
|
||
注意:WebSocket 仅限 admin 用户;非 admin 收到 **403**。
|
||
|
||
---
|
||
|
||
### 客户端 → 服务端 (ClientMessage)
|
||
|
||
```json
|
||
{
|
||
"type": "message|voice_input|ping|history",
|
||
"session_id": "string (可选)",
|
||
"mode": "text|voice_msg|voice_assistant",
|
||
"content": "string (message 类型必填)",
|
||
"audio_data": "string (voice_input 类型必填, base64)",
|
||
"attachments": [
|
||
{
|
||
"type": "image",
|
||
"url": "string",
|
||
"thumbnail_url": "string",
|
||
"filename": "string",
|
||
"width": 0,
|
||
"height": 0,
|
||
"size": 0,
|
||
"description": "string"
|
||
}
|
||
],
|
||
"timestamp": 1717000000000,
|
||
"client_id": "string",
|
||
"device_name": "string",
|
||
"user_agent": "string"
|
||
}
|
||
```
|
||
|
||
| type | 说明 |
|
||
|------|------|
|
||
| `message` | 文字聊天,触发 AI 回复 |
|
||
| `voice_input` | 语音输入,先转录再作为 message 处理 |
|
||
| `ping` | 心跳,自动回复 pong |
|
||
| `history` | 请求历史消息 |
|
||
|
||
---
|
||
|
||
### 服务端 → 客户端 (ServerMessage)
|
||
|
||
```json
|
||
{
|
||
"type": "string (见下表)",
|
||
"message_id": "string",
|
||
"text": "string (完整文本)",
|
||
"content": "string (增量文本/完整内容)",
|
||
"role": "user|assistant|action|system",
|
||
"msg_type": "chat|action|thinking|tool_progress|system_info",
|
||
"session_id": "string",
|
||
"error": "string (仅错误时)",
|
||
"timestamp": 1717000000000,
|
||
"segments": [ { "index": 0, "text": "string", "audio_url": "string", "duration_ms": 0 } ],
|
||
"messages": [ Message ],
|
||
"thinking_status": "string",
|
||
"thinking_content": "string",
|
||
"tool_progress": { "tool_name": "string", "status": "started|running|completed|failed", "progress": 0.5, "message": "string" },
|
||
"system_info": { "level": "info|warning|error", "message": "string", "action": "string" },
|
||
"notification": { "id": "string", "type": "info|warning|success|thinking|reminder", "title": "string", "body": "string", "timestamp": "string", "data": {} },
|
||
"multi_message": { "messages": [ { "index": 0, "content": "string" } ] },
|
||
"review_messages": [ { "type": "action|chat", "content": "string", "delay_ms": 0 } ],
|
||
"client_info": { "client_id": "string", "device_name": "string", "user_agent": "string" },
|
||
"full_audio_url": "string",
|
||
"response_mode": "string"
|
||
}
|
||
```
|
||
|
||
### ServerMessage type 列表
|
||
|
||
| type | 说明 |
|
||
|------|------|
|
||
| `response` | 完整文本回复 |
|
||
| `stream_start` | AI 开始生成 |
|
||
| `stream_chunk` | 增量文本块 |
|
||
| `stream_end` | AI 生成结束(含完整 text) |
|
||
| `stream_segments` | 流式断句(语音) |
|
||
| `voice_transcript` | 语音转录结果 |
|
||
| `error` | 错误 |
|
||
| `history_response` | 历史消息返回 |
|
||
| `notification` | 推送通知 |
|
||
| `multi_message` | 多条消息合并投递 |
|
||
| `review` | 审查后结构化消息 |
|
||
| `thinking` | 后台思考更新 |
|
||
| `tool_progress` | 工具执行进度 |
|
||
| `system_info` | 系统级通知 |
|
||
| `pong` | 响应 ping |
|
||
| `device_update` | IoT 设备状态更新 |
|
||
| `background_thinking` | 后台思考状态变更 |
|
||
|
||
---
|
||
|
||
### 流式响应流程
|
||
|
||
```
|
||
Client Gateway AI-Core
|
||
| | |
|
||
|-- {type:"message"} --> | |
|
||
| |-- POST /api/v1/chat --> |
|
||
| | (SSE streaming) |
|
||
| |<-- data: {delta:"..."} |
|
||
|<-- {type:"stream_start"} | |
|
||
|<-- {type:"review"} | (多条结构化消息) |
|
||
|<-- {type:"stream_segments"} | (断句事件) |
|
||
|<-- {type:"stream_end"} | (含 full text) |
|
||
```
|
||
|
||
---
|
||
|
||
### 语音输入流程
|
||
|
||
```
|
||
Client Gateway Voice-Service
|
||
| | |
|
||
|-- {type:"voice_input", | |
|
||
| audio_data:"<base64>"} --> | |
|
||
| |-- POST /transcribe --> |
|
||
| |<-- {text:"..."} |
|
||
|<-- {type:"voice_transcript", | |
|
||
| text:"转录结果"} | |
|
||
| | |
|
||
| (Gateway 自动将转录文本 | |
|
||
| 作为 message 发给 AI-Core) | |
|
||
|<-- {type:"stream_start"} | |
|
||
|<-- ... 正常流式回复 ... | |
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 会话管理
|
||
|
||
所有接口需要 JWT。Admin 可操作所有用户;非 admin 仅限自己的数据。
|
||
|
||
### POST /sessions — 创建会话
|
||
|
||
```json
|
||
// 请求 (全部可选,空 body 也可)
|
||
{
|
||
"session_id": "string (可选,不传自动生成)",
|
||
"title": "string (默认 '新的对话')",
|
||
"is_main": false
|
||
}
|
||
|
||
// 响应 201
|
||
{
|
||
"id": "string",
|
||
"user_id": "string",
|
||
"title": "string",
|
||
"is_main": false,
|
||
"created_at": 1717000000000,
|
||
"updated_at": 1717000000000
|
||
}
|
||
```
|
||
|
||
### GET /sessions — 列表
|
||
|
||
`?user_id=xxx` — admin 可查任意用户;非 admin 只能查自己。
|
||
|
||
```json
|
||
// 响应 200
|
||
{ "sessions": [ Session, ... ] }
|
||
```
|
||
|
||
### GET /sessions/:id — 详情
|
||
|
||
同 Session 结构。
|
||
|
||
错误: 404 `{"error":"会话不存在","errorType":"session_not_found","hint":"该会话可能已被删除或尚未创建"}`
|
||
|
||
### DELETE /sessions/:id — 删除
|
||
|
||
`{"status":"deleted"}`
|
||
|
||
### DELETE /sessions — 清空全部
|
||
|
||
`?user_id=xxx` → `{"status":"deleted"}`
|
||
|
||
### GET /sessions/:id/messages — 消息
|
||
|
||
`?limit=50&offset=0`
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"messages": [
|
||
{
|
||
"id": 1,
|
||
"session_id": "string",
|
||
"role": "user|assistant|system|action",
|
||
"msg_type": "chat|action",
|
||
"content": "string",
|
||
"created_at": 1717000000000
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### DELETE /sessions/:id/messages — 清空服务器本地所有消息
|
||
|
||
`{"status":"cleared"}`
|
||
|
||
### GET /sessions/:id/export — 导出
|
||
|
||
`?format=json|markdown|txt(默认 json)`
|
||
|
||
返回文件下载。JSON 导出格式:
|
||
```json
|
||
{
|
||
"session": { "id", "title", "created_at", "updated_at" },
|
||
"messages": [ { "role", "content", "created_at" } ]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 消息搜索
|
||
|
||
### GET /messages/search — 全文搜索
|
||
|
||
`?q=<keyword>&user_id=xxx&limit=50&offset=0`
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"results": [
|
||
{
|
||
"message_id": "string",
|
||
"session_id": "string",
|
||
"session_title": "string",
|
||
"role": "string",
|
||
"content": "string",
|
||
"created_at": 1717000000000
|
||
}
|
||
],
|
||
"total": 10,
|
||
"query": "keyword",
|
||
"limit": 50,
|
||
"offset": 0
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 语音 STT / TTS
|
||
|
||
### POST /voice/transcribe — 语音转文字
|
||
|
||
Content-Type: `multipart/form-data`。字段 `audio` (file)。最大 10MB。接受 PCM/WAV/MP3/OGG/FLAC/WebM 等格式。
|
||
|
||
```json
|
||
// 响应 200
|
||
{ "success": true, "text": "识别结果文本" }
|
||
|
||
// 错误
|
||
{ "success": false, "error": "语音识别失败: ..." }
|
||
```
|
||
|
||
### POST /voice/tts — 文字转语音
|
||
|
||
Content-Type: `application/json`。
|
||
|
||
代理到 Voice-Service `POST /api/v1/tts/synthesize`。
|
||
|
||
### GET /voice/tts/voices — 发音人列表
|
||
|
||
代理到 Voice-Service `GET /api/v1/tts/voices`。
|
||
|
||
### GET /voice/tts/status — TTS 状态
|
||
|
||
### GET /voice/status — 语音服务完整状态 (STT + TTS)
|
||
|
||
Voice-Service 不可达时返回 502:
|
||
```json
|
||
{"error":"Voice-Service 不可达: ...","errorType":"voice_service_unreachable"}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 文件管理
|
||
|
||
### POST /files/upload — 上传
|
||
|
||
Content-Type: `multipart/form-data`。字段 `file`。最大 20MB。
|
||
|
||
允许 MIME 类型:`image/jpeg,png,gif,webp,svg+xml` | `application/pdf,msword,vnd.openxmlformats-officedocument.wordprocessingml.document` | `text/plain,markdown` | `audio/mpeg,wav,ogg,webm` | `video/mp4,webm`
|
||
|
||
```json
|
||
// 响应 201
|
||
{
|
||
"id": "uuid",
|
||
"filename": "string (脱敏后)",
|
||
"mime_type": "string",
|
||
"size": 1024,
|
||
"url": "/api/v1/files/<id>/download"
|
||
}
|
||
```
|
||
|
||
错误: 400 `{"error":"文件大小超过限制 (最大 20MB)","errorType":"file_too_large"}`, 400 `{"error":"不支持的文件类型: ...","errorType":"unsupported_type"}`
|
||
|
||
### GET /files — 列表
|
||
|
||
`?page=1&limit=20`
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"files": [
|
||
{
|
||
"id": "uuid", "user_id": "string", "filename": "string",
|
||
"mime_type": "string", "size": 1024, "hash": "sha256hex",
|
||
"is_public": false, "created_at": 1717000000000,
|
||
"url": "string", "thumbnail_url": "string (仅图片)"
|
||
}
|
||
],
|
||
"total": 100, "page": 1, "limit": 20
|
||
}
|
||
```
|
||
|
||
### GET /files/:id — 元数据
|
||
|
||
返回单个 File 对象。
|
||
|
||
### GET /files/:id/download — 下载
|
||
|
||
文件流下载。404 → `{"error":"文件实体不存在(可能已被清理)","errorType":"file_missing"}`
|
||
|
||
### GET /files/:id/thumbnail — 缩略图
|
||
|
||
图片:JPEG 缩略图 (max 300x300)。非图片:SVG 占位图标。`Cache-Control: public, max-age=86400`
|
||
|
||
### DELETE /files/:id — 删除
|
||
|
||
`{"status":"deleted"}`
|
||
|
||
---
|
||
|
||
## 7. 图片分析
|
||
|
||
### POST /images/analyze — 分析
|
||
|
||
两种方式:
|
||
- **JSON:** `{"file_id": "uuid"}` — 分析已上传文件
|
||
- **Multipart:** 字段 `file` 或 `image` — 直接上传分析 (max 10MB),支持 JPEG/PNG/GIF
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"format": "jpeg",
|
||
"width": 1920,
|
||
"height": 1080,
|
||
"file_size": 204800,
|
||
"description": "AI 生成的图片描述",
|
||
"top_colors": [ { "hex": "#4A90D9", "percent": 35.2 } ],
|
||
"exif": { "Make": "Canon" },
|
||
"analyzed_by": "openai_vision|local"
|
||
}
|
||
```
|
||
|
||
### GET /images/analyze/:file_id — 按已上传文件分析
|
||
|
||
同上。
|
||
|
||
---
|
||
|
||
## 8. 知识库
|
||
|
||
### POST /knowledge/bases — 创建知识库
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"name": "string (必填)",
|
||
"description": "string"
|
||
}
|
||
|
||
// 响应 201
|
||
{
|
||
"id": "uuid", "user_id": "string", "name": "string",
|
||
"description": "string", "created_at": "...", "updated_at": "...", "doc_count": 0
|
||
}
|
||
```
|
||
|
||
### GET /knowledge/bases — 列表
|
||
|
||
```json
|
||
{ "knowledge_bases": [ KnowledgeBase ], "total": 10 }
|
||
```
|
||
|
||
### GET /knowledge/bases/:id — 详情(含文档列表)
|
||
|
||
```json
|
||
{ "knowledge_base": KnowledgeBase, "documents": [ KnowledgeDocument ] }
|
||
```
|
||
|
||
### PUT /knowledge/bases/:id — 更新
|
||
|
||
```json
|
||
{ "name": "string (必填)", "description": "string" }
|
||
→ { "status": "updated" }
|
||
```
|
||
|
||
### DELETE /knowledge/bases/:id — 删除
|
||
|
||
`{"status":"deleted"}`
|
||
|
||
---
|
||
|
||
### POST /knowledge/bases/:id/documents — 添加文档
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"title": "string (必填)",
|
||
"content": "string (text 类型时)",
|
||
"source_type": "text|file|url (默认 text)",
|
||
"file_id": "string (file 类型必填)"
|
||
}
|
||
|
||
// 响应 201
|
||
{
|
||
"id": "uuid", "kb_id": "string", "user_id": "string",
|
||
"title": "string", "source_type": "string", "source_ref": "string",
|
||
"content_type": "string", "raw_content": "string",
|
||
"chunk_count": 5, "created_at": "...", "updated_at": "..."
|
||
}
|
||
```
|
||
|
||
注意:`source_type=file` 时 gateway 读取文件内容(仅支持文本类型和 `application/json`)。
|
||
|
||
### GET /knowledge/bases/:id/documents — 文档列表
|
||
|
||
`{"documents": [ KnowledgeDocument ], "total": 10}`
|
||
|
||
### GET /knowledge/documents/:id — 文档详情(含分块)
|
||
|
||
```json
|
||
{
|
||
"document": KnowledgeDocument,
|
||
"chunks": [ KnowledgeChunk ]
|
||
}
|
||
```
|
||
|
||
### DELETE /knowledge/documents/:id — 删除
|
||
|
||
`{"status":"deleted"}`
|
||
|
||
---
|
||
|
||
### POST /knowledge/search — 语义搜索
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"query": "string (必填)",
|
||
"kb_ids": ["uuid"], // 可选,空=搜索全部
|
||
"limit": 5 // 1-50
|
||
}
|
||
|
||
// 响应 200
|
||
{
|
||
"chunks": [ SearchChunkResult ],
|
||
"total": 5,
|
||
"query": "string"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 记忆管理
|
||
|
||
代理到 Memory-Service。
|
||
|
||
### GET /memory/search — 搜索
|
||
|
||
`?q=<keyword>&user_id=xxx` → 代理到 Memory-Service `POST /memories/query`
|
||
|
||
### GET /memory — 列表
|
||
|
||
`?user_id=xxx` → 代理到 Memory-Service `GET /memories`
|
||
|
||
### POST /memory — 添加
|
||
|
||
```json
|
||
{
|
||
"content": "string (必填)",
|
||
"category": "string (默认 other)",
|
||
"priority": 1
|
||
}
|
||
```
|
||
|
||
### DELETE /memory — 删除
|
||
|
||
`?id=<memory_id>`
|
||
|
||
Memory-Service 不可达时返回 502:
|
||
```json
|
||
{"error":"Memory-Service 不可达: ...","errorType":"memory_service_unreachable"}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 自动化规则与场景
|
||
|
||
### 规则
|
||
|
||
#### GET /automation/rules — 列表
|
||
|
||
```json
|
||
{
|
||
"rules": [
|
||
{
|
||
"id": "32位hex", "user_id": "string", "name": "string",
|
||
"description": "string", "trigger_type": "string",
|
||
"trigger_config": {}, "conditions": {}, "actions": {},
|
||
"enabled": true, "created_at": "..."
|
||
}
|
||
],
|
||
"count": 5
|
||
}
|
||
```
|
||
|
||
#### POST /automation/rules — 创建
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"name": "string (必填)",
|
||
"description": "string",
|
||
"trigger_type": "string (必填)",
|
||
"trigger_config": {},
|
||
"conditions": {},
|
||
"actions": {} (必填),
|
||
"enabled": true
|
||
}
|
||
|
||
// 响应 201 → {"success": true, "rule": Rule}
|
||
```
|
||
|
||
#### GET /automation/rules/:id — 详情
|
||
|
||
`{"rule": Rule}` | 404 → `{"error":"规则不存在"}`
|
||
|
||
#### PUT /automation/rules/:id — 更新
|
||
|
||
所有字段可选(partial update)。`{"success": true, "rule": Rule}`
|
||
|
||
#### DELETE /automation/rules/:id — 删除
|
||
|
||
`{"success": true}`
|
||
|
||
#### POST /automation/rules/:id/trigger — 手动触发
|
||
|
||
`{"success": true, "message": "规则已触发"}`
|
||
|
||
---
|
||
|
||
### 场景
|
||
|
||
#### GET /automation/scenes — 列表
|
||
|
||
`{"scenes": [ Scene ], "count": 5}`
|
||
|
||
#### POST /automation/scenes — 创建
|
||
|
||
```json
|
||
{
|
||
"name": "string (必填)",
|
||
"icon": "string",
|
||
"rule_ids": ["rule_id_1", "rule_id_2"]
|
||
}
|
||
→ {"success": true, "scene": Scene}
|
||
```
|
||
|
||
#### GET /automation/scenes/:id — 详情
|
||
|
||
`{"scene": Scene}`
|
||
|
||
#### PUT /automation/scenes/:id — 更新
|
||
|
||
所有字段可选。`{"success": true, "scene": Scene}`
|
||
|
||
#### DELETE /automation/scenes/:id — 删除
|
||
|
||
`{"success": true}`
|
||
|
||
#### POST /automation/scenes/:id/execute — 执行
|
||
|
||
`{"success": true, "message": "场景已执行"}`
|
||
|
||
---
|
||
|
||
## 11. 通知推送
|
||
|
||
### POST /notifications/push — 推送通知
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"user_id": "string (必填)",
|
||
"type": "info|warning|success|thinking|reminder (必填)",
|
||
"title": "string (必填)",
|
||
"body": "string (必填)",
|
||
"data": {}
|
||
}
|
||
|
||
// 响应 200
|
||
{
|
||
"success": true,
|
||
"notification": {
|
||
"id": "uuid",
|
||
"type": "info",
|
||
"title": "...",
|
||
"user_id": "...",
|
||
"timestamp": "2024-01-01T12:00:00Z",
|
||
"delivered": true
|
||
}
|
||
}
|
||
```
|
||
|
||
delivered = true 表示目标用户有活跃 WebSocket 连接。
|
||
|
||
---
|
||
|
||
## 12. 提醒管理
|
||
|
||
### GET /reminders — 列表
|
||
|
||
`?user_id=xxx&status=pending|completed|cancelled&limit=50&offset=0`
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"reminders": [
|
||
{
|
||
"id": "string", "user_id": "string", "title": "string",
|
||
"description": "string", "remind_at": "2024-01-01T15:00:00Z",
|
||
"status": "pending",
|
||
"repeat_type": "none|daily|weekly|monthly",
|
||
"session_id": "string", "notified": false,
|
||
"created_at": "...", "completed_at": null
|
||
}
|
||
],
|
||
"count": 5
|
||
}
|
||
```
|
||
|
||
### POST /reminders — 创建
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"title": "string (必填)",
|
||
"description": "string",
|
||
"remind_at": "2024-01-01T15:00:00Z (必填, ISO 8601)",
|
||
"repeat_type": "none|daily|weekly|monthly (默认 none)",
|
||
"session_id": "string"
|
||
}
|
||
|
||
// 响应 201
|
||
{ "success": true, "reminder": Reminder }
|
||
```
|
||
|
||
错误: 400 `{"error":"时间格式无效,请使用 ISO 8601 格式 (例如 2024-01-01T15:00:00Z)"}`
|
||
|
||
### PUT /reminders/:id — 更新
|
||
|
||
所有字段可选 (partial update)。设置 `status=completed|cancelled` 会自动写入 `completed_at`。
|
||
|
||
`{"success":true, "reminder":Reminder}` | 404 `{"error":"提醒不存在"}`
|
||
|
||
### DELETE /reminders/:id — 删除
|
||
|
||
`{"success":true}`
|
||
|
||
---
|
||
|
||
## 13. 每日简报
|
||
|
||
### GET /briefings — 按日期获取
|
||
|
||
`?user_id=xxx&date=2024-01-01` (date 默认今天)
|
||
|
||
```json
|
||
// 响应 200
|
||
{
|
||
"briefing": {
|
||
"id": "brief_xxx",
|
||
"user_id": "string",
|
||
"date": "2024-01-01",
|
||
"summary": "AI 生成或回退摘要",
|
||
"summary_source": "ai|fallback",
|
||
"status": "pending|generated|delivered",
|
||
"weather": {
|
||
"location": "string", "temp": 22.5,
|
||
"condition": "string", "icon": "☀️"
|
||
},
|
||
"news": [
|
||
{ "title": "string", "url": "string", "source": "string", "summary": "string" }
|
||
],
|
||
"reminders": [
|
||
{ "id": "string", "title": "string", "remind_at": "2024-01-01T15:00:00Z" }
|
||
],
|
||
"created_at": "...", "generated_at": "...", "delivered_at": "..."
|
||
}
|
||
}
|
||
```
|
||
|
||
briefing 为 null 时:`{"briefing":null, "message":"当日简报尚未生成"}`
|
||
|
||
### GET /briefings/latest — 最近简报
|
||
|
||
`?user_id=xxx&limit=7 (max 30)`
|
||
|
||
```json
|
||
{ "briefings": [ Briefing ], "total": 7 }
|
||
```
|
||
|
||
### POST /briefings/generate — 手动生成
|
||
|
||
```json
|
||
// 请求
|
||
{ "user_id": "string (必填)" }
|
||
|
||
// 响应 200
|
||
{ "success": true, "briefing": Briefing, "message": "简报已生成并推送" }
|
||
```
|
||
|
||
---
|
||
|
||
## 14. Webhook 第三方接入
|
||
|
||
Auth: `X-Webhook-Key` header。
|
||
|
||
### POST /webhook/generic — 通用 Webhook
|
||
|
||
```json
|
||
// 请求
|
||
{
|
||
"message": "string (必填)",
|
||
"user_id": "string (默认 webhook_generic,自动加 ext_ 前缀)",
|
||
"session_id": "string (默认 webhook_ + 12 随机字符)",
|
||
"mode": "text|voice_msg (默认 text)",
|
||
"platform": "string (默认 generic)"
|
||
}
|
||
|
||
// 响应 200
|
||
{
|
||
"reply": "AI 回复文本",
|
||
"session_id": "string",
|
||
"message_id": "string",
|
||
"finish_reason": "stop"
|
||
}
|
||
```
|
||
|
||
错误: 400 `{"error":"消息不能为空"}`, 502 `{"error":"AI 服务暂不可用: ..."}`
|
||
|
||
### POST /webhook/discord — Discord 交互
|
||
|
||
接收标准 Discord Interaction:
|
||
- `type=1` (PING) → `{"type":1}`
|
||
- `type=2` (APPLICATION_COMMAND) → 处理 `/chat message:` 命令
|
||
|
||
```json
|
||
// 响应 200
|
||
{ "type": 4, "data": { "content": "AI 回复" } }
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Admin 管理
|
||
|
||
需要 JWT + admin 权限(`user_id == "admin"`)。非 admin 返回 **403**。
|
||
|
||
### 会话管理
|
||
|
||
#### GET /admin/sessions — 活跃会话列表
|
||
|
||
```json
|
||
{ "sessions": [ SessionState ], "total": 5 }
|
||
```
|
||
|
||
#### GET /admin/sessions/active — 按用户分组
|
||
|
||
```json
|
||
{ "users": { "user_id": [ SessionState ] } }
|
||
```
|
||
|
||
#### GET /admin/sessions/:id — 指定会话详情
|
||
|
||
404 → `{"error":"会话不存在","errorType":"session_not_found"}`
|
||
|
||
---
|
||
|
||
### 客户端管理
|
||
|
||
#### GET /admin/clients — 已知客户端
|
||
|
||
`?user_id=admin`
|
||
|
||
```json
|
||
{
|
||
"clients": [
|
||
{
|
||
"client_id": "string", "device_name": "string",
|
||
"user_agent": "string", "note": "string",
|
||
"last_seen": 1717000000000, "online": true
|
||
}
|
||
],
|
||
"total": 3
|
||
}
|
||
```
|
||
|
||
#### PUT /admin/clients/:id/note — 设置备注
|
||
|
||
```json
|
||
{ "note": "string" }
|
||
→ { "status": "ok", "client_id": "string", "note": "string" }
|
||
```
|
||
|
||
404 → `{"error":"客户端未找到"}`
|
||
|
||
---
|
||
|
||
### 模型配置管理
|
||
|
||
#### GET /admin/models/providers — Provider 列表
|
||
|
||
```json
|
||
{
|
||
"providers": [
|
||
{ "name": "string", "base_url": "string", "api_key": "string" }
|
||
],
|
||
"total": 2
|
||
}
|
||
```
|
||
|
||
#### POST /admin/models/providers/:name — 创建/更新 Provider
|
||
|
||
```json
|
||
{ "name": "...", "base_url": "...", "api_key": "..." }
|
||
→ { "status": "saved", "name": "string" }
|
||
```
|
||
|
||
#### DELETE /admin/models/providers/:name — 删除
|
||
|
||
`{"status":"deleted","name":"string"}`
|
||
|
||
#### GET /admin/models/models — Model 列表
|
||
|
||
```json
|
||
{
|
||
"models": [
|
||
{
|
||
"id": "string", "name": "string", "provider": "string",
|
||
"description": "string", "priority": 1, "tags": [],
|
||
"params": { "temperature": 0.7 }, "enabled": true,
|
||
"updated_at": "..."
|
||
}
|
||
],
|
||
"total": 5
|
||
}
|
||
```
|
||
|
||
#### POST /admin/models/models/:id — 创建/更新 Model
|
||
|
||
```json
|
||
{ "id": "...", "name": "...", "provider": "...", "params": {}, ... }
|
||
→ { "status": "saved", "id": "string" }
|
||
```
|
||
|
||
#### DELETE /admin/models/models/:id — 删除
|
||
|
||
`{"status":"deleted","id":"string"}`
|
||
|
||
#### GET /admin/models/routing — 路由规则列表
|
||
|
||
#### POST /admin/models/routing/:purpose — 创建/更新路由规则
|
||
|
||
```json
|
||
{ "purpose": "...", "fallback_chain": ["model1", "model2"], "required": true }
|
||
→ { "status": "saved", "purpose": "string" }
|
||
```
|
||
|
||
#### DELETE /admin/models/routing/:purpose — 删除
|
||
|
||
#### POST /admin/models/health-check — 测试 Provider 连接
|
||
|
||
```json
|
||
{ "provider": "string (必填)" }
|
||
→ { "provider": "string", "message": "Provider 配置已保存,连接测试请通过实际 LLM 调用验证" }
|
||
```
|
||
|
||
#### GET /admin/models/fetch-models/:name — 代理获取远程模型列表
|
||
|
||
`?url=<provider_models_api_url>` → 返回该 Provider 支持的模型列表。
|
||
|
||
---
|
||
|
||
## 16. 健康检查
|
||
|
||
### GET /health — 健康检查
|
||
|
||
Auth: 无。
|
||
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"service": "cyrene-gateway",
|
||
"ws_connections": 3
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 附录:错误格式
|
||
|
||
所有 API 错误统一为:
|
||
|
||
```json
|
||
{
|
||
"error": "错误描述",
|
||
"errorType": "error_code (可选,客户端可据此判断)",
|
||
"hint": "解决建议 (可选)"
|
||
}
|
||
```
|
||
|
||
### errorType 列表
|
||
|
||
| errorType | 含义 |
|
||
|-----------|------|
|
||
| `session_not_found` | 会话不存在 |
|
||
| `file_too_large` | 文件超过大小限制 |
|
||
| `unsupported_type` | 不支持的 MIME 类型 |
|
||
| `file_missing` | 文件实体已清理 |
|
||
| `memory_service_unreachable` | Memory-Service 不可达 |
|
||
| `voice_service_unreachable` | Voice-Service 不可达 |
|
||
| `admin_only` | 仅限管理员操作 |
|
||
|
||
### HTTP 状态码
|
||
|
||
| 状态码 | 场景 |
|
||
|--------|------|
|
||
| 200 | 成功 |
|
||
| 201 | 创建成功 |
|
||
| 400 | 请求参数错误 |
|
||
| 401 | 未认证 / Token 无效 |
|
||
| 403 | 无权限 |
|
||
| 404 | 资源不存在 |
|
||
| 409 | 资源冲突 (如用户名已存在) |
|
||
| 413 | 请求体过大 |
|
||
| 502 | 下游服务不可达 |
|