docs: 添加完整 API 文档 — Gateway 统一文档 + 后端服务文档
新增 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>
This commit is contained in:
+3
-2
@@ -44,8 +44,9 @@ models.json
|
||||
platform_configs.json
|
||||
.claude/
|
||||
|
||||
# ========== 文档 (项目规范:docs/ 不纳入版本管理) ==========
|
||||
docs/
|
||||
# ========== 文档 (项目规范:docs/ 不纳入版本管理,docs/api/ 为例外) ==========
|
||||
docs/*
|
||||
!docs/api/
|
||||
|
||||
# ========== 调试临时文件 (项目规范:debug/cache/ 为临时脚本目录) ==========
|
||||
debug/cache/
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
# AI-Core Service API
|
||||
|
||||
**Base URL:** `http://<host>:8091` | **Auth:** 无(/internal 路由除外)
|
||||
|
||||
AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调度、结果合成。所有对话和记忆端点通过 **Server-Sent Events (SSE)** 或 **JSON** 返回。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [POST /api/v1/chat — 对话](#1-post-apiv1chat)
|
||||
2. [GET /api/v1/memory/search — 记忆搜索](#2-get-apiv1memorysearch)
|
||||
3. [GET /api/v1/memory — 记忆列表](#3-get-apiv1memory)
|
||||
4. [POST /api/v1/memory — 添加记忆](#4-post-apiv1memory)
|
||||
5. [DELETE /api/v1/memory — 删除记忆](#5-delete-apiv1memory)
|
||||
6. [POST /api/v1/internal/presence — 在线状态](#6-post-apiv1internalpresence)
|
||||
7. [GET /api/v1/health — 健康检查](#7-get-apiv1health)
|
||||
8. [Model Selector 路由说明](#8-model-selector-路由说明)
|
||||
|
||||
---
|
||||
|
||||
## 1. POST /api/v1/chat
|
||||
|
||||
**类型:** SSE 流式 | **Content-Type:** `application/json` → `text/event-stream`
|
||||
|
||||
### 请求体 (JSON)
|
||||
|
||||
| JSON 字段 | Go 类型 | 必填 | 说明 |
|
||||
|-----------|---------|------|------|
|
||||
| `user_id` | string | 是 | 用户 ID |
|
||||
| `session_id` | string | 是 | 会话 ID |
|
||||
| `message` | string | 是 | 用户消息文本 |
|
||||
| `images` | []string | 否 | base64 Data URL 数组 |
|
||||
| `mode` | string | 否 | 默认 `"text"` |
|
||||
| `nickname` | string | 否 | 用户昵称 |
|
||||
|
||||
### SSE 事件
|
||||
|
||||
**delta** — 逐 token 发送
|
||||
```json
|
||||
{ "delta": "token 文本", "message_id": "msg-1717000000000000000" }
|
||||
```
|
||||
|
||||
**segments** — 断句事件(生成完成后)
|
||||
```json
|
||||
{
|
||||
"message_id": "string",
|
||||
"mode": "string",
|
||||
"segments": [
|
||||
{ "index": 0, "text": "第一句话" },
|
||||
{ "index": 1, "text": "第二句话" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**review** — 审查后结构化消息(action/chat 分离)
|
||||
```json
|
||||
{
|
||||
"message_id": "string",
|
||||
"review_messages": [
|
||||
{ "type": "action", "content": "打开灯光", "delay_ms": 0 },
|
||||
{ "type": "chat", "content": "好的,已为你打开客厅的灯光。", "delay_ms": 200 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**done** — 流结束
|
||||
```json
|
||||
{ "message_id": "string", "mode": "string", "done": true }
|
||||
```
|
||||
|
||||
**error** — 错误
|
||||
```json
|
||||
{ "delta": "", "error": "错误描述" }
|
||||
```
|
||||
|
||||
终端标记: `data: [DONE]\n\n`
|
||||
|
||||
### HTTP 状态码
|
||||
|
||||
| 状态码 | 含义 |
|
||||
|--------|------|
|
||||
| 200 | 流开始 |
|
||||
| 400 | JSON 解析失败 |
|
||||
| 405 | 非 POST 请求 |
|
||||
| 500 | 服务端不支持流式 |
|
||||
|
||||
---
|
||||
|
||||
## 2. GET /api/v1/memory/search
|
||||
|
||||
### Query 参数
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `user_id` | 是 | 用户 ID |
|
||||
| `q` | 是 | 搜索关键词 |
|
||||
|
||||
### 响应 200
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "string",
|
||||
"query": "搜索词",
|
||||
"memories": [ MemoryEntry, ... ],
|
||||
"total": 5
|
||||
}
|
||||
```
|
||||
|
||||
### 错误 (200 + error 字段)
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "string",
|
||||
"query": "string",
|
||||
"memories": [],
|
||||
"error": "错误描述",
|
||||
"errorType": "memory_store_unavailable|retrieve_failed",
|
||||
"hint": "解决方案 (仅 memory_store_unavailable)"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /api/v1/memory — 记忆列表
|
||||
|
||||
`?user_id=xxx` 最大返回 50 条。
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "string",
|
||||
"memories": [ MemoryEntry, ... ],
|
||||
"total": 3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. POST /api/v1/memory — 添加记忆
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"user_id": "string (必填)",
|
||||
"content": "string (必填)",
|
||||
"category": "string (默认 other)",
|
||||
"priority": 1
|
||||
}
|
||||
|
||||
// 响应 201
|
||||
{
|
||||
"status": "saved",
|
||||
"memory": MemoryEntry
|
||||
}
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | errorType | 说明 |
|
||||
|--------|-----------|------|
|
||||
| 400 | — | 缺少 user_id 或 content |
|
||||
| 500 | `save_failed` | 保存失败 |
|
||||
| 503 | `memory_store_unavailable` | 存储未初始化 |
|
||||
|
||||
---
|
||||
|
||||
## 5. DELETE /api/v1/memory — 删除记忆
|
||||
|
||||
`?id=<memory_id>`
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "status": "deleted", "memory_id": "string" }
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | errorType |
|
||||
|--------|-----------|
|
||||
| 400 | 缺少 id 参数 |
|
||||
| 500 | `delete_failed` |
|
||||
| 503 | `memory_store_unavailable` |
|
||||
|
||||
---
|
||||
|
||||
## 6. POST /api/v1/internal/presence
|
||||
|
||||
**Auth:** `X-Internal-Token` header。Gateway 内部调用的用户上线/下线通知。
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"user_id": "string (必填)",
|
||||
"status": "online|offline (必填)",
|
||||
"session_id": "string (必填)"
|
||||
}
|
||||
|
||||
// 响应 200
|
||||
{ "status": "ok" }
|
||||
```
|
||||
|
||||
| 状态码 | 含义 |
|
||||
|--------|------|
|
||||
| 200 | 成功 |
|
||||
| 400 | JSON 无效 |
|
||||
| 401 | Token 无效 |
|
||||
|
||||
---
|
||||
|
||||
## 7. GET /api/v1/health
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "ai-core",
|
||||
"model": "gpt-4o"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Model Selector 路由说明
|
||||
|
||||
AI-Core 使用基于用途的模型路由。模型配置从 `models.json` 加载,回退到 `.env` 环境变量。
|
||||
|
||||
### Purpose 常量
|
||||
|
||||
| Purpose | 常量 | 用途 |
|
||||
|---------|------|------|
|
||||
| `chat` | `PurposeChat` | 通用对话 |
|
||||
| `deep_thinking` | `PurposeDeepThinking` | 后台深度思考 |
|
||||
| `intent_analysis` | `PurposeIntentAnalysis` | 意图分析 |
|
||||
| `tool_calling` | `PurposeToolCalling` | 工具调用 |
|
||||
| `memory_extraction` | `PurposeMemoryExtraction` | 记忆提取 |
|
||||
|
||||
### 路由策略
|
||||
|
||||
1. `models.json` 存在 → 按 `routing.<purpose>.fallback_chain` 顺序尝试
|
||||
2. `models.json` 不存在 → 回退到 `.env` 的 `LLM_API_URL`/`LLM_API_KEY`/`LLM_MODEL`
|
||||
3. 全部失败 → 返回 `DefaultAdapter()` 使用 fallback model
|
||||
|
||||
### MemoryEntry 结构
|
||||
|
||||
| JSON 字段 | Go 类型 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `id` | string | UUID |
|
||||
| `user_id` | string | 所属用户 |
|
||||
| `content` | string | 完整内容 |
|
||||
| `summary` | string | 摘要 |
|
||||
| `category` | string | `user_preference`, `personal_info`, `conversation`, `knowledge`, `event`, `task`, `relationship` |
|
||||
| `priority` | int | 0=Temp, 1=Normal, 2=Important, 3=Core |
|
||||
| `importance` | int | 1-10 |
|
||||
| `keywords` | []string | 关键词标签 |
|
||||
| `session_id` | string | 来源会话 |
|
||||
| `source` | string | `conversation`, `thinking`, `manual` |
|
||||
| `access_count` | int | 访问次数 |
|
||||
| `last_access` | time | 最近访问 |
|
||||
| `created_at` | time | 创建时间 |
|
||||
| `updated_at` | time | 更新时间 |
|
||||
| `expires_at` | *time | 临时记忆过期(可空) |
|
||||
@@ -0,0 +1,178 @@
|
||||
# IoT Debug Service API
|
||||
|
||||
**Base URL:** `http://<host>:8083` | **Auth:** 无
|
||||
|
||||
模拟 IoT 设备的调试服务,预置 8 个设备用于开发和测试。所有状态存储在内存中,重启后重置。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [GET /api/v1/health](#1-get-apiv1health)
|
||||
2. [GET /api/v1/devices](#2-get-apiv1devices)
|
||||
3. [GET /api/v1/devices/:id](#3-get-apiv1devicesid)
|
||||
4. [GET /api/v1/devices/:id/history](#4-get-apiv1devicesidhistory)
|
||||
5. [POST /api/v1/devices/:id/toggle](#5-post-apiv1devicesidtoggle)
|
||||
6. [POST /api/v1/devices/:id/set](#6-post-apiv1devicesidset)
|
||||
|
||||
---
|
||||
|
||||
## 预置设备
|
||||
|
||||
| ID | 名称 | 类型 | 默认状态 |
|
||||
|----|------|------|----------|
|
||||
| `light-livingroom` | 客厅灯 | light | off, brightness=0 |
|
||||
| `light-bedroom` | 卧室灯 | light | off, brightness=0 |
|
||||
| `ac-livingroom` | 客厅空调 | ac | off, temperature=26 |
|
||||
| `ac-bedroom` | 卧室空调 | ac | off, temperature=26 |
|
||||
| `curtain-livingroom` | 客厅窗帘 | curtain | closed, position=0 |
|
||||
| `sensor-temperature` | 温度传感器 | sensor | value=25.5, unit=celsius |
|
||||
| `sensor-humidity` | 湿度传感器 | sensor | value=60.0, unit=percent |
|
||||
| `lock-door` | 智能门锁 | lock | locked |
|
||||
|
||||
---
|
||||
|
||||
## 数据模型
|
||||
|
||||
### Device
|
||||
|
||||
| 字段 | 类型 | 适用类型 | 说明 |
|
||||
|------|------|----------|------|
|
||||
| `id` | string | 全部 | 设备 ID |
|
||||
| `name` | string | 全部 | 设备名称 |
|
||||
| `type` | string | 全部 | `light`, `ac`, `curtain`, `sensor`, `lock` |
|
||||
| `status` | string | 全部 | `on`/`off`, `open`/`closed`, `locked`/`unlocked` |
|
||||
| `brightness` | int | light | 0-100 |
|
||||
| `color` | string | light | 颜色标识 |
|
||||
| `temperature` | float64 | ac | 设定温度 |
|
||||
| `mode` | string | ac | `cool`, `heat`, `auto` |
|
||||
| `position` | int | curtain | 0-100 |
|
||||
| `value` | float64 | sensor | 传感器读数 |
|
||||
| `unit` | string | sensor | `celsius`, `percent` |
|
||||
| `battery` | int | lock | 电池百分比 |
|
||||
| `last_updated` | string | 全部 | RFC3339 时间戳 |
|
||||
|
||||
### HistoryEntry
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `timestamp` | string | RFC3339 |
|
||||
| `field` | string | 变更字段名 |
|
||||
| `old_value` | string | 旧值 |
|
||||
| `new_value` | string | 新值 |
|
||||
|
||||
---
|
||||
|
||||
## 1. GET /api/v1/health
|
||||
|
||||
```json
|
||||
{ "status": "ok", "service": "iot-debug-service" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. GET /api/v1/devices — 设备列表
|
||||
|
||||
`history` 字段在列表中始终为 null。
|
||||
|
||||
```json
|
||||
{
|
||||
"devices": [ Device, ... ],
|
||||
"total": 8
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /api/v1/devices/:id — 设备详情
|
||||
|
||||
含最近 10 条 `history`。
|
||||
|
||||
```json
|
||||
{
|
||||
"device": {
|
||||
"id": "light-livingroom",
|
||||
"name": "客厅灯",
|
||||
"type": "light",
|
||||
"status": "off",
|
||||
"brightness": 0,
|
||||
"color": "warm_white",
|
||||
"last_updated": "2024-01-01T12:00:00Z",
|
||||
"history": [
|
||||
{ "timestamp": "2024-01-01T12:00:00Z", "field": "status", "old_value": "on", "new_value": "off" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**404:** `{"error":"设备 {id} 不存在"}`
|
||||
|
||||
---
|
||||
|
||||
## 4. GET /api/v1/devices/:id/history — 设备历史
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "string",
|
||||
"history": [ HistoryEntry, ... ]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. POST /api/v1/devices/:id/toggle — 切换状态
|
||||
|
||||
**请求体:** 空。
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "device": Device, "action": "toggled" }
|
||||
```
|
||||
|
||||
### 行为
|
||||
|
||||
| 设备类型 | 行为 |
|
||||
|----------|------|
|
||||
| light | on ↔ off。off 时 brightness=0,on 时 brightness=80 |
|
||||
| ac | on ↔ off |
|
||||
| curtain | closed (position=0) ↔ open (position=100) |
|
||||
| lock | locked ↔ unlocked |
|
||||
| sensor | **不支持**,返回错误 |
|
||||
|
||||
---
|
||||
|
||||
## 6. POST /api/v1/devices/:id/set — 设置属性
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{ "field": "brightness", "value": 80 }
|
||||
```
|
||||
|
||||
### 有效 field/value 组合
|
||||
|
||||
| field | value | 适用设备 | 说明 |
|
||||
|-------|-------|----------|------|
|
||||
| `status` / `power` | `"on"`/`"off"`/`"open"`/`"closed"`/`"locked"`/`"unlocked"` | 除 sensor | 中文 `"开"`/`"关"` 也支持 |
|
||||
| `status` / `power` | `true`/`false` | 除 sensor | true→on, false→off |
|
||||
| `status` / `power` | 数字 | 除 sensor | 0→off, 非0→on |
|
||||
| `temperature` | number | ac | — |
|
||||
| `brightness` | int 0-100 | light | — |
|
||||
| `position` | int 0-100 | curtain | — |
|
||||
| `mode` | `"cool"`/`"heat"`/`"auto"` | ac | — |
|
||||
| `color` | string | light | 如 `"warm_white"`, `"colorful"` |
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "device": Device, "action": "set_brightness" }
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 错误体 |
|
||||
|--------|--------|
|
||||
| 400 | `{"error":"设备 {id} 不存在"}` |
|
||||
| 400 | `{"error":"无效的状态值: ..."}` |
|
||||
| 400 | `{"error":"temperature 需要数字值"}` |
|
||||
| 400 | `{"error":"设备 {name} (类型 {type}) 不支持温度调节"}` |
|
||||
| 400 | `{"error":"不支持的属性: {field}"}` |
|
||||
| 400 | `{"error":"请求格式错误"}` |
|
||||
@@ -0,0 +1,298 @@
|
||||
# Memory-Service API
|
||||
|
||||
**Base URL:** `http://<host>:8094` | **Auth:** 无(按 `user_id` 隔离数据)
|
||||
|
||||
记忆服务负责长期记忆的存储、检索、合并、衰减以及后台思考日志记录。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [数据模型](#数据模型)
|
||||
2. [POST /api/v1/memories — 创建记忆](#1-post-apiv1memories)
|
||||
3. [GET /api/v1/memories — 记忆列表](#2-get-apiv1memories)
|
||||
4. [GET /api/v1/memories/:id — 获取记忆](#3-get-apiv1memoriesid)
|
||||
5. [PUT /api/v1/memories/:id — 更新记忆](#4-put-apiv1memoriesid)
|
||||
6. [DELETE /api/v1/memories/:id — 删除记忆](#5-delete-apiv1memoriesid)
|
||||
7. [POST /api/v1/memories/query — 搜索记忆](#6-post-apiv1memoriesquery)
|
||||
8. [POST /api/v1/memories/consolidate — 合并记忆](#7-post-apiv1memoriesconsolidate)
|
||||
9. [POST /api/v1/memories/decay — 记忆衰减](#8-post-apiv1memoriesdecay)
|
||||
10. [GET /api/v1/memories/categories — 分类统计](#9-get-apiv1memoriescategories)
|
||||
11. [POST /api/v1/thinking — 记录思考](#10-post-apiv1thinking)
|
||||
12. [GET /api/v1/thinking — 思考列表](#11-get-apiv1thinking)
|
||||
13. [GET /api/v1/thinking/:id — 思考详情](#12-get-apiv1thinkingid)
|
||||
14. [GET /api/v1/thinking/stats — 思考统计](#13-get-apiv1thinkingstats)
|
||||
15. [GET /api/v1/health — 健康检查](#14-get-apiv1health)
|
||||
|
||||
---
|
||||
|
||||
## 数据模型
|
||||
|
||||
### MemoryEntry
|
||||
|
||||
| JSON 字段 | Go 类型 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `id` | string | UUID 主键 |
|
||||
| `user_id` | string | 所属用户 (max 64 chars) |
|
||||
| `content` | string | 完整记忆文本 |
|
||||
| `summary` | string | 简短摘要 |
|
||||
| `category` | string | 7 种: `user_preference`, `personal_info`, `conversation`, `knowledge`, `event`, `task`, `relationship` |
|
||||
| `priority` | int | 0=Temp, 1=Normal, 2=Important, 3=Core (写入时 clamp [0,10]) |
|
||||
| `importance` | int | 1-10 (默认 5) |
|
||||
| `keywords` | []string | 关键词标签 |
|
||||
| `session_id` | string | 来源会话 ID |
|
||||
| `source` | string | `conversation`, `manual`, `merged`, `consolidated` |
|
||||
| `access_count` | int | 访问次数 |
|
||||
| `last_access` | string | 最近访问时间 (RFC3339) |
|
||||
| `created_at` | string | 创建时间 |
|
||||
| `updated_at` | string | 更新时间 |
|
||||
| `expires_at` | string/null | 临时记忆过期时间 (omitempty) |
|
||||
|
||||
### ThinkingLog
|
||||
|
||||
| JSON 字段 | Go 类型 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `id` | string | UUID |
|
||||
| `user_id` | string | 所属用户 |
|
||||
| `content` | string | 思考日志全文 |
|
||||
| `tool_calls` | string | JSON 数组 (字符串存储) |
|
||||
| `tool_call_count` | int | 工具调用次数 |
|
||||
| `content_length` | int | 内容字符长度 |
|
||||
| `created_at` | string | 创建时间 (RFC3339) |
|
||||
|
||||
### ThinkingStats
|
||||
|
||||
| JSON 字段 | Go 类型 | 说明 |
|
||||
|-----------|---------|------|
|
||||
| `total_logs` | int | 思考日志总数 |
|
||||
| `total_tool_calls` | int | 工具调用总次数 |
|
||||
| `avg_content_length` | float64 | 平均内容长度 |
|
||||
| `latest_at` | string | 最近日志时间 |
|
||||
|
||||
---
|
||||
|
||||
## 1. POST /api/v1/memories — 创建记忆
|
||||
|
||||
创建时自动去重:与已有记忆的 Jaccard/双字母组相似度 >= 0.75 时,合并内容到已有条目而非新建。
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"user_id": "string (必填)",
|
||||
"content": "string (必填)",
|
||||
"summary": "string",
|
||||
"category": "string (默认 knowledge, 七选一)",
|
||||
"priority": 1,
|
||||
"importance": 5,
|
||||
"keywords": ["tag1", "tag2"],
|
||||
"session_id": "string",
|
||||
"source": "string (默认 manual)"
|
||||
}
|
||||
|
||||
// 响应 201
|
||||
{ "status": "saved", "memory": MemoryEntry }
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 错误 |
|
||||
|--------|------|
|
||||
| 400 | `缺少 user_id 或 content` |
|
||||
| 400 | `请求格式错误: ...` |
|
||||
| 405 | `method not allowed` |
|
||||
| 500 | 数据库错误 |
|
||||
|
||||
---
|
||||
|
||||
## 2. GET /api/v1/memories — 记忆列表
|
||||
|
||||
### Query 参数
|
||||
|
||||
| 参数 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `user_id` | 是 | — | 用户 ID |
|
||||
| `category` | 否 | 全部 | 分类过滤 |
|
||||
| `min_importance` | 否 | 0 | 最低重要度 |
|
||||
| `limit` | 否 | 50 | 最大条数 |
|
||||
|
||||
### 响应 200
|
||||
|
||||
```json
|
||||
{ "user_id": "string", "memories": [ MemoryEntry, ... ], "total": 10 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /api/v1/memories/:id — 获取记忆
|
||||
|
||||
访问后异步递增 `access_count`。
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "memory": MemoryEntry }
|
||||
|
||||
// 错误 404
|
||||
{ "error": "记忆不存在" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PUT /api/v1/memories/:id — 更新记忆
|
||||
|
||||
Body 所有字段可选 (partial update)。`user_id` 和 `session_id` 不可修改。
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"content": "新内容",
|
||||
"summary": "新摘要",
|
||||
"category": "knowledge",
|
||||
"priority": 2,
|
||||
"importance": 8,
|
||||
"keywords": ["新标签"],
|
||||
"source": "manual"
|
||||
}
|
||||
|
||||
// 响应 200
|
||||
{ "status": "updated", "memory_id": "uuid" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. DELETE /api/v1/memories/:id — 删除记忆
|
||||
|
||||
不检查存在性,始终返回成功。
|
||||
|
||||
```json
|
||||
{ "status": "deleted", "memory_id": "uuid" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. POST /api/v1/memories/query — 搜索记忆
|
||||
|
||||
内部使用 SQL ILIKE + 应用层子串匹配在 content/summary/keywords 中搜索,按 importance 降序排序并去重。
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"user_id": "string (必填)",
|
||||
"query_text": "关键词",
|
||||
"category": "knowledge",
|
||||
"min_importance": 3,
|
||||
"limit": 10
|
||||
}
|
||||
|
||||
// 响应 200
|
||||
{ "user_id": "string", "query": "关键词", "memories": [ MemoryEntry ], "total": 3 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. POST /api/v1/memories/consolidate — 合并记忆
|
||||
|
||||
查找 Jaccard 相似度 >= 0.75 的记忆对,合并关键词、增加 importance、删除重复条目。
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{ "user_id": "string (必填)" }
|
||||
|
||||
// 响应 200
|
||||
{ "status": "consolidated", "user_id": "string", "merged": 3, "message": "记忆整理完成" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. POST /api/v1/memories/decay — 记忆衰减
|
||||
|
||||
两阶段操作:
|
||||
1. **降级:** access_count < 3、最近 30 天未访问、importance < 3、priority > 0、非 personal_info/user_preference → priority -1
|
||||
2. **删除:** priority = 0、access_count = 0、最近 14 天未访问
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{ "user_id": "string (必填)" }
|
||||
|
||||
// 响应 200
|
||||
{ "status": "decayed", "user_id": "string", "decayed": 5, "deleted": 2, "message": "记忆衰减完成" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. GET /api/v1/memories/categories — 分类统计
|
||||
|
||||
`?user_id=xxx`
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{
|
||||
"user_id": "string",
|
||||
"categories": {
|
||||
"knowledge": 12,
|
||||
"user_preference": 3,
|
||||
"conversation": 8
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. POST /api/v1/thinking — 记录思考
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"user_id": "string (默认 admin)",
|
||||
"content": "string (必填)",
|
||||
"tool_calls": "string (默认 [])",
|
||||
"tool_call_count": 0,
|
||||
"content_length": 0
|
||||
}
|
||||
|
||||
// 响应 201
|
||||
{ "status": "saved", "thinking": ThinkingLog }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. GET /api/v1/thinking — 思考列表
|
||||
|
||||
`?user_id=xxx&limit=20&offset=0`
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "logs": [ ThinkingLog ], "total": 5 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. GET /api/v1/thinking/:id — 思考详情
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "thinking": ThinkingLog }
|
||||
|
||||
// 错误 404
|
||||
{ "error": "思考日志不存在" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. GET /api/v1/thinking/stats — 思考统计
|
||||
|
||||
`?user_id=xxx` (可选,缺省返回全部用户)
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{ "total_logs": 100, "total_tool_calls": 250, "avg_content_length": 512.3, "latest_at": "2024-01-01T12:00:00Z" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. GET /api/v1/health — 健康检查
|
||||
|
||||
```json
|
||||
{ "status": "ok", "service": "memory-service" }
|
||||
// 或数据库不可用时
|
||||
{ "status": "degraded", "service": "memory-service" }
|
||||
```
|
||||
@@ -0,0 +1,297 @@
|
||||
# Tool-Engine API
|
||||
|
||||
**Base URL:** `http://<host>:8092` | **Auth:** 无
|
||||
|
||||
工具引擎注册了 13 个内置工具,支持单次和批量执行,可选数据库持久化的调用日志。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [GET /api/v1/health](#1-get-apiv1health)
|
||||
2. [GET /api/v1/tools](#2-get-apiv1tools)
|
||||
3. [GET /api/v1/tools/:name](#3-get-apiv1toolsname)
|
||||
4. [POST /api/v1/tools/:name/execute](#4-post-apiv1toolsnameexecute)
|
||||
5. [POST /api/v1/tools/execute — 批量执行](#5-post-apiv1toolsexecute)
|
||||
6. [GET /api/v1/tools/calls](#6-get-apiv1toolscalls)
|
||||
7. [GET /api/v1/tools/calls/stats](#7-get-apiv1toolscallsstats)
|
||||
8. [已注册工具参考](#8-已注册工具参考)
|
||||
|
||||
---
|
||||
|
||||
## 数据模型
|
||||
|
||||
### ToolDefinition
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `name` | string | 工具标识 |
|
||||
| `description` | string | 功能描述 |
|
||||
| `parameters` | object | JSON Schema 参数定义 |
|
||||
|
||||
### CallLogRecord
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | int | 数据库自增 ID |
|
||||
| `call_id` | string | UUID v4 |
|
||||
| `tool_name` | string | 工具名 |
|
||||
| `arguments` | json.RawMessage | 调用参数 |
|
||||
| `output` | string | 输出文本 |
|
||||
| `error` | string | 错误信息 |
|
||||
| `success` | bool | 是否成功 |
|
||||
| `duration_ms` | int | 执行耗时 |
|
||||
| `user_id` | string | 调用用户 |
|
||||
| `session_id` | string | 调用会话 |
|
||||
| `created_at` | string | 时间戳 |
|
||||
|
||||
### ToolCallCount
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `tool_name` | string | 工具名 |
|
||||
| `count` | int | 调用总数 |
|
||||
| `success_count` | int | 成功次数 |
|
||||
| `fail_count` | int | 失败次数 |
|
||||
| `avg_duration_ms` | float64 | 平均耗时 |
|
||||
|
||||
---
|
||||
|
||||
## 1. GET /api/v1/health
|
||||
|
||||
```json
|
||||
{ "status": "ok", "service": "tool-engine" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. GET /api/v1/tools — 工具列表
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": [ ToolDefinition, ... ],
|
||||
"total": 13
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /api/v1/tools/:name — 工具详情
|
||||
|
||||
```json
|
||||
{ "name": "calculator", "description": "...", "parameters": { ... } }
|
||||
```
|
||||
|
||||
**404:** `{"error":"工具 {name} 不存在"}`
|
||||
|
||||
---
|
||||
|
||||
## 4. POST /api/v1/tools/:name/execute — 执行工具
|
||||
|
||||
### 请求
|
||||
|
||||
```json
|
||||
{ "arguments": { "expression": "3 + 4 * 2" } }
|
||||
```
|
||||
|
||||
### Query 参数 (可选,用于日志)
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| `user_id` | 调用用户 |
|
||||
| `session_id` | 调用会话 |
|
||||
|
||||
### 响应 200
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "",
|
||||
"output": "11",
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
- 成功: `output` 有值,`error` 为空字符串
|
||||
- 失败: `output` 可能为空,`error` 有值 —— **仍然返回 HTTP 200**,调用方需检查 `error` 字段
|
||||
|
||||
**500:** `{"error":"执行工具 {name} 失败: ..."}` — 工具注册表未找到(非参数错误)
|
||||
|
||||
---
|
||||
|
||||
## 5. POST /api/v1/tools/execute — 批量执行
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"calls": [
|
||||
{ "id": "call-1", "name": "calculator", "arguments": { "expression": "3+4" } },
|
||||
{ "id": "call-2", "name": "datetime", "arguments": { "action": "now" } }
|
||||
]
|
||||
}
|
||||
|
||||
// 响应 200
|
||||
{
|
||||
"results": [
|
||||
{ "id": "call-1", "output": "7", "error": "" },
|
||||
{ "id": "call-2", "output": "2024-01-01 12:00:00", "error": "" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| 状态码 | 错误 |
|
||||
|--------|------|
|
||||
| 400 | `{"error":"calls 不能为空"}` |
|
||||
| 400 | `{"error":"请求体格式错误: ..."}` |
|
||||
|
||||
---
|
||||
|
||||
## 6. GET /api/v1/tools/calls — 调用日志
|
||||
|
||||
需要 `DB_URL` 环境变量。未配置数据库时返回空结果。
|
||||
|
||||
### Query 参数
|
||||
|
||||
| 参数 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `tool_name` | 全部 | 按工具名过滤 |
|
||||
| `page` | 1 | 页码 |
|
||||
| `limit` | 20 (max 100) | 每页条数 |
|
||||
|
||||
### 响应 200
|
||||
|
||||
```json
|
||||
{
|
||||
"calls": [ CallLogRecord, ... ],
|
||||
"total": 150,
|
||||
"page": 1,
|
||||
"limit": 20,
|
||||
"total_pages": 8
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. GET /api/v1/tools/calls/stats — 调用统计
|
||||
|
||||
```json
|
||||
{
|
||||
"total_calls": 150,
|
||||
"success_count": 140,
|
||||
"fail_count": 10,
|
||||
"success_rate": 93.33,
|
||||
"avg_duration_ms": 45.2,
|
||||
"by_tool": [
|
||||
{ "tool_name": "calculator", "count": 80, "success_count": 78, "fail_count": 2, "avg_duration_ms": 12.3 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
未配置数据库时全返回 0。
|
||||
|
||||
---
|
||||
|
||||
## 8. 已注册工具参考
|
||||
|
||||
### calculator — 数学计算
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `expression` | 是 | 数学表达式 (如 `3 + 4 * 2`) |
|
||||
|
||||
### datetime — 日期时间
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `now`, `format`, `add`, `diff`, `timezone_list` |
|
||||
| `format` | 否 | 时间格式 (action=format 时) |
|
||||
| `timezone` | 否 | 时区 |
|
||||
| `date` | 否 | 日期 |
|
||||
| `duration` | 否 | 时长 (action=add 时) |
|
||||
| `date2` | 否 | 第二个日期 (action=diff 时) |
|
||||
|
||||
### text — 文本处理
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `count`, `summarize`, `translate`, `extract` |
|
||||
| `text` | 是 | 文本内容 |
|
||||
| `target_lang` | 否 | 目标语言 (translate) |
|
||||
| `pattern` | 否 | 提取模式 (extract) |
|
||||
|
||||
### crypto — 加密编码
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `hash`, `base64_encode`, `base64_decode`, `url_encode`, `url_decode` |
|
||||
| `input` | 是 | 输入文本 |
|
||||
| `algorithm` | 否 | hash 算法: `md5`, `sha1`, `sha256`, `sha512` (默认 sha256) |
|
||||
|
||||
### random — 随机生成
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `number`, `uuid`, `password`, `pick`, `shuffle` |
|
||||
| `min` | 否 | 最小值 (number) |
|
||||
| `max` | 否 | 最大值 (number) |
|
||||
| `length` | 否 | 长度 (password) |
|
||||
| `items` | 否 | 选项数组 (pick/shuffle) |
|
||||
| `count` | 否 | 选取数量 (pick) |
|
||||
|
||||
### markdown — Markdown 处理
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `to_html`, `to_text`, `extract_links`, `extract_code`, `table_of_contents` |
|
||||
| `markdown` | 是 | Markdown 原文 |
|
||||
|
||||
### json_ops — JSON 操作
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `parse`, `query`, `validate` |
|
||||
| `json_string` | 是 | JSON 字符串 |
|
||||
| `path` | 否 | 查询路径 (query) |
|
||||
|
||||
### file_ops — 文件操作
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `read`, `write`, `list`, `exists`, `delete` |
|
||||
| `path` | 是 | 文件路径 |
|
||||
| `content` | 否 | 写入内容 (write) |
|
||||
|
||||
### http_request — HTTP 请求
|
||||
|
||||
| 参数 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `url` | 是 | — | 请求 URL |
|
||||
| `method` | 否 | GET | HTTP 方法 |
|
||||
| `headers` | 否 | {} | 请求头 |
|
||||
| `body` | 否 | — | 请求体 |
|
||||
| `timeout` | 否 | 30s | 超时秒数 |
|
||||
|
||||
### web_search — 网页搜索
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `query` | 是 | 搜索关键词 |
|
||||
|
||||
### web_fetch — 网页抓取
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `url` | 是 | 目标 URL |
|
||||
|
||||
### iot_query — IoT 设备查询
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `device_id` | 否 | 设备 ID (缺省返回全部) |
|
||||
|
||||
### iot_control — IoT 设备控制
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `device_id` | 是 | 设备 ID (别名 `entity_id`) |
|
||||
| `action` | 是 | `toggle`, `turn_on`, `turn_off`, `set_temperature`, `set_brightness`, `set_position`, `set_mode`, `set_color` (支持中文名) |
|
||||
| `value` | 否 | 值 (set_* 动作时需要) |
|
||||
@@ -0,0 +1,231 @@
|
||||
# Voice-Service API
|
||||
|
||||
**Base URL:** `http://<host>:8093` | **Auth:** 无
|
||||
|
||||
语音服务封装两层引擎:
|
||||
- **STT (语音转文字):** DashScope `qwen3-asr-flash-realtime` (主) + 本地 Whisper (备)
|
||||
- **TTS (文字转语音):** edge-tts (主) + espeak-ng (备)
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [POST /api/v1/transcribe — 语音转文字](#1-post-apiv1transcribe)
|
||||
2. [POST /api/v1/tts/synthesize — 文字转语音](#2-post-apiv1ttssynthesize)
|
||||
3. [GET /api/v1/tts/voices — 发音人列表](#3-get-apiv1ttsvoices)
|
||||
4. [GET /api/v1/health — 健康检查](#4-get-apiv1health)
|
||||
5. [GET /api/v1/status — 服务状态](#5-get-apiv1status)
|
||||
6. [GET /api/v1/tts/status — TTS 状态](#6-get-apiv1ttsstatus)
|
||||
7. [WebSocket GET /api/v1/stt/stream — 流式 STT](#7-websocket-get-apiv1sttstream)
|
||||
|
||||
---
|
||||
|
||||
## 1. POST /api/v1/transcribe — 语音转文字
|
||||
|
||||
**Content-Type:** `multipart/form-data` | **Max body:** 10 MB
|
||||
|
||||
### 表单字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `audio` | file | 是 | 音频文件。格式从扩展名推断:wav/mp3/ogg/flac/m4a |
|
||||
| `language` | string | 否 | 默认 `"zh"`。可选: `zh`, `en`, `ja`, `ko`, `auto` |
|
||||
|
||||
### 响应 200
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"text": "转录结果文本",
|
||||
"language": "zh",
|
||||
"duration_ms": 1234
|
||||
}
|
||||
```
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 错误体 |
|
||||
|--------|--------|
|
||||
| 400 | `{"error":"文件过大或解析失败,最大支持 10MB"}` |
|
||||
| 400 | `{"error":"缺少 audio 文件字段"}` |
|
||||
| 400 | `{"error":"音频文件为空"}` |
|
||||
| 400 | `{"error":"不支持的音频格式: <ext>,支持的格式: WAV, MP3, OGG, FLAC, M4A"}` |
|
||||
| 405 | `{"error":"method not allowed"}` |
|
||||
| 500 | `{"error":"读取音频文件失败"}` |
|
||||
| 500 | `{"success":false,"error":"<engine error>"}` |
|
||||
|
||||
---
|
||||
|
||||
## 2. POST /api/v1/tts/synthesize — 文字转语音
|
||||
|
||||
**Content-Type:** `application/json`
|
||||
|
||||
### 请求
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "你好世界 (必填)",
|
||||
"voice": "zh-CN-XiaoxiaoNeural (默认)",
|
||||
"rate": "+0% (默认,如 +20%/-20%)"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应 200 — 原始音频流
|
||||
|
||||
- **Content-Type:** `audio/mpeg` (edge-tts) 或 `audio/wav` (espeak-ng/fallback)
|
||||
- **Content-Disposition:** `inline; filename=synthesized.mp3`
|
||||
|
||||
引擎回退链: edge-tts (mp3) → espeak-ng (wav) → silent WAV
|
||||
|
||||
### 错误
|
||||
|
||||
| 状态码 | 错误体 |
|
||||
|--------|--------|
|
||||
| 400 | `{"error":"请求体解析失败: ..."}` |
|
||||
| 400 | `{"error":"text 字段不能为空"}` |
|
||||
| 405 | `{"error":"method not allowed"}` |
|
||||
| 500 | `{"error":"TTS 合成失败: ..."}` |
|
||||
|
||||
---
|
||||
|
||||
## 3. GET /api/v1/tts/voices — 发音人列表
|
||||
|
||||
```json
|
||||
// 响应 200
|
||||
{
|
||||
"voices": [
|
||||
{ "name": "zh-CN-XiaoxiaoNeural", "display_name": "晓晓 (女声)", "gender": "Female", "locale": "zh-CN" },
|
||||
{ "name": "zh-CN-YunxiNeural", "display_name": "云希 (男声)", "gender": "Male", "locale": "zh-CN" },
|
||||
{ "name": "zh-CN-XiaoyiNeural", "display_name": "晓伊 (女声)", "gender": "Female", "locale": "zh-CN" }
|
||||
],
|
||||
"count": 3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. GET /api/v1/health — 健康检查
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "voice-service",
|
||||
"stt": {
|
||||
"available": true,
|
||||
"primary": "dashscope",
|
||||
"dashscope": { "available": true, "model": "qwen3-asr-flash-realtime", "provider": "dashscope" },
|
||||
"whisper": {
|
||||
"available": true,
|
||||
"binary_available": true,
|
||||
"model_loaded": true,
|
||||
"model_name": "ggml-small.bin"
|
||||
},
|
||||
"default_language": "zh",
|
||||
"supported_languages": ["zh","en","ja","ko","auto"]
|
||||
},
|
||||
"tts": {
|
||||
"available": true,
|
||||
"edge_tts": true,
|
||||
"espeak_ng": false,
|
||||
"engine": "edge-tts",
|
||||
"default_voice": "zh-CN-XiaoxiaoNeural",
|
||||
"builtin_voices": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 状态字段说明
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `stt.available` | DashScope 或 Whisper 至少一个可用 |
|
||||
| `stt.dashscope.available` | DashScope API Key 已配置 |
|
||||
| `stt.whisper.available` | Whisper 二进制 + 模型文件均存在 |
|
||||
| `tts.available` | 至少一个 TTS 引擎可用 |
|
||||
| `tts.engine` | 当前激活引擎: `edge-tts`, `espeak-ng`, `fallback (silent WAV)`, `none` |
|
||||
|
||||
---
|
||||
|
||||
## 5. GET /api/v1/status — 服务状态
|
||||
|
||||
同 `/health` 但无顶层 `status` 字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"service": "voice-service",
|
||||
"stt": { ... }, // 同 health.stt
|
||||
"tts": { ... } // 同 health.tts
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. GET /api/v1/tts/status — TTS 单独状态
|
||||
|
||||
```json
|
||||
{
|
||||
"service": "voice-service",
|
||||
"tts": {
|
||||
"available": true,
|
||||
"edge_tts": true,
|
||||
"espeak_ng": false,
|
||||
"engine": "edge-tts",
|
||||
"default_voice": "zh-CN-XiaoxiaoNeural",
|
||||
"builtin_voices": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. WebSocket GET /api/v1/stt/stream — 流式 STT
|
||||
|
||||
**Query 参数:** `?language=zh&format=pcm` (language 默认 zh, format 默认 pcm)
|
||||
**Read deadline:** 300s
|
||||
|
||||
### 客户端 → 服务端
|
||||
|
||||
**Binary 帧:** 原始 PCM 音频 (16-bit LE, 16000Hz, mono)。每帧通过 `input_audio_buffer.append` 转发到 DashScope。
|
||||
|
||||
**JSON 控制帧:**
|
||||
|
||||
```json
|
||||
{ "action": "stop" }
|
||||
// 请求结束会话。服务端返回 done 后关闭。
|
||||
|
||||
{ "language": "en" }
|
||||
// 动态切换识别语言。
|
||||
```
|
||||
|
||||
### 服务端 → 客户端 (JSON 文本帧)
|
||||
|
||||
**result** — 识别结果
|
||||
```json
|
||||
{
|
||||
"type": "result",
|
||||
"text": "识别文本片段",
|
||||
"isFinal": true
|
||||
}
|
||||
```
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `isFinal: true` | VAD 端点检测到的完整句子 |
|
||||
| `isFinal: false` | 中间增量 (delta) |
|
||||
|
||||
**error**
|
||||
```json
|
||||
{ "type": "error", "error": "错误描述" }
|
||||
```
|
||||
|
||||
**done** — 响应 stop
|
||||
```json
|
||||
{ "type": "done", "action": "stop" }
|
||||
```
|
||||
|
||||
### 连接生命周期
|
||||
|
||||
1. HTTP 升级请求 → 验证 STT 引擎可用性 (不可用返回 503)
|
||||
2. 建立 DashScope realtime 会话 (`session.created` → `session.update` → `session.updated`)
|
||||
3. 客户端发送 binary PCM 帧 → 服务端 base64 编码后 `input_audio_buffer.append`
|
||||
4. DashScope VAD 自动检测 → `conversation.item.input_audio_transcription.completed` → 转发 result
|
||||
5. 客户端发送 `{"action":"stop"}` → 服务端 `session.finish` → 关闭连接
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user