文档
视频生成
使用 Google Veo 3.1 系列将文本或图像转换为视频。提供两种 API 形式:一种是一次性同步端点,会阻塞等待视频片段就绪;另一种是用于生产工作负载的提交并轮询异步端点组合。
端点:POST /v1/video/generations(同步,先介绍),以及 POST /v1/videos + GET /v1/videos/{id}(异步,推荐用于生产环境)。生成时间视模型和时长而定,从 30 秒到数分钟不等——使用同步端点时,请将客户端超时设置得足够长(600s 是安全值)。
文本生成视频
传入 prompt 并选择模型。aspect_ratio 可选。
import requests
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane unfolding, soft light",
"aspect_ratio": "16:9",
},
timeout=600, # video generation can take minutes
)
print(resp.json()["data"][0]["url"])duration(秒)用于在按秒计费的模型(Seedance 系列模型和 Wan 2.7)上设置片段时长。Veo 模型会忽略它;每个 Veo 片段都是 8 秒,按视频计费。
# The models billed per second take a clip length: here 5 seconds of
# Seedance 2. Leave "duration" out and these models make a 5-second clip.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "seedance-2",
"prompt": "a paper crane unfolds into a flock of birds over a city at dawn",
"duration": 5,
"aspect_ratio": "16:9",
},
timeout=600,
)
print(resp.json()["data"][0]["url"])图像生成视频
添加 image_url,Veo 就会以它为基础生成动画——默认情况下,静态图像会成为视频的第一帧。
# Image-to-video: animate a still image. The source image can be an
# https URL, or inline base64 — Kunavo hosts it for the model automatically.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "the crane gently lifts off the desk",
"image_url": "https://your-cdn.com/source.png",
},
timeout=600,
)
print(resp.json()["data"][0]["url"])image_url 接受 https:// URL 或内联 data: base64 URI。运行模型前,Kunavo 会自动解码 base64 并将其托管到 Kunavo CDN。首帧、尾帧和参考图
image_mode 控制 Veo 如何使用图像。传入 image_urls(数组)可发送多张图像。
frame(默认)— 一张图像作为首帧;两张图像分别作为首帧和尾帧,Veo 会生成两帧之间的过渡。reference— 最多三张图像可用作风格和主体参考。它们会引导生成效果,但不会作为视频帧出现。
# First + last frame: pass two images and Veo fills in the motion.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "a smooth transition between the two poses",
"image_urls": [
"https://your-cdn.com/first.png",
"https://your-cdn.com/last.png",
],
"image_mode": "frame",
},
timeout=600,
)上传源帧
如果只有本地文件,请通过 POST /v1/files 上传一次,并重复使用返回的永久 URL。
# No public URL? Upload the still first, then animate it.
with open("frame.png", "rb") as f:
up = requests.post(
"https://api.kunavo.com/v1/files",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
).json()
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "slow push-in, volumetric light",
"image_url": up["url"],
},
timeout=600,
)参数
| 参数 | 类型 | 备注 |
|---|---|---|
model | 字符串(必填) | 来自 /v1/models 的视频模型标识。 |
prompt | 字符串(必填) | 镜头的文本描述。 |
image_url | string | 用于图生视频的单张源图像。URL 或 data: URI。 |
image_urls | string[] | 多个源图像(Veo)。优先级高于 image_url。 |
image_mode | string | Veo:"frame"(默认 — 首帧/ |
duration | int | 按秒计费模型的片段时长,单位为秒,省略时为 5:Seedance 2、Seedance 2 Fast 和 Seedance 2.0 Mini 支持 4–15,Seedance 2.5 支持 4–30,Wan 2.7 支持 2–15。超出模型范围的时长会被拒绝,并返回 400。Veo 会忽略该参数:每个 Veo 片段都是 8 秒。 |
aspect_ratio | string | 例如 "16:9"、"9:16"、"1:1"。 |
resolution | string | 模型提供多个档位时使用,例如 "720p"、"1080p"。 |
input | object | 备用方案 — 见下文的 Raw input。 |
原始输入直通选项
在按秒计费的模型上,input 会按原样发送至上游,替代我们的适配器原本会构建的输入。Veo 模型会忽略它。
决定价格的字段是例外:resolution 始终会以该模型的某个档位发送(未提供该字段或其值不是该模型的档位时,发送默认档位),duration 必须是该模型范围内的整数秒数(其他任何值都会被拒绝,并返回 400;未提供该字段时发送 5)。设置了 input 时,不会读取请求自身的 resolution 和 duration。
视频模型
| 标识符(slug) | 提供商 | 备注 |
|---|---|---|
veo-3 | Veo 3.1 Fast — 比 Quality 更快、更便宜,原生支持音频。 | |
veo-3-quality | Veo 3.1 Quality — 最高保真度。 | |
veo-3-lite | Veo 3.1 Lite — 面向预览的经济档。 | |
seedance-2-5 | ByteDance | Seedance 2.5 — 支持最长 30 秒的视频片段和多模态参考,按秒计费。 |
seedance-2 | ByteDance | Seedance 2 — 支持多镜头一致性,最高 1080p,按秒计费。 |
seedance-2-fast | ByteDance | Seedance 2 Fast — 经济档,最高 720p,按秒计费。 |
seedance-2-mini | ByteDance | Seedance 2.0 Mini — 最低价档,仅支持 480p/ |
wan-2-7 | Alibaba | Wan 2.7 — 电影质感的文本生成视频,按秒计费。 |
请始终查看 /models,以获取实时模型列表和各模型定价。
延迟和超时
- Kunavo 最多轮询上游任务 540 秒,之后会返回 504。
- 快速档(Veo 3.1 Fast / Lite):通常为 30–90 秒。
- 高质量档和较长时长:2–5 分钟。
- 将 HTTP 客户端超时设置为至少 600s。
- 如果网络不稳定或使用移动客户端,请优先使用异步 API——提交请求会在数秒内返回,然后你可以轮询获取结果。
异步 API(提交 + 轮询)
端点:POST /v1/videos + GET /v1/videos/{id}。它们返回的任务对象使用 OpenAI 视频对象的字段名称和状态值,并额外包含一个存放视频片段 URL 的 output 字段。请求体为包含上述参数的 JSON。
上面的同步端点会保持 HTTP 连接打开,最长可达九分钟——适合一次性脚本,但在移动网络上不可靠,也会降低服务器效率。异步端点组合会立即返回一个 vid_* ID;你可以轮询 GET /v1/videos/{id},直到 status 变为 completed 或 failed。模型相同、价格相同,归档的 URL 也相同。
import requests, time
# 1. Submit — returns immediately with a task id. No long-lived connection.
submit = requests.post(
"https://api.kunavo.com/v1/videos",
headers={
"Authorization": f"Bearer {API_KEY}",
# Optional: retrying with the same key inside ~24h returns the
# original task rather than submitting again.
"Idempotency-Key": "my-task-uuid",
},
json={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane",
"aspect_ratio": "16:9",
},
timeout=60,
).json()
task_id = submit["id"] # "vid_abc..."
status = submit["status"] # "queued"
# 2. Poll until terminal. Recommended cadence: 5s, backing off to 30s.
while status not in ("completed", "failed"):
time.sleep(5)
r = requests.get(
f"https://api.kunavo.com/v1/videos/{task_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
).json()
status = r["status"]
if status == "failed":
raise RuntimeError(r["error"]["message"])
print(r["output"]["url"])使用 OpenAI SDK 发送该请求体时,请使用 client.post,并按下文所示使用 client.get 轮询。SDK 自带的 client.videos.create 在这里无法使用:它只接受 Sora 的参数,并会以 multipart 表单的形式发送这些参数(Python SDK 自版本 2.27.0 起),而此端点会以 400 错误拒绝这种请求。
import time
from openai import OpenAI
client = OpenAI(api_key=API_KEY, base_url="https://api.kunavo.com/v1")
# The same JSON body, sent with the client's own post().
task = client.post(
"/videos",
body={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane",
"aspect_ratio": "16:9",
},
# object hands back the JSON as parsed. Passing dict instead raises
# after the task has been created.
cast_to=object,
options={"headers": {"Idempotency-Key": "my-task-uuid"}},
)
while task["status"] not in ("completed", "failed"):
time.sleep(5)
task = client.get(f"/videos/{task['id']}", cast_to=object)
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
print(task["output"]["url"])响应格式
| 字段 | 类型 | 备注 |
|---|---|---|
id | string | 以 vid_ 为前缀的任务 ID。在上游发生更改时保持稳定。 |
object | string | "video". |
status | string | queued | in_progress | completed | failed。 |
model | string | 提交时指定的模型 slug。 |
created_at | int | 我们接受提交请求时的 Unix 秒数。 |
completed_at | int | null | 进入终态时的 Unix 秒数 ——任务待处理时为 null。 |
expires_at | int | 提交后满 30 天时的 Unix 秒数:至少在此之前都可以轮询该任务。其结果 URL 不会过期。 |
progress | int | 0–100。任务结束前当前报告值为 0,结束后为 100。 |
output | object | null | 完成时返回 {url, urls[], duration_ |
error | object | null | 失败时返回 {code, message}。 |
请求头与约定
Idempotency-Key(可选,最多 128 个字符)— 在同一账户下使用相同的密钥提交两次,会返回原任务而不会创建重复任务。适用于重试循环。- 全新提交时,
POST /v1/videos返回 202 Accepted;幂等键命中并重放先前结果时,返回 200 OK。 GET /v1/videos/{id}按所有者进行范围限定:查询属于其他账户的任务会返回 404——我们绝不会确认其他用户的任务 ID 是否存在。- 建议的轮询间隔:5 s,并采用指数退避,最长间隔为 30 s。任务通常会在 30 s – 5 min 内完成,具体取决于模型和分辨率。
何时使用哪种方式
| 同步 /v1/ | 异步 /v1/videos | |
|---|---|---|
| 适用场景 | 一次性脚本、笔记本 | 适用于生产环境、移动端和长时间运行的任务 |
| 网络 | 连接最长保持 9 分钟 | 几秒内提交;按你的时间安排轮询 |
| 故障恢复 | 丢失响应 = 丢失任务 | expires_at 到期前随时重新查询该 ID |
| 并发数 | 每次调用占用一个服务器工作进程 | 提交后立即释放连接 |
| 响应格式 | OpenAI /images/ | OpenAI /videos 格式 |
响应与存储
响应采用 OpenAI 的标准格式 — data[].url。URL 是一个永久的 files.kunavo.com 链接:Kunavo 会将每个结果归档到自己的 CDN,因此与原始上游 URL 不同,它永不过期。每个视频片段也会显示在 /app/assets 中。