任务进度查询

任务进度查询用于通过 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 参数可能被代理或网关记录。生产环境优先使用 Authorization header。

订阅任务

{
  "type": "subscribe",
  "task_ids": ["TASK_ID"]
}

服务端会逐个校验任务是否存在,以及任务是否属于当前 API Key 对应用户。合法任务会加入订阅集合,并立即返回当前进度快照。

取消订阅

{
  "type": "unsubscribe",
  "task_ids": ["TASK_ID"]
}

连接断开时,服务端会自动清理该连接的全部订阅。

连接生命周期

当连接当前订阅集合中的所有任务都进入 completedfailedcancelled 后,服务端会在发送最后一条终态 progress_update 后主动关闭 WebSocket。客户端应将这次关闭视为正常收尾;后续如需监听新任务,请重新建立连接并发送新的 subscribe 消息。

若同一连接仍有任一任务处于 queuedprocessing,连接会保持打开并继续推送该任务的进度。

进度消息

{
  "type": "progress_update",
  "data": {
    "task_id": "TASK_ID",
    "status": "processing",
    "progress_percent": 42,
    "progress_node": "render",
    "extra": {},
    "timestamp": 1790000000000
  }
}
字段类型说明
typestring固定为 progress_update
data.task_idstring任务 ID
data.statusstring任务状态,与查询任务接口一致
data.progress_percentnumber可选,处理进度百分比
data.progress_nodestring可选,当前处理节点
data.extraobject可选,业务扩展信息
data.timestampnumber服务端事件时间,Unix 毫秒

各模态进度节点

不同 task_type 推送的 progress_nodeextra 字段细节略有不同。客户端应将以下作为参考而非硬约束。

状态消息(所有 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 ≈ 10
  • progress_node: "processing", progress_percent ≈ 50
  • progress_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检查握手请求的 Authorizationapi_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()