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

# 视频生成

> 通过 Rivus AI 网关代理调用 OpenAI Sora 视频生成接口

使用 OpenAI Sora 模型生成视频内容。Rivus AI 支持完整的视频生成工作流，包括任务创建、状态查询和内容下载。

## 创建视频任务

通过提供文本提示词来生成视频：

```bash theme={null}
curl -X POST "https://models.rivus.cn/v1/videos" \
  -H "Authorization: Bearer $TOKEN" \
  -F "model=sora-2" \
  -F "prompt=百事可乐宣传片" \
  -F "seconds=10" \
  -F "size=720x1280"
```

### 请求参数

* `model`：模型名称，支持 `sora-2` 和 `sora-2-pro`
* `prompt`：视频生成的文本描述
* `seconds`：视频时长（秒，字符串传递更兼容）。常见可用档位：
  * `sora-2`：`10`、`15`
  * `sora-2-pro`：`15`、`25`
  * OpenAI 官方 API 仅支持：`4`、`8`、`12`
* `size`：视频分辨率，如 `1280x720`、`1920x1080`

<Callout type="tip">
  时长选择建议：

  * 快速预览：优先 10 秒（若使用 OpenAI 官方 API，请按其仅支持的 4/8/12 秒档位）
  * 正式成片：`sora-2-pro` 的 25 秒可以呈现更完整叙事，但生成与下载时间也更长
</Callout>

### 角色视频（Character）扩展（特定上游）

当 OpenAI 渠道的上游支持 Sora 角色扩展能力时，平台会对 `/v1/videos` 进行扩展，支持官方文档中的角色相关参数。典型用法是先通过 `/sora/v1/characters` 创建一个角色，再在视频提示词或参数中引用该角色。

#### 额外参数（仅在支持该扩展能力的上游生效）

* `character_url`：包含目标角色的视频 URL（通常与 `/sora/v1/characters` 中的 `url` 一致）
* `character_timestamps`：角色在视频中的时间片段范围，单位秒，格式如 `1,3`（表示 1～3 秒）
* `private`：是否为私有角色，字符串 `"true"` 或 `"false"`（不填时由上游按默认策略处理）

#### JSON 调用示例（支持角色扩展的上游）

```bash theme={null}
curl -X POST "https://models.kapon.cloud/v1/videos" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "sora-2",
    "prompt": "让刚才创建的角色在咖啡馆场景中阅读一本书",
    "seconds": 10,
    "size": "16x9",
    "character_url": "https://filesystem.site/cdn/20251030/example-character.mp4",
    "character_timestamps": "1,3",
    "private": "false"
  }'
```

在上述特定上游场景下：

* JSON 请求会在网关层自动转换为 `multipart/form-data`，并透传上述字段到上游；
* multipart 请求则保持原样透传，你也可以直接使用 `-F character_url=...` 的形式提交。

### 响应示例

```json theme={null}
{
  "id": "video_691209aab0a08198a4e78870277f7e3d0215e09cec47a737",
  "object": "video",
  "created_at": 1762789802,
  "status": "queued",
  "model": "sora-2",
  "prompt": "百事可乐宣传片",
  "progress": 0,
  "seconds": "4",
  "size": "720x1280"
}
```

## 状态说明

任务创建后会经历以下状态：

* `queued`：任务已排队，等待处理
* `processing`：正在生成视频
* `completed`：生成完成，可以下载视频
* `failed`：生成失败

<Callout type="info">
  任务完成后，响应会包含 `completed_at`（完成时间）和 `expires_at`（过期时间）字段。视频文件会在过期时间后自动删除。
</Callout>

## 完整示例

创建任务并等待完成：

```bash theme={null}
# 1. 创建视频任务
RESPONSE=$(curl -X POST "https://models.rivus.cn/v1/videos" \
  -H "Authorization: Bearer $TOKEN" \
  -F "model=sora-2" \
  -F "prompt=百事可乐宣传片" \
  -F "seconds=10" \
  -F "size=720x1280")

VIDEO_ID=$(echo $RESPONSE | jq -r '.id')
echo "视频任务 ID: $VIDEO_ID"

# 2. 轮询查询状态
while true; do
  RESPONSE=$(curl "https://models.rivus.cn/v1/videos/$VIDEO_ID" \
    -H "Authorization: Bearer $TOKEN")
  
  STATUS=$(echo $RESPONSE | jq -r '.status')
  PROGRESS=$(echo $RESPONSE | jq -r '.progress')
  
  echo "当前状态: $STATUS (进度: $PROGRESS%)"
  
  if [ "$STATUS" = "completed" ]; then
    echo "✓ 视频生成完成"
    break
  elif [ "$STATUS" = "failed" ]; then
    echo "✗ 视频生成失败"
    exit 1
  fi
  
  sleep 5
done

# 3. 下载视频
curl -L "https://models.rivus.cn/v1/videos/$VIDEO_ID/content" \
  -H "Authorization: Bearer $TOKEN" \
  --output "${VIDEO_ID}.mp4"

echo "✓ 视频已保存到 ${VIDEO_ID}.mp4"
```

<Callout type="info">
  Rivus AI 会对不同供应商的返回结构进行统一封装，`status` 字段取值为 `queued`、`processing`、`completed`、`failed` 等。视频完成后会包含 `completed_at` 和 `expires_at` 时间戳。
</Callout>

## 计费模型与升级说明

* 计费模式：Sora 视频任务采用“终态实扣，失败不扣”的模式：
  * 创建阶段：仅记录任务与预估信息，不对用户/Token 实际扣费；
  * 终态结算：当任务进入 `completed` 或 `failed` 时，由后台轮询器根据最终时长与价目表一次性结算；
  * 失败任务：不扣费，仅更新计费状态。
* 新旧版本兼容：
  * 老版本曾采用“创建阶段先扣，失败时退款”的策略，部分历史任务的计费记录可能存在“预扣 + 退款”；
  * 新版本仅对创建时 `Quota=0` 的任务启用终态计费；历史数据的对账与核对可以通过 `logs.metadata.platform_task_id` 与 `tasks.platform_task_id` 进行关联审计。

### 脚本示例（Python，本地文件参考图）

仓库提供了基于 openai Python SDK 的本地验证脚本，可通过 `input_reference` 上传参考图并自动轮询与下载：

```bash theme={null}
export OPENAI_BASE_URL="https://models.rivus.cn/v1"
export OPENAI_API_KEY="$TOKEN"

python3 scripts/sora2_image_to_video_sdk.py \
  --prompt "百事可乐宣传片" \
  --seconds 4 \
  --size 720x1280 \
  --image /absolute/path/to/ref.jpg \
  --output sora_video.mp4
```

## 参考图生视频（Image-to-Video）

除纯文本生视频外，Rivus AI 也支持“带参考图”的视频生成。按照 OpenAI Sora 的接口规范，在创建任务时以 multipart/form-data 方式上传参考图文件字段 `input_reference`。

### curl 示例（multipart）

```bash theme={null}
curl -X POST "https://models.rivus.cn/v1/videos" \
  -H "Authorization: Bearer $TOKEN" \
  -F "model=sora-2" \
  -F "prompt=百事可乐宣传片，都市街拍风，年轻活力，镜头运动丰富" \
  -F "seconds=10" \
  -F "size=720x1280" \
  -F "input_reference=@/absolute/path/to/ref.jpg"
```

<Callout type="warning">
  若通道为 OpenAI 官方 API，`seconds` 必须是 4、8 或 12 且需在 multipart 表单中显式提供。请确保 `-F seconds=8` 使用的是纯数字，不要加引号，也不要误用 Bash/Zsh 的保留变量 `SECONDS`。
</Callout>

### Python SDK 示例（openai-python）

```python theme={null}
from openai import OpenAI

client = OpenAI(
    base_url="https://models.rivus.cn/v1",
    api_key="$TOKEN",
)

with open("./ref.jpg", "rb") as f:
    job = client.videos.create(
        model="sora-2",
        prompt="百事可乐宣传片，都市街拍风，年轻活力，镜头运动丰富",
        seconds="10",         # 以字符串传递更兼容
        size="720x1280",
        input_reference=f,     # 关键：参考图文件
    )

print("任务ID:", job.id, "状态:", job.status)

# 轮询
import time
while True:
    cur = client.videos.retrieve(job.id)
    print("状态:", cur.status, "进度:", getattr(cur, "progress", None))
    if cur.status in ("completed", "failed"):
        job = cur
        break
    time.sleep(2)

if job.status == "completed":
    content = client.videos.download_content(job.id)
    content.write_to_file("output.mp4")
    print("已保存到 output.mp4")
else:
    print("生成失败:", getattr(job, "error", None))
```

<Callout type="tip">
  本仓库已提供两个可执行脚本便于本地验证：

  * curl 版本：`scripts/validate_image2video.sh`（自动下载示例参考图、轮询并下载成片）
  * SDK 版本：`scripts/sora2_image_to_video_sdk.py`（基于 openai Python SDK，支持 `--image/--seconds/--size` 参数）
</Callout>


## OpenAPI

````yaml POST /v1/videos
openapi: 3.0.0
info:
  title: OpenAI Video API
  description: OpenAI Sora 视频生成 API
  version: 1.0.0
servers:
  - url: https://models.rivus.cn
    description: Rivus AI 生产环境
security:
  - BearerAuth: []
paths:
  /v1/videos:
    post:
      tags:
        - Videos
      summary: 创建视频任务
      description: 使用 OpenAI Sora 模型创建视频生成任务
      operationId: createVideo
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - model
                - prompt
              properties:
                model:
                  type: string
                  description: 模型名称
                  enum:
                    - sora-2
                    - sora-2-pro
                  example: sora-2
                prompt:
                  type: string
                  description: 视频生成的文本描述，最多 1000 个字符
                  maxLength: 1000
                  example: 百事可乐宣传片
                seconds:
                  type: integer
                  description: >-
                    视频时长（秒）。sora-2 支持 4、8、10、12、15 秒，默认 10；sora-2-pro 支持
                    4、8、12、15、25 秒，默认 15
                  enum:
                    - 4
                    - 8
                    - 10
                    - 12
                    - 15
                    - 25
                  example: 4
                size:
                  type: string
                  description: 视频分辨率
                  enum:
                    - 1280x720
                    - 1920x1080
                    - 720x1280
                    - 1080x1920
                  default: 1280x720
                  example: 720x1280
      responses:
        '200':
          description: 任务创建成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoObject'
              example:
                id: video_691209aab0a08198a4e78870277f7e3d0215e09cec47a737
                object: video
                created_at: 1762789802
                status: queued
                model: sora-2
                prompt: 百事可乐宣传片
                progress: 0
                seconds: '4'
                size: 720x1280
        '400':
          description: 请求参数错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: 认证失败
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 请求频率超限
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    VideoObject:
      type: object
      properties:
        id:
          type: string
          description: 视频任务的唯一标识符
          example: video_691209aab0a08198a4e78870277f7e3d0215e09cec47a737
        object:
          type: string
          description: 对象类型
          enum:
            - video
          example: video
        created_at:
          type: integer
          description: 创建时间戳（Unix 时间）
          example: 1762789802
        completed_at:
          type: integer
          description: 任务完成时间戳（仅在 completed 状态下存在）
          example: 1762789891
        expires_at:
          type: integer
          description: 视频过期时间戳（仅在 completed 状态下存在）
          example: 1762793491
        model:
          type: string
          description: 使用的模型名称
          example: sora-2
        status:
          type: string
          description: 任务状态
          enum:
            - queued
            - processing
            - completed
            - failed
          example: queued
        prompt:
          type: string
          description: 生成视频的文本描述
          example: 一个无人机从海滩升空拍摄夕阳
        progress:
          type: integer
          description: 处理进度（0-100）
          minimum: 0
          maximum: 100
          example: 0
        seconds:
          type: string
          description: 视频时长（字符串格式）
          example: '10'
        size:
          type: string
          description: 视频分辨率
          example: 1280x720
        assets:
          type: array
          description: 生成的视频资源数组，仅在 completed 状态下存在（部分供应商可能不返回此字段，需通过 /content 端点下载）
          items:
            $ref: '#/components/schemas/VideoAsset'
        parent_video_id:
          type: string
          description: 父视频 ID（仅 Remix 任务返回）
          example: video_691209aab0a08198a4e78870277f7e3d0215e09cec47a737
        error:
          type: object
          description: 错误信息，仅在 failed 状态下存在
          properties:
            code:
              type: string
              example: generation_failed
            message:
              type: string
              example: 视频生成失败，请重试
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
              description: 错误描述
              example: Invalid request parameters
            type:
              type: string
              description: 错误类型
              example: invalid_request_error
            code:
              type: string
              description: 错误代码
              example: invalid_parameters
    VideoAsset:
      type: object
      properties:
        url:
          type: string
          description: 视频文件 URL
          example: >-
            https://cdn.example.com/video_691209aab0a08198a4e78870277f7e3d0215e09cec47a737.mp4
        quality:
          type: string
          description: 视频质量/分辨率
          example: 1280x720
        duration:
          type: integer
          description: 视频时长（秒）
          example: 10
        size_bytes:
          type: integer
          description: 文件大小（字节）
          example: 5242880
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 使用 API Key 作为 Bearer Token

````