www_site/docs/API_CONTRACT.md

145 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 已接入”。