任务进度查询
任务进度查询用于通过 WebSocket 订阅任务状态变化,减少轮询请求并更快获得处理进度。当前端点为 /ws/v1/progress,服务端会在订阅成功后立即返回一次任务快照,并继续推送后续进度事件。
请求
基本信息
| 项目 | 值 |
|---|---|
| 协议 | WebSocket |
| 路径 | /ws/v1/progress |
| 鉴权方式 | API Key |
握手鉴权
优先通过 Authorization header 传递 API Key:
Authorization: YOUR_API_KEY
浏览器环境无法设置自定义 header 时,可以降级使用 api_key query 参数:
wss://api.ai-mcn.tv:10000/ws/v1/progress?api_key=YOUR_API_KEY
注意:query 参数可能被代理或网关记录。生产环境优先使用
Authorizationheader。
订阅任务
{
"type": "subscribe",
"task_ids": ["TASK_ID"]
}
服务端会逐个校验任务是否存在,以及任务是否属于当前 API Key 对应用户。合法任务会加入订阅集合,并立即返回当前进度快照。
取消订阅
{
"type": "unsubscribe",
"task_ids": ["TASK_ID"]
}
连接断开时,服务端会自动清理该连接的全部订阅。
连接生命周期
当连接当前订阅集合中的所有任务都进入 completed、failed 或 cancelled 后,服务端会在发送最后一条终态 progress_update 后主动关闭 WebSocket。客户端应将这次关闭视为正常收尾;后续如需监听新任务,请重新建立连接并发送新的 subscribe 消息。
若同一连接仍有任一任务处于 queued 或 processing,连接会保持打开并继续推送该任务的进度。
进度消息
{
"type": "progress_update",
"data": {
"task_id": "TASK_ID",
"status": "processing",
"progress_percent": 42,
"progress_node": "render",
"extra": {},
"timestamp": 1790000000000
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
type | string | 固定为 progress_update |
data.task_id | string | 任务 ID |
data.status | string | 任务状态,与查询任务接口一致 |
data.progress_percent | number | 可选,处理进度百分比 |
data.progress_node | string | 可选,当前处理节点 |
data.extra | object | 可选,业务扩展信息 |
data.timestamp | number | 服务端事件时间,Unix 毫秒 |
各模态进度节点
不同 task_type 推送的 progress_node 与 extra 字段细节略有不同。客户端应将以下作为参考而非硬约束。
状态消息(所有 task_type 共享)
每个任务至少推送 2 条 status 转换消息:
status: "processing"(任务开始执行,progress_percent: 0)- 终态:
status: "completed"(progress_percent: 100)/failed/cancelled
图片 / 文本 task_type
图片处理通常 < 5 秒,文本 < 1 秒。该类任务不推送中间进度,客户端只会收到 2 条 status 转换消息。
音频 task_type(asr / audio_silence_remove / audio_noise_reduce / audio_speaker_split)
每个音频任务至少推送 3 个进度节点:
progress_node: "decoded",progress_percent ≈ 10(输入文件解码完成)progress_node: "processing",progress_percent ≈ 50(核心处理过半)progress_node: "encoding",progress_percent ≈ 95(输出编码完成)
视频处理类 task_type
包括 video_blackborder_remove / video_canvas_adapt / video_interpolate / video_upscale / video_purify / video_stabilizer / video_vaporwave / video_ai_subtitle。
该类任务推送以下 3 个进度节点:
progress_node: "decoded",progress_percent ≈ 10progress_node: "processing",progress_percent ≈ 50progress_node: "encoding",progress_percent ≈ 95
⚠️ 该类任务的
extra不包含current_frame/total_frames字段。extra中的字段为可选项,客户端应对其中的字段做兼容处理(缺失时按None/ 不存在处理)。
视频拆分类 task_type(video_segment / video_ai_segment / video_motion_cut)
拆分类任务(输入一个视频,输出多个片段)在 encoding 节点 extra 中包含 segment_count,让客户端感知拆分规模:
{
"type": "progress_update",
"data": {
"task_id": "TASK_ID",
"status": "processing",
"progress_percent": 95,
"progress_node": "encoding",
"extra": { "segment_count": 12 },
"timestamp": 1790000000000
}
}
基于时间的进度估算节点(elapsed,所有 task_type 通用)
对于处理时间较长的任务,服务端会在处理过程中持续推送基于已用时长的进度估算,确保进度平滑推进:
progress_node: "elapsed"progress_percent为基于已用时长的估算值
该估算与精确进度共享单调递增保证(进度只增不减):当收到精确进度后,落后于精确值的估算会自动跳过。客户端无需特殊处理,按常规 progress_update 处理即可。
部分任务类型可能不包含该估算节点,此时进度来自处理阶段节点与状态转换两类消息。
错误消息
{
"type": "error",
"code": "TASK_NOT_FOUND",
"message": "task not found",
"task_id": "TASK_ID"
}
| 错误码 | 说明 | 解决方案 |
|---|---|---|
AUTH_REQUIRED | 缺少或无效 API Key | 检查握手请求的 Authorization 或 api_key |
TASK_NOT_FOUND | 任务不存在 | 确认 task_id 是否正确 |
TASK_FORBIDDEN | 任务不属于当前用户 | 使用创建该任务的 API Key 订阅 |
INVALID_MESSAGE | 消息不是合法 JSON、缺少字段或 type 未知 | 检查消息格式 |
RATE_LIMITED | 超过单用户连接数限制 | 关闭多余连接后重试 |
限制
单个用户首期最多同时建立 5 个 WebSocket 连接。超过限制的连接会收到 RATE_LIMITED 错误并被关闭。
Node 示例
import WebSocket from 'ws'
const ws = new WebSocket('wss://api.ai-mcn.tv:10000/ws/v1/progress', {
headers: {
Authorization: process.env.GITRUCK_API_KEY,
},
})
ws.on('open', () => {
ws.send(JSON.stringify({
type: 'subscribe',
task_ids: ['TASK_ID'],
}))
})
ws.on('message', (raw) => {
const message = JSON.parse(raw.toString())
console.log(message)
})
ws.on('close', () => {
console.log('progress stream closed; reconnect before subscribing to new tasks')
})
Python 示例
import json
import os
import websocket
ws = websocket.create_connection(
"wss://api.ai-mcn.tv:10000/ws/v1/progress",
header=[f"Authorization: {os.environ['GITRUCK_API_KEY']}"],
)
ws.send(json.dumps({
"type": "subscribe",
"task_ids": ["TASK_ID"],
}))
try:
while True:
print(json.loads(ws.recv()))
except websocket.WebSocketConnectionClosedException:
print("progress stream closed; reconnect before subscribing to new tasks")
finally:
ws.close()