# TTS 接口契约与适配边界 状态:Phase 0 审计基线,已补充旧 TTS 工程只读核查事实 审计日期:2026-09-08 重要说明:本文件将“已核实事实”和“目标契约”分开。已授权只读检查外部工程 `E:\RD\Kaotings\kts_site\KT26-0903_Big-TTS`,未复制或修改该工程。 ## 1. 现有接口事实 | 项目 | 结论 | 证据/处理 | | --- | --- | --- | | 上游地址 | 代码默认:`http://43.248.188.28:44480`,路径 `/v1/audio/speech` | `ReadMe.md` 和 `server.js` 初始 SQLite 配置;不是实际运行地址证明 | | 协议和方法 | `POST`,OpenAI 兼容 JSON 请求 | 旧工程 `/api/tts` 使用 `fetch` | | 鉴权 | 配置有 API Key 时发送 `Authorization: Bearer `;默认 Key 为空 | Key 只存旧工程服务端 SQLite,配置接口返回掩码 | | 输入文本字段 | `input` | 旧工程将业务文本映射为 `input` | | 音色 ID/语言 | `voice`;默认 `default`,逗号分隔配置;无真实语言清单 | 旧工程 `tts_config` 和前端 `/api/config` | | 参数范围 | `response_format`: `wav`/`mp3`;`speed`: `0.5` 至 `2.0`;文本 `1` 至 `5000` 字符 | `server.js` 服务端校验 | | 模型 | 默认 `qwen3-tts`,可由旧工程管理员配置 | `ReadMe.md`、`tts_config` | | 同步/异步 | 同步 | 单次 `fetch` 等待完整响应,无 task ID | | 结果格式 | 音频字节流;WAV `audio/wav`,MP3 `audio/mpeg` | 旧工程返回完整 `arrayBuffer` | | 错误语义 | 输入错误 `400`;未登录 `401`;上游非 2xx/超时统一 `502` | 旧工程业务层映射 | | 超时和大小限制 | 上游超时 `120000ms`;请求体最多 `1 MiB`;文本最多 `5000` 字符;未见上游响应大小限制 | `body()` 与 `AbortSignal.timeout(120000)` | | 幂等支持 | 未实现 | 无幂等键、provider task ID 或重复请求去重 | 代码契约已核实;对默认地址的真实最小文本联调返回 `401 Unauthorized`,说明地址可达但当前请求缺少有效鉴权。不能把代码默认值写成已确认的实际部署地址。当前测试服务器没有 TTS 监听端口。 旧工程自身的业务接口为:登录后 `GET /api/config` 获取模型/音色元数据,`POST /api/tts` 同步返回音频,`GET /api/history` 返回当前用户最多 100 条历史;管理员配置接口为 `/api/admin/config`。Phase 3 只复用上游边界,不复制旧工程用户体系或整套工程。 `www_site` 不复用旧工程的网页端管理员配置接口。上游主机、API Key、超时和相关秘密只由服务端环境配置注入;网站用户和管理员均不能通过网页修改上游连接配置。 ## 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 码点计量、校验文本长度/音色/参数/权益/并发和频率,不能信任客户端计数或隐藏字段。旧工程会把完整原始文本写入 SQLite 历史,Phase 3 不直接复制该隐私行为。 ### 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. 确认 `43.248.188.28:44480` 是否仍是获授权的测试上游;代码默认值不作为部署事实。 2. 提供该上游测试环境的 API Key 或其他鉴权凭据注入方式;本次无鉴权最小请求返回 `401`,未保存或输出响应内容。 3. 获取当前音色 ID、语言、参数和计量补充资料;旧工程只有 `default` 示例,没有真实清单。 4. 确认上游是否支持幂等、取消、重试和 provider task ID 查询;当前旧工程不提供这些能力。 5. 在测试环境执行最小成功、参数拒绝、超时、上游失败、重复请求和响应不明测试;不得用 Mock 结果替代。 6. 依据真实结果固定 `TTSVoice`、`TTSTask`、错误映射、超时、重试、音频校验和额度计量配置。 在上述步骤完成前,Phase 3 不得宣称“真实 TTS 已接入”。