Seedance 2.0 API 教程:用 Python 做文生视频和图生视频
一个脚本就能建任务、轮询并保存 MP4。下面写清请求字段和限制,还有我们在 2026 年 10 月 30 日生成的两条 5 秒视频。
本页内容
Seedance 2.0 跑在 OmniaKey 的媒体 API 上,模型 ID 是 dreamina-seedance-2-0-260128。流程分三步:向 https://api.omniakey.com/v1/media/tasks 提交任务,轮询任务 ID,最后下载 MP4。我们在 2026 年 10 月 30 日生成的两条 720p 视频都是 5 秒,一条来自文字,一条来自静态图。两条分别用了 159 秒和 139 秒。
先说结论
- 模型 ID 是
dreamina-seedance-2-0-260128,有三个操作:text_to_video、image_to_video、reference_to_video(OmniaKey 的 视频 API 文档,2026 年 10 月 30 日核对)。 - 建任务、轮询、下载:创建请求返回 202 和任务 ID,之后每隔几秒 GET 一次
/v1/media/tasks/{id},直到状态变成succeeded。查询规则见 OmniaKey 的 媒体 API 概览,2026 年 10 月 30 日核对。 - 时长是 4 到 15 的整数秒。完整 2.0 ID 能出 480P、720P 和 1080P。
- 整个请求体不超过 1 MiB,内联 base64 也算在里面。
- 我们这两条 5 秒 720p 视频,文生视频用了 159 秒,图生视频用了 139 秒。
第一次调用前要准备什么?
需要 OmniaKey 的 API key、Python 3 和完整的模型 ID。脚本只导入标准库,不用建虚拟环境,也不用装包。
第一次调用前把 key 导出为 OMNIAKEY_API_KEY。脚本只读一次,每次请求都作为 Bearer token 发送。key 不会写进文件,也不会进 git 历史。
创建任务用 POST https://api.omniakey.com/v1/media/tasks,轮询用 GET https://api.omniakey.com/v1/media/tasks/{id}。再加上取消任务的 POST /v1/media/tasks/{id}/cancel,媒体 API 就这三个接口(媒体 API 概览,2026 年 10 月 30 日核对)。
模型 ID 要写全。OmniaKey 不提供 seedance-2 和 seedance-2-5 这类短别名,调用会返回 503 no_available_channel(视频 API 文档,2026 年 10 月 30 日核对)。
视频任务按生成结果每秒预扣费。任务以 failed 或 canceled 结束时,扣掉的费用自动退回(媒体 API 概览,2026 年 10 月 30 日核对)。每秒多少钱看 Seedance 2.0 模型页 上的现价。
Seedance 2.0 请求要填哪些字段?
四个顶层字段承载任务,parameters 对象放输出设置。只有 duration 没有合理默认值,每次都要传。
model:完整模型 ID(短别名会失败)type:video(媒体类型)operation:text_to_video、image_to_video、reference_to_video(只写名字,不带前缀)input.prompt:一个字符串(场景、动作和镜头,最多 12,000 字符)input.media[]:{"type": "first_frame", "url": …}(首帧,或者reference_image)
parameters 里的字段:
duration:4 到 15 的整数秒(决定价格)resolution:480P、720P、1080P(Fast 和 Mini 最高 720P)ratio:16:9、9:16、1:1、4:3、3:4、21:9、adaptive(adaptive跟随画面)generate_audio:默认true,也可以false(false得到无声 MP4)n:1(只能是 1)
这两份清单来自 OmniaKey 的 视频 API 文档 和 媒体 API 概览,2026 年 10 月 30 日核对。提示词长度上限来自模型页。
操作名只写名字,媒体类型前缀由 OmniaKey 补上(视频 API 文档,2026 年 10 月 30 日核对)。不认识的参数会原样转给服务商(媒体 API 概览,2026 年 10 月 30 日核对)。
从厂商文档入手的人常踩一个坑。BytePlus 自己的建任务接口把字段放在 content[] 和顶层。BytePlus 教程里的代码原样搬到 /v1/media/tasks 上跑不通(BytePlus 建任务接口,2026 年 10 月 30 日核对)。
Python 脚本
一个文件同时跑两个操作,区别只在构造的请求体。存成 seedance_video.py,运行 python3 seedance_video.py。
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "dreamina-seedance-2-0-260128"
def request(method, url, body=None, extra_headers=None):
headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
data = None
if body is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(body).encode()
headers.update(extra_headers or {})
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def poll(url, attempts=5):
for attempt in range(attempts):
try:
return request("GET", url)
except urllib.error.HTTPError as err:
if err.code < 500 or attempt == attempts - 1:
raise
except urllib.error.URLError:
if attempt == attempts - 1:
raise
time.sleep(5 * (attempt + 1))
def run_task(body, out_path):
task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
print("task", task, flush=True)
for _ in range(180): # 每 5 秒查询一次,最多 15 分钟
time.sleep(5)
state = poll(f"{API}/{task}")
if state["status"] not in ("queued", "processing"):
break
else:
raise TimeoutError(f"{task} is still {state['status']}: poll it again later, do not resubmit")
if state["status"] != "succeeded":
raise RuntimeError(state.get("error") or state["status"])
asset_url = state["assets"][0]["url"] # 签名链接有效期短,马上下载
req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
f.write(resp.read())
return task
def text_to_video(prompt, out_path, duration=5, resolution="720P", ratio="16:9"):
body = {
"model": MODEL,
"type": "video",
"operation": "text_to_video",
"input": {"prompt": prompt},
"parameters": {"duration": duration, "resolution": resolution, "ratio": ratio},
}
return run_task(body, out_path)
def image_to_video(prompt, image_path, out_path, duration=5, resolution="720P", audio=False):
with open(image_path, "rb") as f:
raw = f.read()
if len(raw) > 700_000: # base64 会让体积增加三分之一,整个请求体必须低于 1 MiB
raise ValueError("first frame too large: save it as a JPEG about 1024 px wide")
frame = "data:image/jpeg;base64," + base64.b64encode(raw).decode()
body = {
"model": MODEL,
"type": "video",
"operation": "image_to_video",
"input": {"prompt": prompt, "media": [{"type": "first_frame", "url": frame}]},
"parameters": {"duration": duration, "resolution": resolution, "ratio": "adaptive",
"generate_audio": audio},
}
return run_task(body, out_path)
if __name__ == "__main__":
print("done", text_to_video(
"Close-up of a tall glass on a wooden bar counter. Sparkling water is poured over ice; bubbles "
"rise and the ice cubes clink and shift. Warm evening light from the left. The camera slowly "
"pushes in. Sound of pouring, fizzing and clinking ice. No people, no text.",
"sparkling-glass.mp4",
))
print("done", image_to_video(
"The cat slowly wakes, stretches its front paws and yawns, then looks toward the window. "
"Raindrops keep running down the glass. The camera stays still.",
"cat.jpg",
"cat-wakes.mp4",
))
改代码之前,先看这六点。
- 每个创建请求都带一个随机的
Idempotency-Key。用同一个 key 和同一个请求体重放,返回原来的任务和 HTTP 200,不会重复扣费。这条规则见媒体 API 概览,2026 年 10 月 30 日核对。 - 循环每 5 秒查询一次,180 次后停下,也就是 15 分钟。
- 超时说明任务还在渲染。过一会儿用同一个任务 ID 再查,不要重新提交,否则要付第二条视频的钱。
assets[0].url是签名链接,大约一小时后失效,所以任务成功后脚本立刻下载(媒体 API 概览,2026 年 10 月 30 日核对)。- 任务运行时
progress.percent可能一直是 0,所以循环只看status(视频 API 文档,2026 年 10 月 30 日核对)。 - 图片函数拒绝超过 700,000 字节的文件,因为 base64 会让体积增加三分之一,请求体必须低于 1 MiB。
请求结构和 同一个 API 上的 Kling 3.0 一样。换模型只改模型 ID 和参数,周围的代码不用动。
图生视频的首帧怎么传?
把图片放进 input.media[],写上 "type": "first_frame",用 data:image/jpeg;base64,... 形式内联。我们的猫咪视频就是这么传的。
input.media[] 接受公开的 HTTPS 链接,也接受内联的 data URI。整个请求体上限 1 MiB(视频 API 文档,2026 年 10 月 30 日核对)。OmniaKey 自己测试时,普通的 HTTPS 首帧链接被拒绝,返回 provider_submit_rejected。所以示例改用 data URI(视频 API 文档,2026 年 10 月 30 日核对)。
base64 会让体积增加三分之一,所以从宽度约 1024 像素的 JPEG 开始。我们的首帧是 134,356 字节,一个 4 MB 的 PNG 会被拒绝。
这里把 parameters.ratio 保持为 adaptive,它会跟随你发来的图片形状。1024×571 的静态图就是这样变成了 1280×720 的视频。做 reference_to_video 时,同一个数组改用 "type": "reference_image"(视频 API 文档,2026 年 10 月 30 日核对)。
我们生成的两条视频
两个任务都在 2026 年 10 月 30 日提交,用的就是上面这个文件,一个字没改。第一条是文生视频,任务 task_uF2QUtbeAAUW11lXEaLxNw1ZnBUoqvNk,创建于 01:39:43 UTC,01:42:22 UTC 成功。提示词里要求了倒水的声音,所以音频保持开启。
Close-up of a tall glass on a wooden bar counter. Sparkling water is poured over ice; bubbles rise and the ice cubes clink and shift. Warm evening light from the left. The camera slowly pushes in. Sound of pouring, fizzing and clinking ice. No people, no text.

画面里是一只放在木制吧台上的玻璃杯,杯中有冰块,背景是模糊的酒瓶和暖光。杯子从第一帧到最后一帧逐渐变大,这正是提示词要的推镜,最后满杯,气泡沉在杯底。
第二条是图生视频,任务 task_u85W0jn1sQLkrszJlxqXF1hxJYhsndxK,创建于 01:42:33 UTC,01:44:52 UTC 成功。首帧是一张静态图:一只橘猫睡在雨窗边的一摞旧书上(1024×571 像素),以 data URI 加 "type": "first_frame" 发送。
The cat slowly wakes, stretches its front paws and yawns, then looks toward the window. Raindrops keep running down the glass. The camera stays still.

猫抬起头,睁开眼睛,两只前爪伸到书堆边缘外伸懒腰,张大嘴打哈欠,然后转头看向窗户,顺序和提示词一致。雨一直顺着玻璃往下流,镜头保持不动,和提示词要求的一样。

这两次运行覆盖了文生视频和 720P 的 5 秒首帧。1080P、Fast、Mini、2.5、reference_to_video、HTTPS 首帧链接和其它时长都没有测。
文件实测数据
两条下载都是 H.264 MP4,1280×720,24 fps:121 帧,5.04 秒。
| 视频 | 玻璃杯 | 猫咪 |
|---|---|---|
| 操作 | 文生视频 | 图生视频 |
| 完成时间 | 159 秒 | 139 秒 |
| 文件大小 | 2,070,248 字节 | 1,352,027 字节 |
| 画面 | 1280×720,24 fps,121 帧 | 1280×720,24 fps,121 帧 |
| 音频 | AAC 音轨 | 无 |
玻璃杯那条有倒水、气泡和冰块碰撞的声音,没有人声,也没有音乐。猫咪那条完全没有音轨,因为请求里发的是 generate_audio: false。
两条任务记录都写着 usage.completion_tokens: 108900。这个数等于 121 × 1280 × 720 ÷ 1024。这是 BytePlus 估算视频费用的 token 公式(BytePlus 价格页,2026 年 10 月 30 日核对)。
OmniaKey 的文档说 6 秒 720p 视频通常一分钟左右完成(视频 API 文档,2026 年 10 月 30 日核对)。我们这两条用了 159 秒和 139 秒。10 月 26 日那次对比 里的三条 5 秒 720p 视频用了 144.8、319.0 和 184.7 秒。按 2 到 5 分钟规划,用轮询,别一直挂着请求。
会碰到哪些报错和限制?
先检查三个设置:模型 ID、4 到 15 的时长、音频。服务商的过滤可能拒绝音频。
| 状态码 / 错误码 | 要改什么 |
|---|---|
400 invalid_request | 请求体或 input.prompt |
400 model_price_error | 时长改成 4 到 15 秒 |
403 model_not_allowed | key 的模型权限 |
409 idempotency_key_reused | 每个请求体用新的 key |
503 no_available_channel | 写完整 ID,操作名去掉前缀 |
| 任务失败、服务商报错 | 读 error,然后重试 |
这些错误码来自媒体 API 概览和视频 API 文档(2026 年 10 月 30 日核对)。以 failed 结束的任务会退回预扣费,被拒的渲染只花时间,不花钱。
音频设置要留意。Seedance 默认生成音轨,保持开启时,服务商拒绝了一条 4 秒 480P 的请求,返回 OutputAudioSensitiveContentDetected.PolicyViolation。场景不需要声音就发送 parameters.generate_audio: false(视频 API 文档,2026 年 10 月 30 日核对)。
BytePlus 说 2.0 系列不接受含真实人脸的参考图或参考视频。这条写在 BytePlus 的 Seedance 2.0 页面,2026 年 10 月 30 日核对。Seedance 2.0 也没有 seed 和 camera_fixed,厂商的建任务接口里这两个字段都有(BytePlus 建任务接口,2026 年 10 月 30 日核对)。
15 秒是这个系列的上限,duration: -1 也换不来更长的视频。20 秒或 30 秒的镜头要用 Seedance 2.5(Seedance 2.0 模型页,2026 年 10 月 30 日核对)。
OmniaKey 没有公布固定的频率限制。遇到 HTTP 429 就当作可重试,用逐渐拉长的间隔重试(OmniaKey 的 API 报错页,2026 年 10 月 30 日核对)。
Seedance 2.0、Fast、Mini 还是 2.5?
四个档位用同一个请求体,切换只改一个模型 ID,Fast 和 Mini 的分辨率上限更低。
- Seedance 2.0,
dreamina-seedance-2-0-260128:480P、720P、1080P,4 到 15 秒。BytePlus 标价 5 秒视频 720p 为 $0.76,480p 为 $0.35(BytePlus 价格页,2026 年 10 月 30 日核对)。 - Seedance 2.0 Fast,
dreamina-seedance-2-0-fast-260128:480P、720P,4 到 15 秒。5 秒视频 720p 为 $0.60,480p 为 $0.28。 - Seedance 2.0 Mini,
dreamina-seedance-2-0-mini-260615:480P、720P,4 到 15 秒。5 秒视频 720p 为 $0.38,480p 为 $0.18。 - Seedance 2.5,
dreamina-seedance-2-5-260628:这个系列里唯一能出 20 秒或 30 秒镜头的 ID,也是最慢的。4 秒 480P 视频大约四分钟(视频 API 文档,2026 年 10 月 30 日核对)。画面效果见我们的 Seedance 2.5 评测。
OmniaKey 的模型页显示,4 秒 480P 视频在 2.0 上约一分钟。Fast 约两分钟,Mini 约 100 秒(2026 年 10 月 30 日核对)。
需要 1080P 成片就用完整的 2.0 ID,Fast 和 Mini 最高只到 720P(视频 API 文档,2026 年 10 月 30 日核对)。这几个 ID 的价格由 OmniaKey 自己定,现价看 Seedance 2.0 模型页。
常见问题
Seedance 2.0 有官方 API 吗?
有。BytePlus ModelArk 出售这个模型,开通需要账户余额高于 USD 30,或者有 Savings Plan、Seedance 资源包。这些条件写在 BytePlus 的 Seedance 2.0 页面,2026 年 10 月 30 日核对。上面的脚本改用 OmniaKey 的媒体 API 调同一个模型 ID。
可以传图片链接代替 base64 吗?
OmniaKey 的文档在 data URI 之外也列了公开 HTTPS 链接(视频 API 文档,2026 年 10 月 30 日核对)。我们的测试用了内联方式,因为 OmniaKey 自己测试时 HTTPS 首帧链接返回了 provider_submit_rejected,所以先用一条测试视频试链接。
怎么关掉声音?
发送 parameters.generate_audio: false,MP4 就完全没有音轨,猫咪那条就是这样。这个模型默认开启音频。
请求为什么超时?
视频通常还在渲染,我们的 5 秒 720p 任务用了 139 到 319 秒。用同一个任务 ID 再查,不要重新提交。15 秒的视频要把 15 分钟的循环上限调高。
视频链接能留多久?
assets[0].url 里的签名链接大约一小时后失效,任务记录本身在创建后保留 24 小时(媒体 API 概览,2026 年 10 月 30 日核对)。第一次成功就下载,或者再查一次任务拿新链接。
参考来源
- BytePlus ModelArk:Seedance 2.0 指南,2026 年 10 月 30 日核对
- BytePlus ModelArk:创建视频生成任务 API,2026 年 10 月 30 日核对
- BytePlus ModelArk:模型价格与 token 计算公式,2026 年 10 月 30 日核对
OmniaKey 自己的文档,2026 年 10 月 30 日核对:视频 API、媒体 API 概览 和 API 报错。
