文档
SoulDub 视频翻译 Agent API 参考
面向 Agent、后端服务和自动化脚本的 SoulDub 视频翻译 API 运行时参考。
适用对象:自动化 SoulDub 视频翻译的 Agent、后端服务和脚本。
本文是 Skill 的运行时参考,不替代 scripts/video_translation.py。常规翻译应优先使用脚本;只有在排查 API 调用、认证、幂等、限流、结果下载或错误码时才需要阅读本文。
1. Agent 快速参考
- 当前 API 基础地址:
https://xxx.com/api/v1。 - 外部 API 路径均位于
/api/v1/...下。 - 所有
/api/v1/...接口都需要 Agent API Key,优先使用Authorization: Bearer ${AGENT_API_KEY}。 - 二进制视频上传直接对存储预签名 URL 执行
PUT {presignedUrl},不携带 API Key。 - 媒体网关 URL 直接下载,不携带 API Key。
- 字幕下载仍属于 Agent API 接口,需要 API Key。
- 创建任务和重新翻译必须使用稳定的
Idempotency-Key。 - 不要把 API Key、上传预签名 URL、临时媒体下载 URL 或签名参数写入日志、状态文件、测试报告或提示词。
- 收到 429 时按照
Retry-After等待;遇到并发限制也要等待,不要激进重试。 - 临时 URL 过期后,通过结果接口重新获取 URL。
2. 调用流程
| 顺序 | 阶段 | 接口 |
|---|---|---|
| 1 | 初始化上传 | POST /video-uploads/initiate |
| 2 | 获取分片预签名 URL | POST /video-uploads/presign-part |
| 3 | 上传视频字节 | PUT {presignedUrl} |
| 4 | 完成上传 | POST /video-uploads/complete |
| 5 | 创建翻译任务 | POST /video-translations |
| 6 | 查询任务状态 | GET /video-translations/{taskId} |
| 7 | 查询结果 | GET /video-translations/{taskId}/results |
| 8 | 获取单个媒体 URL | GET /video-translations/{taskId}/results/files/{variant} |
| 9 | 下载字幕 | GET /video-translations/{taskId}/results/subtitles/{variant} |
可选的重新翻译:
POST /video-translations/{existingTaskId}/retranslate3. 认证和通用约定
Agent API 支持以下两种认证请求头,优先使用第一种:
Authorization: Bearer ${AGENT_API_KEY}X-API-Key: ${AGENT_API_KEY}常用 JSON 请求头:
Content-Type: application/json
Accept: application/json
Authorization: Bearer ${AGENT_API_KEY}
X-Request-Id: agent-run-20260704-0001X-Request-Id 为可选项。提供时长度必须为 8..64 个字符,只能包含 A-Z a-z 0-9 _ . : -。服务端会在响应头返回最终 request id。
成功响应使用 JSON envelope:
{
"code": 0,
"message": "ok",
"data": {}
}错误响应也使用 JSON envelope:
{
"code": -1,
"message": "INVALID_REQUEST",
"data": null,
"error": {
"code": "INVALID_REQUEST",
"message": "Validation failed.",
"requestId": "req_abc123",
"details": {}
}
}排查问题时按以下顺序检查:
- HTTP 状态码
error.codeerror.details- 响应头中的
X-Request-Id
所有 Agent API 响应都可能包含限流响应头:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 119
X-RateLimit-Reset: 1782300000限流响应:
HTTP/1.1 429 Too Many Requests
Retry-After: 17返回 RATE_LIMITED 时,必须按照 Retry-After 等待后再重试。
4. 视频上传
4.1 初始化上传
POST /video-uploads/initiate请求:
{
"filename": "demo.mp4",
"contentType": "video/mp4",
"fileSizeBytes": 342556
}| 字段 | 必填 | 说明 |
|---|---|---|
filename | 是 | 必须是 .mp4 文件名 |
contentType | 是 | 必须严格为 video/mp4 |
fileSizeBytes | 是 | 必须大于 0 且不超过账号文件大小限制 |
保存响应中的 fileId、uploadId、key 和 bucket。完成上传和创建任务时还需要这些字段。
4.2 获取分片预签名 URL
POST /video-uploads/presign-part请求:
{
"uploadId": "opaque-r2-upload-id",
"key": "storage-key-from-initiate",
"partNumber": 1,
"expiresInSeconds": 900
}| 字段 | 必填 | 说明 |
|---|---|---|
uploadId | 是 | 初始化上传返回的值 |
key | 是 | 初始化上传返回的值 |
partNumber | 是 | 1..10000 |
expiresInSeconds | 否 | URL 有效期,服务端限制在 60..86400 秒 |
返回的 presignedUrl 只用于当前上传,不要持久化到日志或状态文件。
4.3 上传视频字节
PUT {presignedUrl}
Content-Type: video/mp4请求体是视频字节。这不是 Agent API 请求:
- 不要携带
Authorization。 - 不要携带
X-API-Key。 - 不要记录
presignedUrl。 - URL 过期后重新调用
presign-part。 - 成功的 PUT 通常返回 200,客户端不需要把 ETag 回传给 Agent API。
4.4 完成上传
POST /video-uploads/complete请求:
{
"uploadId": "opaque-r2-upload-id",
"key": "storage-key-from-initiate"
}确认 data.success == true、data.status == "completed",并且 data.fileId 与初始化上传返回的 fileId 一致。
5. 创建翻译任务
POST /video-translations
Idempotency-Key: ${UNIQUE_IDEMPOTENCY_KEY}请求:
{
"fileId": "uploaded-file-id",
"videoDurationSeconds": 6,
"checksumSha256": "optional-file-sha256",
"sourceLanguage": "auto",
"targetLanguage": "en",
"speakerCount": 1,
"allowDynamicDuration": true
}| 字段 | 必填 | 说明 |
|---|---|---|
fileId | 是 | 已完成上传的 fileId |
videoDurationSeconds | 是 | 1..3600 秒 |
checksumSha256 | 否 | 用于跟踪和校验的源文件 SHA-256 |
sourceLanguage | 是 | 源语言,允许使用 auto |
targetLanguage | 是 | 目标语言,不允许使用 auto |
speakerCount | 否 | 0..15,默认 0 表示自动检测 |
allowDynamicDuration | 否 | true 允许动态时长同步 |
支持的语言由 references/languages.json 和服务端校验共同定义。
保存 taskId、fileId、creditsConsumed 以及本次请求使用的 Idempotency-Key。
积分按分钟向上取整:
durationInMinutes = max(1, ceil(videoDurationSeconds / 60))
creditsConsumed = durationInMinutes * credit.points_per_minute当前默认值为 credit.points_per_minute=3,实际值以服务端配置为准。
| 情况 | 结果 |
|---|---|
| 第一次成功请求 | 创建任务、扣除积分并返回 taskId |
| 相同 Key + 相同请求体 | 返回相同响应,不重复扣费 |
| 相同 Key + 不同请求体 | 409 IDEMPOTENCY_KEY_REUSED |
| 相同幂等请求仍在处理 | 409 IDEMPOTENCY_REQUEST_IN_PROGRESS |
如果网络超时导致无法确认服务端是否收到请求,必须使用完全相同的请求体和 Idempotency-Key 重试。
6. 查询任务进度
GET /video-translations/{taskId}| 字段 | 说明 |
|---|---|
taskId | 任务 ID |
status | pending、processing、completed、failed、cancelled |
progress | 任务进度,通常为 0..100 |
errorMessage | 失败原因,成功或处理中通常为空 |
status | 是否终态 | 处理方式 |
|---|---|---|
pending | 否 | 继续轮询 |
processing | 否 | 继续轮询 |
completed | 是 | 获取结果 |
failed | 是 | 停止轮询并报告 errorMessage |
cancelled | 是 | 停止轮询 |
推荐轮询策略:
- 创建任务 2 秒后第一次查询。
- 未完成时逐步退避:
2s -> 5s -> 10s -> 20s -> 30s。 - 推荐最大间隔为 30 秒。
- HTTP 429 按
Retry-After等待。 - HTTP 5xx 使用带总超时的指数退避。
只有 API 返回 completed、failed 或 cancelled 时才停止轮询。
7. 获取结果
7.1 查询结果列表
GET /video-translations/{taskId}/results?expiresIn=600任务必须处于 completed。expiresIn 可选,媒体下载 URL 的有效期由服务端限制在 60..3600 秒,默认 3600 秒。
type | variant | 说明 |
|---|---|---|
video | video | 最终合成的 MP4 视频 |
audio | vocal | 分离的人声 WAV |
audio | background | 分离的背景音 WAV |
audio | full | 完整合成的人声 WAV |
subtitle | source | 源语言 SRT 字幕 |
subtitle | translated | 目标语言 SRT 字幕 |
subtitle | bilingual | 双语 SRT 字幕 |
处理规则:
access=media_gateway的 URL 可直接下载,不需要 API Key。- 带有
access=api且requiresAuthorization=true的字幕 URL 需要 API Key。 - 媒体 URL 过期后,再次调用本接口或单文件接口获取新 URL。
7.2 获取单个媒体文件 URL
GET /video-translations/{taskId}/results/files/{variant}?expiresIn=600variant | 内容 |
|---|---|
video | 最终合成的 MP4 视频 |
vocal | 人声 WAV |
background | 背景音 WAV |
full | 完整合成的人声 WAV |
响应中的 url 是临时媒体网关 URL:
- 不要携带 API Key。
- 不要长期持久化。
- 如果接近
expiresAt时下载失败,再次调用本接口刷新 URL。 - 媒体网关支持 Range GET,可用于大文件断点下载。
7.3 下载字幕
GET /video-translations/{taskId}/results/subtitles/{variant}variant | 内容 |
|---|---|
source | 源语言字幕 |
translated | 翻译字幕 |
bilingual | 双语字幕 |
响应是纯 SRT 文本,不是 JSON:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8追加 ?download=1 可请求附件式下载。字幕接口仍属于 Agent API,必须携带 API Key。
8. 重新翻译
POST /video-translations/{existingTaskId}/retranslate
Idempotency-Key: ${UNIQUE_IDEMPOTENCY_KEY}允许重新翻译的原任务状态:
completedfailedcancelled
请求体可以为空。如果提供请求体,目前只支持:
{
"allowDynamicDuration": true
}重新翻译会创建新任务并扣除积分,同时受并发限制影响,必须使用 Idempotency-Key。
9. 可恢复状态机建议
至少持久化:
{
"apiBase": "https://xxx.com/api/v1",
"fileId": "string",
"uploadId": "string",
"key": "string",
"taskId": "string",
"idempotencyKey": "string",
"sourceLanguage": "auto",
"targetLanguage": "en",
"status": "pending|processing|completed|failed|cancelled"
}不要持久化:
- 明文 Agent API Key
- 上传预签名 URL
- 临时媒体下载 URL
- 临时签名查询参数、签名或凭据
推荐状态机:
NEW
-> UPLOAD_INITIATED
-> PART_PRESIGNED
-> PART_UPLOADED
-> UPLOAD_COMPLETED
-> TASK_CREATED
-> TASK_PROCESSING
-> TASK_COMPLETED
-> RESULT_DOWNLOADED恢复规则:
- 如果存在
uploadId和key,重新为未完成分片获取预签名 URL。 - 如果任务创建请求可能已经到达服务端,使用相同创建请求体和
Idempotency-Key重放。 - 如果存在
taskId,从GET /video-translations/{taskId}恢复。 - 下载 URL 过期后,再次请求
results/files/{variant}或results。
10. 错误码速查
error.code | HTTP | 含义 | 自动重试 |
|---|---|---|---|
UNAUTHORIZED | 401 | 缺少 API Key | 否 |
API_KEY_INVALID | 401 | API Key 无效 | 否 |
API_KEY_EXPIRED | 401 | API Key 已过期 | 否 |
API_KEY_REVOKED | 401 | API Key 已撤销 | 否 |
RATE_LIMITED | 429 | 触发限流 | 是,等待 Retry-After |
CONCURRENCY_LIMIT_REACHED | 429 | 达到账号并发限制 | 是,等待任务完成 |
INSUFFICIENT_CREDITS | 402 | 积分不足 | 否 |
INVALID_REQUEST | 400 | 请求体、字段或 variant 无效 | 否 |
MISSING_IDEMPOTENCY_KEY | 400 | 缺少或无效的幂等 Key | 否 |
INVALID_FILE_SIZE | 400 | 文件大小不为正数 | 否 |
FILE_TOO_LARGE | 400 | 文件过大 | 否 |
INVALID_CONTENT_TYPE | 400 | 不是 MP4 文件 | 否 |
INVALID_LANGUAGE | 400 | 不支持的语言 | 否 |
INVALID_SPEAKER_COUNT | 400 | 说话人数无效 | 否 |
INVALID_DURATION | 400 | 视频时长无效 | 否 |
IDEMPOTENCY_KEY_REUSED | 409 | 相同 Key 被用于不同请求体 | 否,由上层决定 |
IDEMPOTENCY_REQUEST_IN_PROGRESS | 409 | 相同幂等请求仍在处理 | 是,稍后使用相同请求体和 Key 重试 |
UPLOAD_NOT_FOUND | 404 / 409 | 上传会话不存在、过期或状态不允许 | 视情况 |
UPLOAD_NOT_COMPLETED | 409 | 文件上传未完成 | 否,先完成上传 |
TASK_NOT_FOUND | 404 | 任务不存在或未授权 | 否 |
TASK_NOT_COMPLETED | 409 | 任务尚未完成 | 是,继续轮询 |
LANGUAGE_PAIR_TASK_EXISTS | 409 | 同一文件和语言对已有任务 | 否,检查 details.existingTaskId |
FINAL_VIDEO_EXPIRED | 409 | 最终视频输出已过期 | 否,重新处理或恢复 |
FINAL_AUDIO_EXPIRED | 409 | 最终音频输出已过期 | 否,重新处理或恢复 |
RESULT_NOT_READY | 404 | 结果文件尚未准备好 | 是,等待后短暂重试 |
SUBTITLE_NOT_FOUND | 404 | 字幕不存在或为空 | 否,刚完成后可短暂重试 |
| 任意 5xx | 500 / 503 | 服务暂时不可用 | 是,使用有上限的指数退避 |
11. 外部调用说明
- 调用方只需要本文列出的 Base URL、Agent API Key 和接口路径。
- 不要缓存或持久化上传预签名 URL 或临时媒体下载 URL。
- 不要把 API Key、上传预签名 URL 或媒体下载 URL 写入日志或对话上下文。
- 下载 URL 过期后,再次调用结果接口获取新 URL。
