Seedance 2.0 图像转视频 API:全面控制任意图像动画化
学习使用 Seedance 2.0 API 将图像动画化——单图、首尾帧、多图工作流。完整 Python 代码、@tag 语法和电商演示。

Seedance 2.0 图像转视频 API:全面控制任意图像动画化
一张躺在硬盘里的产品照片不会产生任何互动。而一段 10 秒的产品视频——产品在影棚灯光下旋转、配有同步音效——却能带来点击、分享和销售转化。Seedance 2.0 的图像转视频 API 可以将任何静态图片变成完全可控的视频——只需一个 POST 请求。
本指南涵盖三种不同的图像转视频模式:单图动画、首尾帧插值和使用 @tag 引用的多图合成。每个章节都包含完整的、可直接运行的 Python 代码、真实演示输出,以及生成这些演示所使用的确切提示词。
Seedance 2.0 的图像转视频有何不同
目前每个主流 AI 视频平台都提供某种形式的图像转视频生成。Sora 接受单张图片作为起始帧。Kling 提供基本运动控制的图像动画。Veo 2 支持图像条件化以进行风格引导。它们都在解决同一个表面问题:把图片变成动态画面。
Seedance 2.0 解决的是一个完全不同的问题。它让你在单次生成请求中对多张图片拥有组合式控制——并通过一套目前没有其他 API 能匹配的标签系统来实现。
核心差异
| 能力 | Sora | Kling | Veo 2 | Seedance 2.0 |
|---|---|---|---|---|
| 单图转视频 | ✅ | ✅ | ✅ | ✅ |
| 首尾帧控制 | ❌ | ✅(有限) | ❌ | ✅ |
| 多图合成 | ❌ | ❌ | ❌ | ✅(最多 9 张图片) |
| 逐图角色分配 | ❌ | ❌ | ❌ | ✅(@Image1、@Image2……) |
| 混合媒体(图片 + 视频 + 音频) | ❌ | ❌ | ❌ | ✅(最多 12 个文件) |
| 原生音频生成 | ❌ | ❌ | ❌ | ✅ |
| API 优先访问 | 候补名单 | ✅ | 有限 | ✅ |
@tag 系统是 Seedance 2.0 的领先之处。当你上传三张图片时,可以这样编写提示词:
@Image1 is the main character. @Image2 is the background environment.
@Image3 is the art style reference. The character walks through the environment
in the style of @Image3.
每张图片都获得一个特定的语义角色。模型不需要猜测哪张图片是角色、哪张是背景——你明确告诉它。关于这个标签系统的深入解读,请参阅多模态 @Tags 指南。
为什么 @Tags 对开发者很重要
如果你使用过其他图像转视频 API,你一定了解那种挫败感:你上传多张图片,然后寄希望于模型能理解你的意图。有时候它把背景图当作角色使用。有时候它把所有图片混成一团不连贯的画面。这无法调试,因为你无法控制模型如何解读每个输入。
@tag 系统消除了这种不确定性。它本质上是一个变量绑定系统——你为每个输入命名,并在指令中显式引用它。这使得图像转视频生成变得确定且可复现。相同的输入、相同的标签、相同的提示词,每次都会得到相同的语义解读。
对于生产流水线来说,这就是"试试看效果"和"配置好就上线"之间的区别。你可以构建模板、验证输出、针对特定元素进行迭代,而不会让整个画面构成不可预测地发生变化。
原生音频改变了输出
大多数 AI 图像转视频工具生成的是无声片段。你需要单独进行音频生成、单独调用一个 API,然后通过视频编辑将二者合并。Seedance 2.0 通过设置 generate_audio: true,在同一个请求中生成同步音频。脚步声与行走动作匹配。风声与户外场景匹配。这省去了整个后期制作步骤。
不支持的功能
Seedance 2.0 不支持在图像转视频生成中使用真实人脸。如果你的输入图像包含照片级真实的人脸,API 将自动拒绝该请求。插画角色、风格化面孔、动漫角色和非写实肖像都可以正常使用。这是一项审慎的安全限制,而非技术缺陷。
快速设置:API 密钥和环境
你需要三样东西:一个 EvoLink 账户、一个 API 密钥和 requests 库。整个设置不到一分钟。
第 1 步:获取 API 密钥
- 前往 evolink.ai 创建一个免费账户
- 在控制面板中导航到 API Keys 部分
- 生成一个新密钥并复制它
你的密钥以 sk- 开头,看起来像这样:sk-XpXn...Ms1N。
第 2 步:安装依赖
pip install requests
就是这样。无需安装 SDK,无需复杂的认证流程。该 API 使用标准 REST 和 Bearer Token 认证。
第 3 步:设置 Python 环境
import requests
import time
import json
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
本指南中的每个代码示例都基于这三个变量。将 YOUR_API_KEY 替换为你的实际密钥即可开始生成。
轮询辅助函数
由于视频生成需要 60–180 秒,你需要一个函数来轮询完成状态。这个辅助函数适用于所有三种图像转视频模式:
def wait_for_video(task_id, interval=5, max_wait=300):
"""Poll the task endpoint until the video is ready."""
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
resp = requests.get(url, headers=HEADERS)
data = resp.json()
status = data["status"]
if status == "completed":
video_url = data["output"]["video_url"]
print(f"Video ready: {video_url}")
return data
elif status == "failed":
print(f"Generation failed: {data.get('error', 'Unknown error')}")
return data
print(f"Status: {status} ({elapsed}s elapsed)")
time.sleep(interval)
elapsed += interval
print("Timed out waiting for video")
return None
任务状态遵循一个简单的生命周期:pending → processing → completed 或 failed。响应中的视频 URL 在 24 小时后过期——请在此之前下载或使用它们。
关于 API 基础知识(文本转视频、参数、错误处理)的完整演练,请参阅入门指南。
模式 1:单图动画
单图动画是最常见的图像转视频工作流。你提供一张图片和一段描述所需运动的提示词。模型会保留你图片的视觉内容,同时添加逼真的运动、镜头运动和环境效果。
工作原理
当你在 image_urls 中只传入一个 URL 时,Seedance 2.0 将其视为主要视觉参考。模型将第一帧锚定到你的图片,并根据提示词生成向前的运动。输出会保留:
- 源图像的色彩调性
- 构图和画面布局
- 主体特征(服装、形状、细节特征)
- 艺术风格(插画、3D 渲染、摄影)
你的提示词控制变化的内容:运动、镜头角度、光照变化和环境动态。
完整代码:单图转视频
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
def wait_for_video(task_id, interval=5, max_wait=300):
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
resp = requests.get(url, headers=HEADERS)
data = resp.json()
status = data["status"]
if status == "completed":
print(f"Video ready: {data['output']['video_url']}")
return data
elif status == "failed":
print(f"Failed: {data.get('error', 'Unknown error')}")
return data
print(f"Status: {status} ({elapsed}s)")
time.sleep(interval)
elapsed += interval
return None
# --- Single Image Animation ---
payload = {
"model": "seedance-2.0",
"prompt": (
"The woman in the painting slowly reaches for a coffee cup on the table, "
"lifts it to her lips, and takes a quiet sip. Soft morning light filters "
"through a nearby window. Gentle steam rises from the cup. "
"Painterly brushstroke texture preserved throughout."
),
"image_urls": [
"https://example.com/painting-woman.jpg"
],
"duration": 8,
"quality": "1080p",
"aspect_ratio": "16:9",
"generate_audio": True
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
result = resp.json()
print(f"Task ID: {result['task_id']}")
# Poll until complete
video_data = wait_for_video(result["task_id"])
用你自己的 API 密钥运行此代码。 将
image_urls的值替换为任何公开可访问的图片 URL。
演示:画中人栩栩如生
使用的提示词: "The woman in the painting slowly reaches forward, picks up a coffee cup from the table, and takes a quiet sip. Soft indoor lighting. Painterly brushstroke style maintained. Subtle steam rises from the cup."
此演示使用单张油画肖像作为 @Image1(角色参考)。模型在生成自然的手臂运动和蒸汽物理效果的同时,保留了油画美学风格。
演示:风格迁移动画
使用的提示词: "A young girl walks along a winding path through a Van Gogh-style village. Swirling sky with thick brushstrokes. Vibrant yellows and blues. The girl's dress and hair flow in the wind. Camera slowly follows her from behind."
请注意输入图像中的梵高笔触风格如何贯穿每一帧——旋转的天空、建筑物上的厚涂质感、色彩关系。单图动画在风格一���的运动生成方面表现出色。
单图模式的提示词最佳实践
你的提示词决定了动画的质量。静态描述产生静态视频。富含运动的提示词产生动态输出。
弱提示词:
A cat sitting on a windowsill
强提示词:
The cat stretches lazily on the windowsill, yawns wide showing tiny teeth,
then curls back into a ball. Afternoon sunlight shifts slowly across the fur.
Dust motes float in the light beam. Camera holds steady, slight depth of field.
差异在于:强提示词指定了连续动作(伸展 → 打哈欠 → 蜷缩)、环境运动(阳光变化、浮尘)和镜头行为(固定、浅景深)。
单图提示词的关键原则:
| 原则 | 示例 |
|---|---|
| 描述运动,而非外观 | "walks forward" 而非 "a person standing" |
| 排列 2-3 个连续动作 | "picks up → examines → sets down" |
| 添加环境动态 | "wind rustles leaves"、"rain beads on glass" |
| 指定镜头运动 | "slow pan left"、"camera pulls back to reveal" |
| 匹配图片的艺术风格 | "painterly strokes preserved"、"3D render quality" |
关于完整的提示词工程参考,请参阅 Seedance 2.0 提示词指南。关于镜头运动的专门技巧,请参阅镜头运动指南。
模式 2:首尾帧控制
单图模式锚定视频的开头。首尾帧模式则锚定两端。你提供两张图片——开始帧和结束帧——Seedance 2.0 会在两者之间生成平滑过渡。
工作原理
当 image_urls 恰好包含两个 URL 时,模型会将它们解读为:
- 第一个 URL → 起始帧
- 第二个 URL → 结束帧
模型随后生成中间帧,创建自然、物理上合理的过渡。你的提示词引导过渡的风格——无论是平滑变形、叙事旅程还是戏剧性变换。
应用场景
首尾帧控制解决了单图模式无法处理的问题:
- 前后对比展示:翻新、改造、季节变化
- 延时模拟:从黎明到黄昏、从空房间到陈设齐全的房间
- 场景过渡:一个场景变形为另一个场景
- 产品变换:从封闭包装到打开的产品展示
- 变形效果:一个角色或风格变成另一个
完整代码:首尾帧插值
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
def wait_for_video(task_id, interval=5, max_wait=300):
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
resp = requests.get(url, headers=HEADERS)
data = resp.json()
status = data["status"]
if status == "completed":
print(f"Video ready: {data['output']['video_url']}")
return data
elif status == "failed":
print(f"Failed: {data.get('error', 'Unknown error')}")
return data
print(f"Status: {status} ({elapsed}s)")
time.sleep(interval)
elapsed += interval
return None
# --- First-Last Frame Control ---
payload = {
"model": "seedance-2.0",
"prompt": (
"Smooth cinematic transition. The real-world landscape gradually "
"transforms into a traditional Chinese ink wash painting. Mountains "
"dissolve from photorealistic to brushstroke. Water becomes flowing ink. "
"Sky shifts from blue to rice-paper white. Slow, meditative pace."
),
"image_urls": [
"https://example.com/real-landscape.jpg",
"https://example.com/ink-wash-painting.jpg"
],
"duration": 10,
"quality": "1080p",
"aspect_ratio": "16:9"
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
result = resp.json()
print(f"Task ID: {result['task_id']}")
video_data = wait_for_video(result["task_id"])
演示:从现实到水墨画
使用的提示词: "The real-world mountain landscape gradually transforms into a traditional Chinese ink wash (山水画) painting. Photorealistic textures dissolve into flowing brushstrokes. Colors fade from vivid to monochrome ink tones. Water surfaces become calligraphic ink flows. Slow, contemplative transition."
第一帧是一张照片级真实的山景。最后一帧是类似场景的传统水墨画。模型创建了一个无缝转换,照片质感逐渐溶解为笔触——这种效果在 After Effects 中手动制作需要花费数小时。
首尾帧模式技巧
匹配两帧之间的构图。 如果你的第一帧左侧有一座山,你的最后一帧应该在相同位置有类似的结构元素。当两帧共享大致相同的布局时,模型能生成更好的过渡效果。
描述过渡过程,而非仅描述端点。 模型已经知道起点和终点的样子——它有图片。你的提示词应该描述如何从 A 到 B。
# Weak: just describes the endpoints
"A sunrise and a sunset"
# Strong: describes the journey
"The golden dawn light gradually warms to midday brightness,
then softens through amber afternoon hues into deep sunset oranges.
Shadows rotate clockwise. Cloud formations shift and reform."
对复杂过渡使用更长的时长。 简单的色彩变化在 4 秒内就能完成。风格变换(写实 → 插画)需要 8–12 秒效果更好。在短时长内进行突变会显得生硬。
| 过渡类型 | 建议时长 |
|---|---|
| 色彩/光照变化 | 4–6 秒 |
| 镜头位置变化 | 6–8 秒 |
| 风格变换 | 8–12 秒 |
| 叙事场景切换 | 10–15 秒 |
模式 3:使用 @Tags 的多图合成
这是 Seedance 2.0 最强大的图像转视频模式——也是没有竞争对手 API 提供的模式。你提供最多 9 张图片,在提示词中使用 @Image 标签为每张图片分配语义角色,模型会将它们合成为一个连贯的视频。
@Tags 的工作原理
当你在 image_urls 中包含多个 URL 时,Seedance 2.0 会根据数组位置分配顺序标签:
image_urls[0] → @Image1
image_urls[1] → @Image2
image_urls[2] → @Image3
...
image_urls[8] → @Image9
你在提示词中引用这些标签来告诉模型如何使用每张图片:
@Image1 is the main character running through the city.
@Image2 is the city skyline in the background.
@Image3 defines the color grading and visual mood.
如果没有标签,模型必须猜测哪张图片是角色、哪张是背景。有了标签就没有歧义。当你的图片在视觉上相似,或者你希望某张特定图片控制风格而非内容时,这一点尤为重要。
完整代码:多图合成
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
def wait_for_video(task_id, interval=5, max_wait=300):
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
resp = requests.get(url, headers=HEADERS)
data = resp.json()
status = data["status"]
if status == "completed":
print(f"Video ready: {data['output']['video_url']}")
return data
elif status == "failed":
print(f"Failed: {data.get('error', 'Unknown error')}")
return data
print(f"Status: {status} ({elapsed}s)")
time.sleep(interval)
elapsed += interval
return None
# --- Multi-Image Composition with @Tags ---
payload = {
"model": "seedance-2.0",
"prompt": (
"@Image1 is a parkour runner in dark athletic gear. "
"@Image2 is a futuristic city rooftop at twilight. "
"@Image3 is a neon-lit alleyway. "
"@Image4 is a glass skyscraper facade. "
"@Image5 provides the cyberpunk color grading reference. "
"The runner (@Image1) sprints across the rooftop (@Image2), "
"leaps over the edge, flips through the alleyway (@Image3), "
"and wall-runs along the skyscraper (@Image4). "
"Dynamic handheld camera follows the action. "
"Cyberpunk neon color palette from @Image5 throughout."
),
"image_urls": [
"https://example.com/runner.jpg",
"https://example.com/rooftop.jpg",
"https://example.com/alley.jpg",
"https://example.com/skyscraper.jpg",
"https://example.com/cyberpunk-ref.jpg"
],
"duration": 10,
"quality": "1080p",
"aspect_ratio": "16:9",
"generate_audio": True
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
result = resp.json()
print(f"Task ID: {result['task_id']}")
video_data = wait_for_video(result["task_id"])
演示:5 张图片参考的城市跑酷
使用的提示词: "@Image1 is the parkour runner. @Image2 is the rooftop environment. @Image3 is the neon alley. @Image4 is the glass building. @Image5 is the color palette reference. The runner (@Image1) sprints across the rooftop (@Image2), leaps, flips through the alley (@Image3), wall-runs along the building (@Image4). Dynamic tracking camera. Cyberpunk color grading from @Image5."
五张独立的图片——一个角色、三个环境和一个风格参考——合成为一个连续的动作序列。每个 @Image 标签都为模型提供了精确的指令,说明哪个视觉元素控制场景的哪个部分。
常见 @Tag 角色分配
@tag 系统非常灵活。以下是最有效的模式:
| 角色 | 提示词中的标签用法 | 用途 |
|---|---|---|
| 角色 | @Image1 is the main character | 保留身份、服装、特征 |
| 背景 | @Image2 is the environment | 设定场景位置 |
| 风格参考 | @Image3 defines the art style | 控制渲染美学 |
| 物体/道具 | @Image4 is the product on the table | 在场景中放置特定物品 |
| 色彩调性 | @Image5 is the color palette | 从参考中应用情绪/色调 |
| 纹理参考 | @Image6 provides surface textures | 材质/纹理迁移 |
演示:角色搭配风格参考
使用的提示词: "@Image1 is the character — a mysterious figure in a red coat. The character runs through rain-soaked city streets at night. Neon reflections on wet pavement. Camera tracks alongside at medium distance. Cinematic atmosphere, shallow depth of field."
单张角色参考图片控制身份,而提示词驱动环境和动作。红色外套、身体比例和运动风格都来自 @Image1。
关于完整的 @tag 参考——包括视频和音频标签、混合媒体组合以及高级角色模式——请参阅多模态 @Tags 指南。
跨镜头保持角色一致性
单个生成的片段很有用。而在不同场景中使用同一角色的一系列片段就是一个故事。角色一致性是 AI 视频生成中最难的问题,而 Seedance 2.0 的 @tag 系统提供了目前通过 API 可获得的最可靠解决方案。
角色锁定模式
要在多个镜头中保持同一角色,请在每次生成请求中使用相同的角色参考图片作为 @Image1。只改变提示词和背景/环境图片。
CHARACTER_IMAGE = "https://example.com/my-character.jpg"
shots = [
{
"prompt": (
"@Image1 is the main character. She walks into a cozy library, "
"looks around with wonder, and reaches for a book on the top shelf. "
"Warm golden lighting. Camera at eye level, slow push in."
),
"extra_images": [],
"duration": 8
},
{
"prompt": (
"@Image1 is the main character. She sits at a wooden reading table, "
"opens the book, and pages start glowing with magical light. "
"Dust particles float in warm lamplight. Camera orbits slowly around her."
),
"extra_images": [],
"duration": 10
},
{
"prompt": (
"@Image1 is the main character. She steps out of the library into "
"a fantastical world that matches the book's illustrations. "
"Vibrant colors replace the muted library tones. "
"Camera pulls back to reveal the vast landscape. Wide shot."
),
"extra_images": [],
"duration": 10
},
]
def generate_shot(shot):
image_urls = [CHARACTER_IMAGE] + shot["extra_images"]
payload = {
"model": "seedance-2.0",
"prompt": shot["prompt"],
"image_urls": image_urls,
"duration": shot["duration"],
"quality": "1080p",
"aspect_ratio": "16:9"
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
return resp.json()["task_id"]
# Generate all shots
task_ids = [generate_shot(shot) for shot in shots]
print(f"Submitted {len(task_ids)} shots: {task_ids}")
# Poll each shot
for i, task_id in enumerate(task_ids):
print(f"\nWaiting for Shot {i+1}...")
wait_for_video(task_id)
演示:图书馆故事序列
使用的提示词: "@Image1 is a young girl with braids. She enters a grand old library, runs her fingers along the spines of ancient books, pulls one out, and opens it. Golden dust motes swirl in shaft of light from a high window. Warm, magical atmosphere. Camera follows her at child's eye level."
角色——一个扎着辫子的小女孩——保持了视觉一致性,因为每个镜头都由同一张参考图片锚定。模型在生成不同动作和环境的同时,保留了她的比例、服装和视觉特征。
一致性技巧
使用清晰、光线充足的角色参考图。 模型从你的参考图片中提取身份特征。模糊、光线不足或严重遮挡的图片会让模型可参考的信息减少。正面、全身或上半身照片配合干净的背景能产生最佳的一致性效果。
在提示词中尽量简化角色描述。 如果 @Image1 已经展示了一个穿蓝色连衣裙的女孩,就不要在提示词中写"一个穿红色连衣裙的女孩"。冲突的描述会迫使模型在你的图片和文本之间做选择,降低一致性。
在所有镜头中保持相同的宽高比。 在序列中途从 16:9 切换到 9:16 会强制使用不同的画面构图,这可能改变角色的呈现方式。选择一个比例并始终使用它。
将环境图片作为独立的 @tags 添加。 与其完全用文本描述背景,不如提供一张背景参考图片作为 @Image2。这样你可以精确控制角色和环境,同时保持二者在视觉上的分离。
# Shot 1: Character in library
"image_urls": [CHARACTER_IMAGE, "https://example.com/library.jpg"]
# Prompt: "@Image1 is the character. @Image2 is the library environment."
# Shot 2: Character in forest
"image_urls": [CHARACTER_IMAGE, "https://example.com/forest.jpg"]
# Prompt: "@Image1 is the character. @Image2 is the forest environment."
这种模式——固定 @Image1 作为角色,可变的 @Image2 作为环境——是目前任何 AI 视频 API 中最可靠的多镜头工作流。
进阶:多镜头叙事流水线
对于较长的叙事(30 秒以上),你需要生成多个片段并将它们拼接在一起。以下是一种结构化的方法,管理完整的流水线——镜头列表定义、并行生成和有序输出:
import concurrent.futures
import requests
import time
import json
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
CHARACTER_REF = "https://example.com/story-character.jpg"
SHOT_LIST = [
{
"shot_id": "01_entrance",
"prompt": (
"@Image1 is the main character. "
"She pushes open a heavy wooden door and steps into a dimly lit room. "
"Dust swirls in the doorway light. "
"Camera follows her from behind, over-the-shoulder angle."
),
"env_images": [],
"duration": 6
},
{
"shot_id": "02_discovery",
"prompt": (
"@Image1 is the main character. @Image2 is the room interior. "
"She walks to the center of the room and discovers a glowing object on a pedestal. "
"Her face shows surprise. Blue light illuminates her features. "
"Camera pushes in from medium shot to close-up on her expression."
),
"env_images": ["https://example.com/mysterious-room.jpg"],
"duration": 8
},
{
"shot_id": "03_transformation",
"prompt": (
"@Image1 is the main character. "
"She reaches out and touches the glowing object. "
"Light radiates outward from the point of contact. "
"The room transforms — walls dissolve into a starfield. "
"Camera rapidly pulls back to extreme wide shot."
),
"env_images": [],
"duration": 10
},
]
def submit_shot(shot):
"""Submit a single shot for generation."""
image_urls = [CHARACTER_REF] + shot["env_images"]
payload = {
"model": "seedance-2.0",
"prompt": shot["prompt"],
"image_urls": image_urls,
"duration": shot["duration"],
"quality": "1080p",
"aspect_ratio": "16:9",
"generate_audio": True
}
resp = requests.post(f"{BASE_URL}/videos/generations", headers=HEADERS, json=payload)
task_id = resp.json()["task_id"]
return {"shot_id": shot["shot_id"], "task_id": task_id}
def poll_until_done(task_id, max_wait=300):
"""Block until task completes or fails."""
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
data = requests.get(url, headers=HEADERS).json()
if data["status"] in ("completed", "failed"):
return data
time.sleep(5)
elapsed += 5
return None
# Submit all shots in parallel
results = []
for shot in SHOT_LIST:
result = submit_shot(shot)
results.append(result)
print(f"Submitted {result['shot_id']} → {result['task_id']}")
time.sleep(0.5)
# Collect results in order
final_videos = []
for r in results:
print(f"\nPolling {r['shot_id']}...")
data = poll_until_done(r["task_id"])
if data and data["status"] == "completed":
video_url = data["output"]["video_url"]
final_videos.append({"shot_id": r["shot_id"], "url": video_url})
print(f" Done: {r['shot_id']}: {video_url}")
else:
print(f" Failed: {r['shot_id']}: generation failed")
# Output the ordered shot list
print("\n=== Final Shot List ===")
for v in final_videos:
print(f"{v['shot_id']}: {v['url']}")
此流水线生成一个有序的视频 URL 列表,你可以将其输入任何视频编辑器或自动化拼接工具(FFmpeg、MoviePy 等)来组装最终的叙事序列。角色在所有镜头中保持一致,因为每个请求都使用相同的 CHARACTER_REF 作为 @Image1。
处理一致性边缘情况
即使使用相同的参考图片,跨镜头也可能出现轻微变化——角色的服装颜色可能偏移几个色度,或者在极端远景镜头中比例可能略有变化。以下是减少这些变化的策略:
在每个提示词中重新陈述角色细节。 如果你的角色穿着特定服装,简要提及:"@Image1 is the main character wearing a blue denim jacket." 这会强化来自参考图片的视觉锚点。
避免在镜头之间进行极端角度变化。 正面中景紧接着俯瞰极远景会引入最大的变化。逐步过渡:中景 → 稍微更宽的镜头 → 远景。
使用相同的画质和宽高比。 在不同镜头间混用 720p 和 1080p 会引入细微的渲染差异。在你的镜头列表中统一所有参数。
电商产品视频:端到端工作流
产品拍照成本高昂。产品录像更加昂贵——影棚、旋转台、适当的灯光、摄影师、剪辑时间。Seedance 2.0 的图像转视频 API 用单次 API 调用替代了大部分流程。
产品视频的困境
电商平台越来越青睐视频内容。亚马逊报告称,带视频的产品列表有更高的转化率。Instagram 和 TikTok 是视频优先的平台。但制作一段简单的 10 秒产品旋转视频传统上需要:
- 物理旋转台装置
- 适当的灯光设备
- 摄影师(或精心的 DIY)
- 剪辑和调色
- 导出和上传
使用 Seedance 2.0,流程变成:
- 拍一张产品照片(你已经有了)
- 发起一次 API 调用
- 下载视频
单品展示:手表广告
以下是从单张产品图片生成产品展示视频的完整工作流:
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
def wait_for_video(task_id, interval=5, max_wait=300):
url = f"{BASE_URL}/tasks/{task_id}"
elapsed = 0
while elapsed < max_wait:
resp = requests.get(url, headers=HEADERS)
data = resp.json()
status = data["status"]
if status == "completed":
print(f"Video ready: {data['output']['video_url']}")
return data
elif status == "failed":
print(f"Failed: {data.get('error', 'Unknown error')}")
return data
print(f"Status: {status} ({elapsed}s)")
time.sleep(interval)
elapsed += interval
return None
# --- Product Video: Luxury Watch ---
payload = {
"model": "seedance-2.0",
"prompt": (
"@Image1 is a luxury wristwatch. "
"The watch rotates slowly on a dark marble surface. "
"Dramatic side lighting highlights the metal bracelet and crystal face. "
"Light reflections move across the polished surfaces as the watch turns. "
"Subtle lens flare. Extreme close-up with shallow depth of field. "
"Premium product advertisement aesthetic."
),
"image_urls": [
"https://example.com/watch-product.jpg"
],
"duration": 8,
"quality": "1080p",
"aspect_ratio": "16:9",
"generate_audio": False
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
result = resp.json()
print(f"Task ID: {result['task_id']}")
video_data = wait_for_video(result["task_id"])
演示:手表产品视频
使用的提示词: "@Image1 is a luxury wristwatch. The watch rotates slowly under dramatic studio lighting on a dark reflective surface. Light catches the polished metal case and sapphire crystal. Slow cinematic rotation. Premium advertisement quality."
从单张产品照片,API 生成了具有影棚品质灯光的旋转产品展示。手表的设计细节——表盘刻度、表链链节、表壳形状——全部来自参考图片。
多色产品变体
许多产品有多种配色。与其单独拍摄每种变体,你可以使用 @tag 系统在单个视频中展示所有变体:
# --- Multi-Color Product: Headphones ---
payload = {
"model": "seedance-2.0",
"prompt": (
"@Image1 shows premium over-ear headphones in four different colors "
"arranged on a clean surface. The camera slowly pans across all four "
"variants. Each headphone catches the studio light differently. "
"Smooth dolly movement from left to right. "
"Clean white background with subtle shadows. "
"Product catalog video style."
),
"image_urls": [
"https://example.com/headphones-all-colors.jpg"
],
"duration": 10,
"quality": "1080p",
"aspect_ratio": "16:9"
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
result = resp.json()
print(f"Task ID: {result['task_id']}")
video_data = wait_for_video(result["task_id"])
演示:耳机颜色变体
使用的提示词: "@Image1 shows over-ear headphones in four color variants. The camera pans smoothly across each variant under clean studio lighting. Soft reflections on the ear cups. Minimal white background. Product showcase cinematography."
一张产品阵列照片变成一段流畅的平移展示视频。每种配色都获得了镜头时间,影棚灯光美学与专业产品录像相匹配。
产品目录批量生成
如果你有数十或数百个产品,可以将生成逻辑封装在批处理器中:
import csv
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.evolink.ai/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
def generate_product_video(product_name, image_url, style="premium"):
"""Generate a product video from a single product image."""
style_prompts = {
"premium": (
f"@Image1 is a {product_name}. "
"The product rotates slowly under dramatic studio lighting "
"on a dark reflective surface. Cinematic close-up. "
"Light reveals surface details and textures. "
"Premium advertisement quality."
),
"lifestyle": (
f"@Image1 is a {product_name}. "
"The product is shown in a lifestyle setting — "
"a modern living space with natural light. "
"Camera slowly pushes in to reveal product details. "
"Warm, inviting atmosphere."
),
"minimal": (
f"@Image1 is a {product_name}. "
"Clean white background. The product rotates 360 degrees. "
"Even, shadowless lighting. E-commerce product spin."
),
}
payload = {
"model": "seedance-2.0",
"prompt": style_prompts[style],
"image_urls": [image_url],
"duration": 8,
"quality": "1080p",
"aspect_ratio": "1:1"
}
resp = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload
)
data = resp.json()
return data["task_id"]
# Example: process a CSV product catalog
# CSV format: product_name, image_url, style
products = [
("Wireless Earbuds", "https://example.com/earbuds.jpg", "premium"),
("Leather Wallet", "https://example.com/wallet.jpg", "lifestyle"),
("Running Shoes", "https://example.com/shoes.jpg", "minimal"),
]
tasks = []
for name, url, style in products:
task_id = generate_product_video(name, url, style)
tasks.append((name, task_id))
print(f"Submitted: {name} → {task_id}")
time.sleep(1) # Rate limiting courtesy
print(f"\nSubmitted {len(tasks)} product videos")
print("Poll each task_id to retrieve the completed video URLs")
这种批处理模式可扩展到任何目录规模。你可以用回调 URL(callback_url 参数)代替轮询来扩展它,这对于大批量处理更高效——当每个视频完成时,API 会向你的端点发送一个 POST 请求。
产品视频提示词模板
以下是经过实战检验的常见电商视频需求提示词模板:
PRODUCT_TEMPLATES = {
"rotation_360": (
"@Image1 is the product. "
"Full 360-degree rotation on a clean background. "
"Consistent studio lighting throughout the rotation. "
"Smooth, steady turntable motion. "
"Product catalog photography style."
),
"unboxing_reveal": (
"@Image1 is the product. "
"The product emerges from soft tissue paper inside a premium box. "
"Hands carefully lift it into view. "
"Camera slowly pushes in as the product is revealed. "
"Luxury unboxing experience. Warm lighting."
),
"hero_shot": (
"@Image1 is the product. "
"Dramatic hero shot. The product rises into frame against a dark background. "
"Volumetric light beams hit the product from the side. "
"Slow motion. Particles float in the light. "
"Epic product launch trailer aesthetic."
),
"in_use": (
"@Image1 is the product. "
"Someone picks up the product and uses it naturally. "
"Lifestyle setting with soft natural window light. "
"Medium close-up. The camera follows the interaction. "
"Authentic, relatable product usage."
),
}
常见错误及修复方法
经过数百次 API 调用后,哪些做法有效、哪些会失败已经有了清晰的规律。以下是最常见的错误及其修复方法。
错误 1:使用真实人脸照片
表现: API 返回 400 错误或 failed 任务状态。
原因: Seedance 2.0 阻止从照片级真实人脸图像进行图像转视频生成。这是一项安全策略,不是 bug。
修复: 改用插画、风格化或卡通风格的角色图片。动漫角色、油画肖像、3D 渲染角色和剪影都可以完美使用。如果你的工作流需要人物角色,请先使用文本转图像模型以非写实风格生成它们。
# Will be rejected
"image_urls": ["https://example.com/real-person-photo.jpg"]
# Works fine
"image_urls": ["https://example.com/illustrated-character.png"]
"image_urls": ["https://example.com/3d-rendered-character.jpg"]
"image_urls": ["https://example.com/anime-character.png"]
错误 2:仅描述外观的静态提示词
表现: 生成的视频几乎没有或完全没有运动。主体静止不动,或者只有轻微的镜头漂移。
原因: 模型会按字面意思理解你的提示词。如果你描述的是一个静态场景("a cat on a windowsill"),你就会得到一个几乎静止的视频。
修复: 始终包含动作动词、连续动作和环境动态。
# Static: produces near-still video
"prompt": "A beautiful sunset over the ocean with golden light"
# Dynamic: produces engaging video
"prompt": (
"Waves crash against rocky coastline during golden sunset. "
"Water sprays upward, catching the warm light. "
"Camera slowly descends from sky level to water level. "
"Seabirds glide across the frame. "
"Light shifts from golden to deep amber."
)
错误 3:时长与内容不匹配
表现: 简单动作感觉被拉长、很尴尬,或者复杂序列感觉仓促、不连贯。
原因: 时长必须与提示词的复杂度匹配。简单的产品旋转不需要 15 秒。多动作的角色序列在 4 秒内完成不了。
修复: 将时长与提示词复杂度匹配:
| 提示词复杂度 | 描述的动作 | 建议时长 |
|---|---|---|
| 简单(单一动作) | 1 个动作 | 4–6 秒 |
| 中等(2-3 个动作) | 2–3 个连续动作 | 6–10 秒 |
| 复杂(叙事性) | 4 个以上动作、场景切换 | 10–15 秒 |
错误 4:图片 URL 问题
表现: API 返回关于无效图片的错误,或者任务在处理过程中失败。
原因: 几个常见的 URL 问题:
- URL 需要认证(非公开可访问)
- URL 指向网页,而非直接的图片文件
- 图片格式不受支持(WebP 有时会失败)
- 图片太大(超高分辨率文件可能超时)
- URL 已过期(带时间限制的预签名 URL)
修复: 确保你的图片 URL 满足:
- 公开可访问 —— 无需认证头即可下载
- 直接图片链接 —— 以
.jpg、.png或类似扩展名结尾(不是 HTML 页面) - 标准格式 —— JPEG 和 PNG 最可靠
- 合理大小 —— 每张图片不超过 10MB
- 持久有效 —— 在处理期间不会过期
# Problem URLs
"https://drive.google.com/file/d/abc123/view" # Requires auth
"https://example.com/product-page" # HTML page, not image
"https://storage.com/image.jpg?token=abc&exp=1h" # Might expire
# Good URLs
"https://cdn.example.com/images/product.jpg" # Direct CDN link
"https://i.imgur.com/abc123.png" # Public image host
错误 5:多图时未使用 @Tags
表现: 当你传入 3 张以上图片但在提示词中未使用 @Image 标签时,模型会猜测每张图片的用途。结果不可预测——有时背景图被当作角色使用,或者风格参考被当作场景元素处理。
修复: 传入多张图片时始终使用 @Image 标签。明确说明每张图片的角色。
# Ambiguous: model guesses roles
"prompt": "A character walks through a forest in watercolor style"
"image_urls": [character.jpg, forest.jpg, watercolor_ref.jpg]
# Explicit: model knows each role
"prompt": (
"@Image1 is the character. @Image2 is the forest environment. "
"@Image3 defines the watercolor art style. "
"The character (@Image1) walks through the forest (@Image2) "
"rendered in the watercolor style of @Image3."
)
"image_urls": [character.jpg, forest.jpg, watercolor_ref.jpg]
错误 6:忘记视频 URL 过期
表现: 你生成了一个视频,保存了 URL,第二天尝试访问时收到 403 或 404。
原因: 生成的视频 URL 在 24 小时后过期。
修复: 在生成完成后立即下载视频文件。在你的轮询函数中添加下载步骤:
import os
def download_video(video_url, output_path):
"""Download a video before the URL expires."""
resp = requests.get(video_url, stream=True)
resp.raise_for_status()
with open(output_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Saved to {output_path}")
# After generation completes:
video_url = video_data["output"]["video_url"]
download_video(video_url, "output/my-product-video.mp4")
错误 7:提示词与图片内容冲突
表现: 输出视频看起来混乱——图片中的元素和提示词中的元素争夺主导地位,产生视觉伪影或不连贯的场景。
原因: 你在提示词中描述的内容直接与参考图片矛盾。例如,你的图片显示的是一辆红色汽车,但提示词写的是"a blue sports car races down the highway"。
修复: 你的提示词应该补充图片,而非与之矛盾。描述动作、镜头运动和环境变化——而非参考图片已经定义的元素外观。
# Contradicts image (image shows red car)
"prompt": "A blue sports car races down the highway at sunset"
# Complements image (lets the image define appearance)
"prompt": (
"@Image1 is the car. The car accelerates down an open highway. "
"Camera tracks alongside at speed. Sunset light reflects off the hood. "
"Road stretches to the horizon. Motion blur on the asphalt."
)
API 参数参考
以下是图像转视频生成相关的所有参数汇总:
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
model | string | 是 | — | 必须为 "seedance-2.0" |
prompt | string | 是 | — | 运动描述,可选 @Image 标签 |
image_urls | array | 是(图转视频时) | [] | 1–9 个公开可访问的图片 URL |
duration | integer | 否 | 5 | 视频时长,单位秒(4–15) |
quality | string | 否 | "720p" | 输出分辨率:"480p"、"720p"、"1080p" |
aspect_ratio | string | 否 | "16:9" | 输出比例:"16:9"、"9:16"、"1:1"、"4:3"、"3:4" |
generate_audio | boolean | 否 | false | 生成同步音频轨道 |
video_urls | array | 否 | [] | 0–3 个视频参考 URL(用于混合媒体) |
audio_urls | array | 否 | [] | 0–3 个音频参考 URL(用于混合媒体) |
callback_url | string | 否 | — | 完成通知的 Webhook URL |
限制: 每个请求最多 9 张图片 + 3 个视频 + 3 个音频文件。所有媒体类型的总数不能超过 12。标签按数组位置分配:image_urls[0] → @Image1,video_urls[0] → @Video1,audio_urls[0] → @Audio1。
常见问题
Seedance 2.0 图像转视频 API 支持哪些图片格式?
JPEG 和 PNG 完全支持且推荐使用。GIF(仅第一帧)、BMP 和 TIFF 通常可以使用但测试较少。WebP 支持不稳定——转换为 JPEG 或 PNG 可获得可靠的结果。所有图片必须通过无需认证的公开 URL 访问。
图像转视频生成需要多长时间?
典型的生成时间为 60 到 180 秒,取决于时长、画质设置和当前服务器负载。480p 的 4 秒片段比 1080p 的 15 秒片段生成更快。使用轮询端点(GET /v1/tasks/{task_id})或设置 callback_url 来接收处理完成的通知。
单次请求最多可以使用多少张图��?
你可以在 image_urls 中包含最多 9 张图片。所有媒体类型(图片 + 视频 + 音频)的总文件数上限为每个请求 12 个。因此如果你使用了 9 张图片,仍然可以添加最多 3 个视频或音频参考。
可以将图像转视频与音频生成结合使用吗?
可以。在请求参数中同时设置 generate_audio: true 和 image_urls。模型会生成与视觉内容匹配的同步音频——行走场景的脚步声、自然场景的环境音、产品旋转的机械声。你也可以通过 audio_urls 提供自己的音频,并在提示词中用 @Audio1 引用它。
在生产环境中如何处理视频 URL 过期?
生成的视频 URL 在 24 小时后过期。对于生产系统,请在你的流水线中实现即时下载步骤。在任务状态变为 completed 后,将视频文件下载到你自己的存储(S3、GCS 或本地磁盘),然后再将 URL 返回给你的应用。永远不要将 API 生成的 URL 作为永久引用存储。如果你使用 callback_url,你的 webhook 处理程序应将下载步骤作为其处理逻辑的一部分。
可以使用 Seedance 2.0 图像转视频制作动态 Logo 或品牌片头吗?
可以,这是最适合的用例之一。将你的 Logo 或品牌标识作为 @Image1 上传,并在提示词中描述你想要的动画风格——粒子组装、液体揭示、3D 旋转等。由于 Logo 是图形元素(非照片级真实人脸),它们与图像转视频流水线完美兼容。设置 generate_audio: true 可为揭示动画添加同步音效。
为什么我的图像转视频请求被拒绝了?
最常见的拒绝原因是输入图像中包含照片级真实的人脸。Seedance 2.0 出于安全原因自动检测并阻止真实人脸图像。其他拒绝原因包括:图片 URL 无法访问、不支持的文件格式、超过 9 张图片的限制或总媒体文件数超过 12。查看 failed 任务响应中的错误消息以获取具体详情。
开始为你的图片制作动画
你现在拥有三种不同的方法通过 Seedance 2.0 API 将静态图片转换为视频:单图动画用于快速的角色或场景运动,首尾帧控制用于精确的首尾过渡,以及使用 @tags 的多图合成用于复杂的角色分配场景。
本指南中的代码示例都是完整且可运行的。复制其中任何一个,插入你的 API 密钥,指向你自己的图片,几分钟内就能获得生成的视频。
对于产品团队,批量生成工作流可以在无需影棚的情况下将整个产品目录转化为视频素材。对于创意团队,角色一致性模式可以从单张角色参考实现多镜头叙事。对于开发者,@tag 系统提供了目前任何其他 AI 视频 API 都无法匹敌的组合式控制能力。
本指南是 Seedance 2.0 教程系列的一部分。此前发布:Seedance 2.0 提示词指南、入门指南、多模态 @Tags 指南 和镜头运动指南。