视频生成 异步任务 OpenAI 兼容 媒体代理 API 集成

视频生成 API 集成:任务、轮询与内容下载

用创建、轮询和内容下载流程集成视频生成,覆盖编辑与延长端点、Webhook、时长上限和授权媒体交付。

AveMujica API 3 分钟阅读

视频生成 API 集成是一种异步媒体工作流:先创建任务,等待完成或失败,再通过可能过期且必须授权的内容 URL 下载字节。遵循 Videos 表面的 OpenAI 兼容网关通常提供 POST /v1/videos、GET /v1/videos/{task_id} 和 GET /v1/videos/{task_id}/content。OpenAI 官方文档现在把编辑、延长、角色、Webhook 与 Batch 和创建/查询并列,而旧 remix 端点已不再适合新项目。本文基于仓库可见行为和官方文档说明如何安全集成,不虚构延迟或价格结论。

日期背景(2026-07-15): OpenAI 已宣布 Videos API 与 Sora 2 模型别名弃用,并将在 2026-09-24 关闭(参见 OpenAI 弃用公告)。不要仅基于 Sora 2 启动新的长期产品。如果仍通过网关承载 Sora 流量,应把当前视为迁移窗口:保持创建/轮询/内容下载可用,不为 remix-only 流程构建新 UX,并立即规划双供应商别名。

直接答案:把视频当作任务,而不是聊天补全

# 1) create
curl -sS https://YOUR_GATEWAY/v1/videos \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_VIDEO_MODEL_ALIAS",
    "prompt": "Slow aerial push-in over a misty cedar forest at dawn",
    "seconds": "4",
    "size": "1280x720"
  }'

# 2) poll (prefer webhooks when the upstream supports them; see below)
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID \
  -H "Authorization: Bearer $GATEWAY_KEY"

# 3) download when status=completed
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID/content \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -o forest.mp4

应显式处理的状态包括 queued、in_progress、completed 和 failed,这些状态也存在于本代码库的视频 DTO。任务对象常见字段包括 id、model、status、progress、created_at、completed_at、expires_at、seconds、size、可选 error,以及派生任务存在时的 remixed_from_video_id 等 lineage 字段。

始终在供应商当前文档中重新检查参数矩阵,例如 OpenAI 的 视频生成指南 和 Videos API 参考。其他供应商,如 Google Veo / Gemini 视频表面、Runway、Luma、Kling、ByteDance/Volcengine,可能使用不同任务形状。网关也可能根据通道适配器暴露 /v1/video/generations 或 Kling 风格 /kling/v1/videos/* 等供应商专属路由。网关支持时,应用代码应优先使用归一化的 OpenAI 风格任务 API。

OpenAI 官方表面与本网关当前注册能力

能力(OpenAI 文档,2026-07-15)官方路由/事件本仓库网关现状
创建视频POST /v1/videos支持,作为 OpenAI 风格适配器的主要任务提交路径
查询/轮询GET /v1/videos/{id}支持
下载内容GET /v1/videos/{id}/content支持,并检查所有权
编辑现有视频POST /v1/videos/edits(推荐;remix 已弃用)当前尚未归一化为一等网关路由集
延长视频POST /v1/videos/extensions当前尚未归一化
角色POST /v1/videos/characters + create 上的 characters当前尚未归一化
旧 remixPOST /v1/videos/{id}/remix(新集成已弃用)现有 Sora 风格适配器仍检测/注册 remix 路径
Webhookvideo.completed、video.failedOpenAI 上游功能;网关客户端仍应实现轮询 fallback
BatchBatch API 中指向 POST /v1/videos 的行上游功能;不能替代产品任务表

架构评审中必须明确这个缺口:只理解创建/轮询/内容下载的产品代码更能承受多供应商路由;把 remix 硬编码为“编辑”按钮的代码会同时撞上 OpenAI 弃用和网关尚未完整归一化编辑/延长/角色能力的问题。

为什么视频集成比图片更难

关注点图片(典型)视频(典型)
延迟秒级数十秒到数分钟
API 形状通常单次响应创建 + 等待 + 内容
载荷大小KB–MB很容易达到数 MB
失败模式审核/尺寸错误长 timeout、部分进度、内容过期
成本风险n 和分辨率时长、分辨率、编辑/延长链
创建后的 AuthZ可选内容下载必须检查

如果直接套用聊天补全 timeout,例如 60 秒硬取消且不轮询,那么即使任务之后成功,视频集成看起来也会“坏掉”。从第一天就在应用中设计任务表。

推荐的应用数据模型

video_jobs
  id (your id)
  provider_task_id
  model
  prompt_hash / prompt_text (policy-dependent)
  status
  progress
  seconds
  size
  billing_owner_type / billing_owner_id
  team_id / project_id (nullable)
  content_expires_at
  storage_key (nullable until persisted)
  source_task_id (edit/extension/remix lineage)
  last_error
  created_at / updated_at

Worker 从轮询或 Webhook 更新 status 与 progress。状态变为 completed 后,下载 worker 只获取一次 /content,保存到对象存储并设置 storage_key。状态为 failed 时,暴露 error.message / error.code,不要无限重试。

时长与计费上限

时长是计费乘数。本仓库使用 MaxTaskDurationSeconds = 3600 限制用户输入的视频时长,并在校验阶段拒绝越界 seconds。即使平台允许更长,产品也应设置更严格的 UX 上限,例如预览视频限制为 4–12 秒。OpenAI 官方创建示例通常使用离散秒数桶,当前 Sora 文档也包含较长的 16/20 秒变体;不要虚构任意时长。

集成规则:

  • 谨慎解析 seconds,DTO 可能把它作为字符串传递
  • 在服务器重新校验前,不要信任客户端时长来展示价格
  • 向计费所有者(用户或团队)预扣,而不只是执行者
  • 任务在预扣后失败时进行结算或退款
  • 编辑/延长/remix 链也要采用同样规则,防止用户无意放大成本

所有者与执行者分离见 多租户 LLM 网关架构,归因字段见 LLM 使用日志与成本追踪。

等待策略:Webhook 优先,轮询兜底

OpenAI 视频指南建议大约每 10–20 秒退避轮询,并在可用时优先使用 Webhook(video.completed / video.failed)。文档说明下载 URL 生命周期很短,在 OpenAI 指南中约为生成后 1 小时,因此应尽快复制到自有存储。

产品 worker 的实用默认值:

  1. 当供应商及网关/运维链路支持签名交付时注册 Webhook。
  2. 用轮询兜底:从约 10s 开始,加入 jitter,在高负载或连续 in_progress 时退避到 20–30s。
  3. 有 Retry-After 时遵守它。
  4. 为总等待时间设置硬 timeout,并写入终态 expired/failed。
  5. 不要让每个浏览器标签页每几百毫秒轮询一次。
type VideoTask = {
  id: string;
  status: "queued" | "in_progress" | "completed" | "failed" | string;
  progress?: number;
  expires_at?: number;
  error?: { message?: string; code?: string };
};

async function sleep(ms: number) {
  await new Promise((r) => setTimeout(r, ms));
}

async function pollVideo(taskId: string, timeoutMs = 15 * 60_000): Promise<VideoTask> {
  const started = Date.now();
  let interval = 10_000;
  while (Date.now() - started < timeoutMs) {
    const res = await fetch(`${process.env.GATEWAY_BASE}/v1/videos/${taskId}`, {
      headers: { Authorization: `Bearer ${process.env.GATEWAY_KEY}` },
    });
    if (res.status === 429) {
      const ra = Number(res.headers.get("retry-after"));
      await sleep(Number.isFinite(ra) ? ra * 1000 : interval);
      interval = Math.min(interval + 5_000, 30_000);
      continue;
    }
    if (!res.ok) throw new Error(await res.text());
    const task = (await res.json()) as VideoTask;
    if (task.status === "completed" || task.status === "failed") return task;
    const jitter = Math.floor(Math.random() * 2_000);
    await sleep(interval + jitter);
    interval = Math.min(Math.floor(interval * 1.2), 30_000);
  }
  throw new Error("video poll timeout");
}

调优必须依据你的模型和地区的实测完成时间,而不是其他团队的博客。

内容下载 AuthZ 与工作台作用域

创建任务不等于之后有权流式读取字节。在多租户网关中,/v1/videos/{id}/content 必须检查所有权:创建任务时的同一用户/团队/项目作用域,或显式共享策略。跨租户猜测任务 ID 必须失败关闭。

本仓库中的工作台路径:

  • UI:视频工作台
  • /api/user/video-workbench 下的个人 API
  • /api/teams/:team_id/video-workbench 下带项目作用域操作的团队 API
  • 生成视频与管理视频资产等不同授权

这不同于仅个人作用域的 图片工作台。如果持久工作台播放依赖对象存储,应在承诺永久历史前完成配置。指向 /v1/videos/{id}/content 的 fallback 播放 URL 仍需实时 AuthZ,并可能受 expires_at 限制。

编辑、延长、角色与旧版 remix

OpenAI 对新集成的官方指导:

  • 编辑: 使用 POST /v1/videos/edits,通过 prompt 和源 video 做定向修改;remix 已不再承担这项新工作。
  • 延长: 使用 POST /v1/videos/extensions 延续已完成片段;总时长会拼接,且 OpenAI 指南说明 extension 不支持 characters。
  • 角色: 使用 POST /v1/videos/characters,然后在 create 中引用 character ID 以保持一致性。
  • Batch: 离线队列由指向 POST /v1/videos 的 JSONL 组成;OpenAI 文档中 batch 输出有独立留存窗口。

任何派生任务都应遵守以下集成规则,包括本网关仍保留的旧 remix:

  • 只有 caller 能读取源任务时,才允许创建派生任务
  • 从源任务复制租户字段,不要把派生任务留在错误项目下
  • 明确告诉用户编辑/延长/remix 是一个新的计费任务,不是免费调整
  • 为支持和审核持久化 lineage
  • 对供应商专属 metadata bag 使用 feature flag;用全局上限校验时长与尺寸

在网关完成编辑/延长/角色归一化之前,应把这些调用放在显式适配器开关或原生上游客户端后面,不要假装 remix 是现代 OpenAI 路径。

持久化策略

应假设:

  1. 上游内容 URL 甚至网关临时代理都会过期(expires_at 是一等字段;OpenAI 记录交互式下载约 1 小时)
  2. 产品页面需要你的对象键
  3. 缩略图应在下载后生成,而不是临时抓取供应商 CDN
  4. 团队离开或用户行使留存权利时必须能够删除

安全流水线:

completed → 授权内容获取 → 必要时病毒/类型嗅探 → 对象存储写入 → 数据库 storage_key → 通过带应用鉴权的 CDN 提供。

“等需要时再存储”会让 demo 变成事故工单;如果上游 Videos API 本身还在退役,这种问题尤其痛苦。

可观测性与支持

至少记录网关 request ID / task ID、模型别名、秒数、尺寸、状态转换、计费所有者和执行者、Webhook 或轮询路径,以及最终错误码。Dashboard 应把视频失败类别与聊天失败分开。支持工具应能打开任务和使用日志,而不把完整 MP4 下载到工单系统。

可能遇到的其他路由

根据通道适配器,运维人员还可能启用:

  • /v1/video/generations 风格端点
  • Kling /kling/v1/videos/*
  • Gemini/Vertex Veo 任务适配器
  • Jimeng 或相似路由后的其他供应商任务 API

应用团队不应 hardcode 每条供应商路径。优先使用一个归一化客户端(/v1/videos + 稳定别名),由网关映射通道。如果某项能力只存在于供应商路径,例如 motion brush 或电影预设,应放在 feature flag 后并记录不可移植契约。

相关阅读

来源

运维问答

可以阻塞 HTTP 请求直到视频完成吗?

只适合短时内部工具。产品 UI 应创建任务记录,并使用 Webhook 或轮询。长同步请求会放大网关和负载均衡器 timeout。

应使用什么轮询间隔?

默认从约 10 秒开始并加入 jitter,退避到 20–30 秒,遵守 Retry-After,可用时优先使用 video.completed / video.failed Webhook。OpenAI 指南给出的轮询区间约为 10–20 秒。

状态已完成后,为什么内容下载仍失败?

常见原因包括内容已过期、鉴权作用域错误、任务属于另一个项目,或存储/代理配置错误。重新生成前先检查 expires_at 与租户字段。

新产品应该使用 remix 吗?

不应把它作为主要编辑路径。OpenAI 官方文档将新编辑工作指向 POST /v1/videos/edits,remix 已弃用。本网关可能仍为兼容性接受 remix 风格路由,应把它当作旧版桥梁,而不是绿地设计。

已经调用 /v1/videos 后还需要视频工作台吗?

纯后端流水线不需要。当人类需要共享历史、预设或 UI 中的团队作用域资产管理时需要。

首个应交付的 Worker

实现一个 Worker:如果已有稳定的非 Sora 别名,就用它创建短视频;否则使用明确标为临时的 Sora 别名,并写下 2026-09-24 前的迁移日期。以 10s + jitter 轮询(Webhook 可选),只下载一次 /content,上传到对象存储,并证明第二个团队的密钥无法下载该任务 ID。完成这些验证后再把 happy path 接入产品 UI。