www_site/docs/API_CONTRACT.md

145 lines
6.4 KiB
Markdown
Raw Normal View History

2026-09-08 07:29:09 +00:00
# TTS 接口契约与适配边界
状态Phase 0 审计基线
审计日期2026-09-08
重要说明:本文件将“已核实事实”和“目标契约”分开。当前没有在仓库或测试机中发现可调用的现有 TTS 接口;目标样例不能作为现有能力证明。
## 1. 现有接口事实
| 项目 | 结论 | 证据/处理 |
| --- | --- | --- |
| 上游地址 | 待确认 | 仓库无配置;测试机仅监听 SSH/DNS |
| 协议和方法 | 待确认 | 未发现 OpenAPI、客户端或请求样例 |
| 鉴权 | 待确认 | 未发现密钥名、Token 方案或服务账号 |
| 输入文本字段 | 待确认 | 规划只规定业务层语义,不代表上游字段 |
| 音色 ID/语言 | 待确认 | 未发现音色清单 |
| 参数范围 | 待确认 | 未发现 speed/pitch/format 等上游定义 |
| 同步/异步 | 待确认 | 未发现任务 ID 或结果轮询协议 |
| 结果格式 | 待确认 | 未发现音频 MIME、字节流、URL 或 JSON 约定 |
| 错误语义 | 待确认 | 未发现状态码/错误码映射 |
| 超时和大小限制 | 待确认 | 由联调和容量测试确定,不能凭规划虚构 |
| 幂等支持 | 待确认 | 不假设上游支持;业务层必须先自行防重复结算 |
真实请求测试因缺少授权上游地址、测试凭据和测试文本而未执行。不得将此状态写成“接口不可用”或“接口已通”,正确表述是“接口未核实”。
## 2. 业务层目标契约
以下是依据 `V1_PLAN.md` 第 9、10 章拟定的业务层边界。它是 Phase 2/3 的实现输入,不是上游协议。
### 2.1 公开业务 API
| 方法与路径 | 用途 | 认证 |
| --- | --- | --- |
| `GET /api/v1/tts/voices` | 返回当前可用音色及安全参数元数据 | 可公开,实际策略待定 |
| `POST /api/v1/tts/tasks` | 创建 TTS 任务,返回 `202``task_id` | 登录、限流、额度和并发校验 |
| `GET /api/v1/tts/tasks` | 当前用户分页历史 | 当前用户 |
| `GET /api/v1/tts/tasks/{id}` | 查询状态和结果元数据 | 所有者或管理员 |
| `GET /api/v1/tts/tasks/{id}/audio` | 受控播放 | 所有者或管理员 |
| `GET /api/v1/tts/tasks/{id}/download` | 受控下载 | 所有者或管理员 |
认证、账户和管理接口以 `V1_PLAN.md` 第 9 章为准。业务层统一使用同源 `/api/v1`,浏览器不直接访问上游 TTS 地址。
### 2.2 创建任务请求
下面是脱敏的目标样例,仅用于说明业务层字段;字段名、音色和参数必须在上游联调后固定。
```json
{
"text": "待转换文本",
"voice_id": "configured-voice-id",
"parameters": {
"format": "mp3"
},
"idempotency_key": "client-generated-opaque-key"
}
```
服务端必须重新计算 Unicode 码点计量、校验文本长度/音色/参数/权益/并发和频率,不能信任客户端计数或隐藏字段。原始文本不进入普通业务日志。
### 2.3 创建成功响应
```json
{
"task_id": "uuid",
"status": "queued",
"text_length": 123,
"reserved_amount": 123,
"request_id": "request-id"
}
```
返回 `202 Accepted` 表示任务已持久化并冻结额度,不表示上游已成功生成音频。额度冻结和任务创建必须在同一数据库事务中完成。
### 2.4 状态响应
```json
{
"task_id": "uuid",
"status": "queued|running|succeeded|failed",
"text_length": 123,
"voice_id": "configured-voice-id",
"audio": {
"available": false,
"duration_ms": null,
"expires_at": null
},
"error": null,
"request_id": "request-id"
}
```
成功时 `audio` 只返回受控业务地址或短期授权结果,不返回存储桶内部路径。管理员默认不展开完整输入文本。
## 3. 适配器目标边界
`services/worker` 通过配置固定的上游主机和端点调用适配器;用户输入不能成为 URL、Host、路径或凭据。适配器负责
- 将业务层标准请求映射为真实上游请求,并从真实响应提取 provider task ID、音频数据/地址和计量信息。
- 对上游鉴权、连接超时、读取超时、响应大小、MIME 和音频可解析性做服务端校验。
- 将真实上游错误映射到内部错误码,不向浏览器泄露内部地址、密钥、模型路径或堆栈。
- 在上游语义明确时实现有限重试;超时且结果不明时先保留 `running` 并按 provider task ID 核对,禁止盲目重复生成。
- 将音频写入私有对象存储后,才允许任务转为 `succeeded` 并把冻结额度转为消费。
适配器不负责用户授权、额度决策、跨用户资源判断或 CMS 权限;这些由 API/业务服务负责。
## 4. 失败语义基线
以下是业务层目标分类,不是对未核实上游返回码的断言:
| 内部错误码 | HTTP 建议 | 处理 |
| --- | ---: | --- |
| `AUTH_REQUIRED` | 401 | 不创建任务,不冻结额度 |
| `FORBIDDEN` | 403 | 不泄露资源存在性 |
| `INVALID_INPUT` | 422 | 文本、音色或参数不合法 |
| `QUOTA_EXCEEDED` | 409 | 不创建任务,不产生负余额 |
| `RATE_LIMITED` | 429 | 返回安全的重试提示 |
| `UPSTREAM_UNAVAILABLE` | 503 | 按任务状态处理,不盲目重试不确定请求 |
| `UPSTREAM_REJECTED` | 502 | 记录脱敏上游分类,失败时释放冻结 |
| `AUDIO_PERSIST_FAILED` | 500/503 | 不标记成功,执行对账/释放策略 |
| `TASK_FAILED` | 500 | 任务失败,保留可追踪错误码 |
| `AUDIO_EXPIRED` | 410 | 保留历史元信息,不返回内部路径 |
错误响应统一使用:
```json
{
"error": {
"code": "INVALID_INPUT",
"message": "请求参数不可用",
"request_id": "request-id"
}
}
```
不记录密码、会话令牌、验证码、上游密钥或完整原始文本。
## 5. 待确认清单和验证顺序
1. 由服务负责人提供已授权的上游主机、端点、测试凭据注入方式和网络允许范围。
2. 获取真实 OpenAPI/接口文档或脱敏请求响应,确认同步/异步、任务查询、结果下载、音色、参数、错误和计量。
3. 确认上游是否支持幂等、取消、重试和 provider task ID 查询;不支持时由业务 Worker 承担任务恢复与防重复结算。
4. 在测试环境执行最小成功、参数拒绝、超时、上游失败、重复请求和响应不明测试;不得用 Mock 结果替代。
5. 依据真实结果固定 `TTSVoice`、`TTSTask`、错误映射、超时、重试、音频校验和额度计量配置。
在上述步骤完成前Phase 3 不得宣称“真实 TTS 已接入”。