> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inputapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 视频生成与任务管理

> 创建、查询、下载及重混视频任务。

视频使用异步任务：创建后保存网关返回的 `id`，用同一用户/项目范围内的凭据查询，完成后下载。不要使用供应商后台里的私有任务 ID。

截至 2026-10-14，[OpenAI 官方说明](https://developers.openai.com/api/docs/guides/video-generation)已注明 Sora 2 / Videos API 于 2026-09-24 停用。本页说明项目仍提供的兼容接口；使用前必须确认部署中有实际可用、支持 `openai_video` 的渠道或插件。代码中存在 Sora 插件或 SDK 方法，不代表 OpenAI 上游仍可调用。

## 任务生命周期

| 状态 | 应用处理 |
| - | - |
| `queued` / `in_progress` | 等待后继续查询，设置查询次数和总时间预算 |
| `completed` | 请求内容端点；仍可能遇到过期或下载失败 |
| `failed` | 停止轮询，查看任务错误/日志 |
| `unknown` 或未识别值 | 停止自动流程并排查，不能当作成功 |

`progress` 只是提示，不以 100 代替 `status: completed`。查询可能返回后台轮询保存的快照，频繁查询不保证更快更新。

## Python：创建、续查和下载

按 [Python SDK](/zh/guides/python)配置环境，`API_MODEL` 必须是管理员确认可用的视频模型。保存为 `videos.py`。固定版本 SDK 仍提供兼容方法，但可能显示 Sora 弃用提示；它只用于访问你配置的网关，不能恢复已停用的上游。

先运行 `python videos.py create`，保存输出的 `id`。下方的 `task_example` 必须替换为该 ID；每次 `create` 都是新任务，不要把创建命令放入轮询循环。

```sh theme={null}
python videos.py status task_example
python videos.py wait task_example
python videos.py download task_example
```

`wait` 默认最多查询 60 次，间隔 5 秒，每次请求还有 120 秒超时，因此不承诺五分钟内结束。可用 `--max-polls` 设置 1–120 次。达到上限、退出或网络错误都不会取消服务端任务，可以稍后用相同 ID 继续查询。

```python theme={null}
import argparse
import json
import os
import re
import time
from contextlib import ExitStack
from pathlib import Path
from openai import OpenAI, APIConnectionError, APIStatusError

parser = argparse.ArgumentParser()
parser.add_argument("action", choices=["create", "status", "wait", "download", "remix"])
parser.add_argument("task_id", nargs="?")
parser.add_argument("--max-polls", type=int, default=60)
parser.add_argument("--image", help="Reference image to upload when creating a task")
args = parser.parse_args()
if args.action != "create" and (not args.task_id or not re.fullmatch(r"[A-Za-z0-9_-]+", args.task_id)):
    parser.error("Provide the public gateway task ID (letters, digits, underscores, or hyphens).")
if not 1 <= args.max_polls <= 120:
    parser.error("--max-polls must be between 1 and 120.")
if args.image and args.action != "create":
    parser.error("--image is only valid with create.")

with OpenAI(base_url=os.environ["API_BASE_URL"].rstrip("/"),
            api_key=os.environ["API_KEY"], timeout=120.0, max_retries=0) as client:
    try:
        if args.action == "create":
            # SDK sends multipart; the gateway also accepts JSON for compatible plugins.
            with ExitStack() as stack:
                extra = {}
                if args.image:
                    extra["input_reference"] = stack.enter_context(Path(args.image).open("rb"))
                result = client.videos.create(
                    model=os.environ["API_MODEL"],
                    prompt="A paper boat floating on a calm pond, static camera.", **extra,
                )
        elif args.action == "remix":
            result = client.videos.remix(args.task_id, prompt="Change the scene to sunset.")
        elif args.action == "download":
            task = client.videos.retrieve(args.task_id)
            if task.status != "completed":
                raise ValueError("Video is not completed.")
            # A failed transfer may leave a partial file; remove it before retrying download.
            output = Path("video.mp4")
            with client.videos.with_streaming_response.download_content(args.task_id) as response:
                media_type = response.headers.get("content-type", "").split(";")[0].lower()
                if media_type not in ("video/mp4", "application/octet-stream"):
                    raise ValueError("Expected MP4 bytes for this example.")
                with output.open("xb") as target:
                    size = 0
                    for chunk in response.iter_bytes():
                        size += len(chunk)
                        if size > 256 * 1024 * 1024:
                            raise ValueError("Example download exceeds 256 MiB.")
                        target.write(chunk)
                if size == 0:
                    raise ValueError("Empty video.")
            print("Saved video.mp4")
            raise SystemExit(0)
        else:
            for attempt in range(args.max_polls if args.action == "wait" else 1):
                result = client.videos.retrieve(args.task_id)
                if result.status not in ("queued", "in_progress") or args.action == "status":
                    break
                if attempt + 1 == args.max_polls:
                    raise SystemExit("Polling limit reached; resume with the same task ID. The task was not cancelled.")
                time.sleep(5)
        if not result.id or result.status not in ("queued", "in_progress", "completed", "failed"):
            raise ValueError("Unrecognized video response.")
        print(json.dumps({"id": result.id, "status": result.status, "progress": getattr(result, "progress", None)}))
        if result.status == "failed":
            raise SystemExit("Video task failed. Check the task logs before submitting again.")
    except APIStatusError as error:
        raise SystemExit(f"Request failed (HTTP {error.status_code}). Keep any task ID; do not automatically create another task.")
    except APIConnectionError:
        raise SystemExit("Connection failed. Keep any task ID; do not automatically create another task.")
    except (ValueError, OSError):
        raise SystemExit("Invalid video response or output file. Check status, content type, and any partial download.")
```

## 图生视频与 Remix

[创建接口](/zh/api-reference/videos-create)支持 JSON 或 multipart，但 `input_reference`、时长和尺寸取决于执行插件。上传参考图时用 multipart 的 `input_reference` 文件字段；确认模型支持的编码、尺寸和文件大小。示例可执行 `python videos.py create --image /path/to/reference.png`，会将图片上传到配置的网关及其上游。只提供 `prompt` 是文生视频，输入图片不是上传待转写的视频。

[Remix](/zh/api-reference/videos-remix)使用已有任务：`python videos.py remix task_example`。仅在原任务所属渠道和插件支持时使用；网关会关联原任务并固定到原渠道。返回的是新任务的提交摘要，保存新 `id` 后继续查询。不要假定所有视频插件都有 Remix 能力。

## 下载与恢复

[下载内容](/zh/api-reference/videos-content)返回二进制；[HEAD](/zh/api-reference/videos-content-head)仅检查响应头。使用网关内容端点并保留 Bearer 认证，不向供应商返回的任意 URL 发送网关密钥。不要把长期 API Key 放进浏览器 `<video>` 的 URL。

本例只保存 MP4 / octet-stream，单次上限 256 MiB，且不覆盖 `video.mp4`；这些是示例约束。失败后可能留下部分文件，删除该部分文件或换输出名后再下载。完整下载不代表已进行媒体解码校验。`Range`、缓存头、文件大小和其他内容类型依赖内容源，不保证每个插件一致。任务完成也不代表内容永久保留；`410` 表示内容已不可用，`502` 可能是内容代理失败。

## 兼容边界

旧的 `/v1/video/generations` 接口与 `/v1/videos` 不具有相同响应结构；不要混用解析器。本指南统一使用 `/v1/videos`。不承诺 OpenAI SDK 中的列表、删除、扩展、角色、独立编辑端点在本项目可用，也不承诺 webhook 或取消任务接口。

提交超时且没有收到 ID 时，先用请求日志确认是否已创建；重复 POST 可能生成多份内容。查询和下载失败时保留 ID，按[错误处理](/zh/guides/errors)恢复。

[Read in English](/en/guides/video-generation)

[相关指南：视频理解](/zh/guides/video-understanding)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.