文档

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获取分片预签名 URLPOST /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获取单个媒体 URLGET /video-translations/{taskId}/results/files/{variant}
9下载字幕GET /video-translations/{taskId}/results/subtitles/{variant}

可选的重新翻译:

POST /video-translations/{existingTaskId}/retranslate

3. 认证和通用约定

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-0001

X-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": {}
  }
}

排查问题时按以下顺序检查:

  1. HTTP 状态码
  2. error.code
  3. error.details
  4. 响应头中的 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
statuspending、processing、completed、failed、cancelled
progress任务进度,通常为 0..100
errorMessage失败原因,成功或处理中通常为空
status是否终态处理方式
pending否继续轮询
processing否继续轮询
completed是获取结果
failed是停止轮询并报告 errorMessage
cancelled是停止轮询

推荐轮询策略:

  1. 创建任务 2 秒后第一次查询。
  2. 未完成时逐步退避:2s -> 5s -> 10s -> 20s -> 30s。
  3. 推荐最大间隔为 30 秒。
  4. HTTP 429 按 Retry-After 等待。
  5. HTTP 5xx 使用带总超时的指数退避。

只有 API 返回 completed、failed 或 cancelled 时才停止轮询。

7. 获取结果

7.1 查询结果列表

GET /video-translations/{taskId}/results?expiresIn=600

任务必须处于 completed。expiresIn 可选,媒体下载 URL 的有效期由服务端限制在 60..3600 秒,默认 3600 秒。

typevariant说明
videovideo最终合成的 MP4 视频
audiovocal分离的人声 WAV
audiobackground分离的背景音 WAV
audiofull完整合成的人声 WAV
subtitlesource源语言 SRT 字幕
subtitletranslated目标语言 SRT 字幕
subtitlebilingual双语 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=600
variant内容
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}

允许重新翻译的原任务状态:

  • completed
  • failed
  • cancelled

请求体可以为空。如果提供请求体,目前只支持:

{
  "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.codeHTTP含义自动重试
UNAUTHORIZED401缺少 API Key否
API_KEY_INVALID401API Key 无效否
API_KEY_EXPIRED401API Key 已过期否
API_KEY_REVOKED401API Key 已撤销否
RATE_LIMITED429触发限流是,等待 Retry-After
CONCURRENCY_LIMIT_REACHED429达到账号并发限制是,等待任务完成
INSUFFICIENT_CREDITS402积分不足否
INVALID_REQUEST400请求体、字段或 variant 无效否
MISSING_IDEMPOTENCY_KEY400缺少或无效的幂等 Key否
INVALID_FILE_SIZE400文件大小不为正数否
FILE_TOO_LARGE400文件过大否
INVALID_CONTENT_TYPE400不是 MP4 文件否
INVALID_LANGUAGE400不支持的语言否
INVALID_SPEAKER_COUNT400说话人数无效否
INVALID_DURATION400视频时长无效否
IDEMPOTENCY_KEY_REUSED409相同 Key 被用于不同请求体否,由上层决定
IDEMPOTENCY_REQUEST_IN_PROGRESS409相同幂等请求仍在处理是,稍后使用相同请求体和 Key 重试
UPLOAD_NOT_FOUND404 / 409上传会话不存在、过期或状态不允许视情况
UPLOAD_NOT_COMPLETED409文件上传未完成否,先完成上传
TASK_NOT_FOUND404任务不存在或未授权否
TASK_NOT_COMPLETED409任务尚未完成是,继续轮询
LANGUAGE_PAIR_TASK_EXISTS409同一文件和语言对已有任务否,检查 details.existingTaskId
FINAL_VIDEO_EXPIRED409最终视频输出已过期否,重新处理或恢复
FINAL_AUDIO_EXPIRED409最终音频输出已过期否,重新处理或恢复
RESULT_NOT_READY404结果文件尚未准备好是,等待后短暂重试
SUBTITLE_NOT_FOUND404字幕不存在或为空否,刚完成后可短暂重试
任意 5xx500 / 503服务暂时不可用是,使用有上限的指数退避

11. 外部调用说明

  • 调用方只需要本文列出的 Base URL、Agent API Key 和接口路径。
  • 不要缓存或持久化上传预签名 URL 或临时媒体下载 URL。
  • 不要把 API Key、上传预签名 URL 或媒体下载 URL 写入日志或对话上下文。
  • 下载 URL 过期后,再次调用结果接口获取新 URL。