Seedance — 完全版APIチュートリアル
SeedanceはByteDanceが開発する最先端の動画生成モデルファミリーです。主な特徴は以下の通りです:
- ネイティブな視覚・音声同期: デュアルブランチ拡散トランスフォーマー(動画+音声を共有潜在空間で同時生成)
- 多言語リップシンク(英語、中国語、日本語、韓国語、スペイン語、インドネシア語など)
- シネマティックなカメラコントロール — パン、チルト、ズーム、オービット、手持ち、マルチショットな叙事
- 複数のモデルバリアント — 高速・軽量からシネマティック旗艦品質まで
- 柔軟なフォーマット: 480p〜1080p解像度 | 4〜12秒の長さ | 24 FPS | MP4出力
API: BytePlus ModelArk — https://ark.ap-southeast.bytepluses.com/api/v3
このチュートリアルでは、公式BytePlus SDK (
byteplus-python-sdk-v2) と 最新のSeedance 1.5 Proモデルを使用します。ワークフローは非同期です: タスクを作成 → 完了までポーリング → 動画をダウンロードします。
1. セットアップと設定
# Install required packages
!pip install byteplus-python-sdk-v2 python-dotenv requests pillow -qimport os
import time
import json
import requests
from pathlib import Path
from dotenv import load_dotenv
from IPython.display import Video, Image, display, HTML
from byteplussdkarkruntime import Ark
# Load credentials from .env file
load_dotenv()
ARK_API_KEY = os.getenv("ARK_API_KEY")
ARK_BASE_URL = os.getenv("ARK_BASE_URL", "https://ark.ap-southeast.bytepluses.com/api/v3")
if not ARK_API_KEY:
raise EnvironmentError(
"ARK_API_KEY not found. Create a .env file with:\n"
"ARK_API_KEY=your_key_here\n"
"Get yours at: https://console.byteplus.com/ark/region:ark+ap-southeast-1/apikey"
)
# Initialize the Ark client
client = Ark(
base_url=ARK_BASE_URL,
api_key=ARK_API_KEY,
)
print(f"✅ Client initialized | Base URL: {ARK_BASE_URL}")
# Output directory
OUTPUT_DIR = Path("seedance_outputs")
OUTPUT_DIR.mkdir(exist_ok=True)2. モデル概要
利用可能なSeedanceモデル
Seedance 1.5 Pro(最新 — 旗艦品質)
| モデルID | タイプ | 解像度 | 長さ | 主な強み |
|---|---|---|---|---|
seedance-1-5-pro-251215 |
テキスト→動画+画像→動画 | 480p, 720p, 1080p | 4〜12秒 | シネマティック品質+ネイティブ視聴覚同期 |
Seedance 1.0 Pro(高品質)
| モデルID | タイプ | 解像度 | 長さ | 主な強み |
|---|---|---|---|---|
seedance-1-0-pro-250528 |
テキスト→動画 | 480p〜1080p | 4〜12秒 | マルチショット叙事、最高解像度 |
seedance-1-0-pro-fast-251015 |
テキスト→動画 | 480p〜1080p | 4〜12秒 | 3倍高速生成、バランスの取れた品質 |
Seedance 1.0 Lite(高速・コスト効率)
| モデルID | タイプ | 解像度 | 長さ | 主な強み |
|---|---|---|---|---|
seedance-1-0-lite-t2v-250428 |
テキスト→動画 | 480p, 720p | 4〜12秒 | 最速生成、コスト重視 |
料金計算式(Seedance 1.5 Pro):
tokens = (height × width × FPS × duration) / 1024
cost_with_audio = tokens × $2.4 / 1,000,000
cost_without_audio = tokens × $1.2 / 1,000,000
💡 推奨: 最高品質とネイティブ音声サポートにはSeedance 1.5 Proモデル(このチュートリアルで使用)を使います。高速な反復には1.0 Pro Fast、コスト重視のアプリケーションには1.0 Liteを使います。
def estimate_cost(resolution="720p", duration=5, audio=True):
"""Estimate video generation cost."""
dims = {"480p": (854, 480), "720p": (1280, 720), "1080p": (1920, 1080)}
w, h = dims.get(resolution, (1280, 720))
fps = 24
tokens = (h * w * fps * duration) / 1024
rate = 2.4 if audio else 1.2
cost = tokens * rate / 1_000_000
print(f"Resolution: {resolution} ({w}x{h}) | Duration: {duration}s | Audio: {audio}")
print(f"Tokens: {tokens:,.0f} | Estimated cost: ${cost:.4f}")
return cost
estimate_cost("720p", 5, audio=True)3. コアヘルパー関数
動画生成は非同期です: タスクを送信し、完了するまでステータスをポーリングします。
def poll_task(task_id, interval=10, max_wait=600, verbose=True):
"""
Poll a video generation task until it's complete.
Args:
task_id: Task ID from create_task response
interval: Seconds between polls
max_wait: Maximum wait time in seconds
verbose: Print status updates
Returns:
Task result dict or None on timeout
"""
elapsed = 0
while elapsed < max_wait:
result = client.content_generation.tasks.get(id=task_id)
status = result.status
if verbose:
print(f" [{elapsed:>4}s] Status: {status}")
if status == "succeeded":
return result
elif status in ("failed", "cancelled"):
print(f"❌ Task {status}: {getattr(result, 'error', 'unknown error')}")
return None
time.sleep(interval)
elapsed += interval
print(f"⏱️ Timed out after {max_wait}s")
return None
def download_video(url, filename, output_dir=OUTPUT_DIR):
"""Download a video from a URL and save locally."""
path = output_dir / filename
response = requests.get(url, stream=True, timeout=60)
response.raise_for_status()
with open(path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
size_mb = path.stat().st_size / 1_048_576
print(f"✅ Saved: {path} ({size_mb:.1f} MB)")
return path
def generate_video(model, content, filename="output.mp4", verbose=True):
"""
Full pipeline: create task, poll, download.
Args:
model: Model ID string
content: List of content dicts (text/image_url)
filename: Output filename
verbose: Print progress
Returns:
Local path to downloaded video
"""
print(f"🎬 Creating task | Model: {model}")
task = client.content_generation.tasks.create(model=model, content=content)
task_id = task.id
print(f" Task ID: {task_id}")
result = poll_task(task_id, verbose=verbose)
if result is None:
return None
video_url = result.content.video_url
print(f"🔗 Video URL: {video_url}")
return download_video(video_url, filename)
print("✅ Helper functions defined")4. テキストから動画(T2V)生成
使用モデル: seedance-1-5-pro-251215(ネイティブ視聴覚同期を備えた最新旗艦モデル)
上記の表から任意のテキスト→動画モデルに
T2V_MODELを置き換えられます(例: 高速生成ならseedance-1-0-pro-fast-251015、コスト重視ならseedance-1-0-lite-t2v-250428)。
プロンプトの公式: 被写体 + 動き + 背景 + カメラ
動画の仕様を制御するには、プロンプトテキストに--パラメータを追加します:
--resolution 720p --duration 5 --camerafixed false
# --- Basic Text-to-Video ---
T2V_MODEL = "seedance-1-5-pro-251215"
prompt_t2v = (
"Cinematic close-up of a single white daisy in a sunlit meadow. "
"Dewdrops glisten on the petals as a gentle breeze sways the flower. "
"Slow zoom out, soft golden hour lighting, film grain texture. "
"--resolution 720p --duration 5 --camerafixed false"
)
content_t2v = [{"type": "text", "text": prompt_t2v}]
# Uncomment to run (costs ~$0.26)
# video_path = generate_video(T2V_MODEL, content_t2v, filename="t2v_basic.mp4")
# if video_path:
# display(Video(str(video_path), embed=True, width=640))
print("Prompt ready. Uncomment the generate_video call to run.")
print(f"Model: {T2V_MODEL}")
print(f"Prompt: {prompt_t2v}")プロンプトパラメータ一覧
| パラメータ | 値 | 説明 |
|---|---|---|
--resolution |
480p, 720p |
出力解像度 |
--duration |
4〜12 |
長さ(秒) |
--camerafixed |
true, false |
カメラ位置を固定 |
--aspect_ratio |
16:9, 9:16, 1:1, 4:3, 21:9 |
アスペクト比 |
# --- Prompt Variations Showcase ---
prompt_examples = {
"nature": (
"Aerial view of a dense forest at dawn, morning mist weaving through treetops. "
"Slow drone descent through the canopy, dappled light filtering down. "
"--resolution 720p --duration 8 --camerafixed false"
),
"character": (
"A young woman in a red coat walks across a rain-slicked Tokyo street at night. "
"Neon lights reflect in puddles. Medium tracking shot, handheld feel. "
"She pauses, looks at camera, slight smile. "
"--resolution 720p --duration 6 --camerafixed false"
),
"product": (
"Luxury perfume bottle rotating on a reflective obsidian surface. "
"Deep purple and gold lighting. Slow 360 orbit shot. "
"Particles of light drift around the bottle. Studio setup. "
"--resolution 720p --duration 5 --camerafixed false"
),
"multi_shot": (
"Wide shot: A chef seasons vegetables in a professional kitchen, flames rising in a wok. "
"Cut to close-up of vegetables sizzling with vibrant steam. "
"Cut to the chef plating the dish with focused expression. "
"Natural lighting, documentary style. "
"--resolution 720p --duration 10 --camerafixed false"
),
}
for name, prompt in prompt_examples.items():
print(f"\n📋 [{name.upper()}]")
print(f" {prompt[:120]}..." if len(prompt) > 120 else f" {prompt}")5. 画像から動画(I2V)生成
使用モデル: seedance-1-5-pro-251215(T2VとI2Vの両方、音声付きに対応する最新統合モデル)
参照画像をアニメーション化します。コンテンツ配列にtextとimage_urlの両方を渡します。プロンプトは動きに集中させてください — シーンは画像で既に決まっています。
参照画像:

このBig Benの街並み画像がI2Vモデルによってアニメーション化されます。モデルはテキストプロンプトに基づき、流れる交通、漂う雲、輝く光などの自然な動きを追加します。
I2V_MODEL = "seedance-1-5-pro-251215" # Same model does both T2V and I2V
# Public test image (replace with your own)
IMAGE_URL = "https://ark-doc.tos-ap-southeast-1.bytepluses.com/see_i2v.jpeg"
# For I2V: describe movement and camera — the image defines the scene
prompt_i2v = (
"Traffic flows along the bridge toward Big Ben at dusk. "
"Cars move steadily with glowing headlights and taillights. "
"Clouds drift slowly across the dramatic sky. "
"Slow zoom in, cinematic urban atmosphere. "
"--resolution 720p --duration 5 --camerafixed false"
)
content_i2v = [
{"type": "text", "text": prompt_i2v},
{"type": "image_url", "image_url": {"url": IMAGE_URL}},
]
# Display the input image
try:
display(Image(url=IMAGE_URL, width=400))
print(f"Reference image: {IMAGE_URL}")
except Exception:
print(f"Reference image URL: {IMAGE_URL}")
# Uncomment to run
# video_path = generate_video(I2V_MODEL, content_i2v, filename="i2v_output.mp4")
# if video_path:
# display(Video(str(video_path), embed=True, width=640))
print("\nI2V content structure ready.")最初と最後のフレームを使うI2V
一部のSeedanceモデルでは、開始フレームと終了フレームの両方を指定でき、その間の動きを生成します。
# First + Last frame I2V (supported by seedance-1-0-pro-250528)
START_FRAME_URL = "https://ark-doc.tos-ap-southeast-1.bytepluses.com/see_i2v.jpeg"
END_FRAME_URL = "https://ark-doc.tos-ap-southeast-1.bytepluses.com/see_i2v_last.jpeg"
content_first_last = [
{
"type": "text",
"text": "Flowers blooming, petals opening slowly. Gentle sunlight. --resolution 720p --duration 5"
},
{"type": "image_url", "image_url": {"url": START_FRAME_URL}}, # first frame
{"type": "image_url", "image_url": {"url": END_FRAME_URL}}, # last frame
]
print("First+Last frame content structure:")
print(json.dumps(content_first_last, indent=2))6. タスク管理 — 取得と一覧
# Retrieve a specific task by ID
def get_task_status(task_id):
"""Retrieve and display task status."""
try:
result = client.content_generation.tasks.get(id=task_id)
print(f"Task ID : {result.id}")
print(f"Status : {result.status}")
print(f"Model : {result.model}")
if result.status == "succeeded":
print(f"Video URL: {result.content.video_url}")
elif result.status == "failed":
print(f"Error : {getattr(result, 'error', 'N/A')}")
return result
except Exception as e:
print(f"Error fetching task: {e}")
return None
# List recent tasks
def list_tasks(model=None, limit=5):
"""List recent video generation tasks."""
try:
params = {"page_size": limit}
if model:
params["model"] = model
tasks = client.content_generation.tasks.list(**params)
print(f"Recent tasks (limit {limit}):")
for t in tasks.items:
print(f" {t.id} | {t.status:12} | {t.model}")
return tasks
except Exception as e:
print(f"Error listing tasks: {e}")
return None
# Example usage
# get_task_status("your-task-id-here")
# list_tasks(limit=5)
print("Task management functions defined.")7. 直接REST APIを使う(Requests)
SDKを使わずに生のHTTP呼び出しを行う場合:
API_BASE = ARK_BASE_URL
HEADERS = {
"Authorization": f"Bearer {ARK_API_KEY}",
"Content-Type": "application/json",
}
def create_task_rest(model, content):
"""Create a video generation task via REST API."""
payload = {"model": model, "content": content}
resp = requests.post(
f"{API_BASE}/content_generation/tasks",
headers=HEADERS,
json=payload,
timeout=30,
)
resp.raise_for_status()
return resp.json()
def get_task_rest(task_id):
"""Retrieve a video generation task via REST API."""
resp = requests.get(
f"{API_BASE}/content_generation/tasks/{task_id}",
headers=HEADERS,
timeout=30,
)
resp.raise_for_status()
return resp.json()
def poll_task_rest(task_id, interval=10, max_wait=600):
"""Poll REST API until task completes."""
elapsed = 0
while elapsed < max_wait:
data = get_task_rest(task_id)
status = data.get("status")
print(f" [{elapsed:>4}s] {status}")
if status == "succeeded":
return data
elif status in ("failed", "cancelled"):
return data
time.sleep(interval)
elapsed += interval
return None
# Example REST call (uncomment to run)
# task = create_task_rest(
# model="seedance-1-5-pro-t2v-250612",
# content=[{"type": "text", "text": "A cat playing piano. --resolution 480p --duration 4"}]
# )
# print(json.dumps(task, indent=2))
# result = poll_task_rest(task["id"])
print("REST API functions defined.")8. プロンプトエンジニアリングガイド
基本公式
Subject + Movement → Background + Movement → Camera + Movement
カメラ移動のキーワード
- 固定:
camera fixed,locked shot,static frame - 動き:
slow pan left,zoom in,tilt down,aerial drone,handheld,orbit around subject - マルチショット: ショット間の切り替えには
Cut toまたはCamera switchingを使う
音声のヒント(Seedance 1.5 Pro)
プロンプトに直接音の手がかりを含めます:
"sound of rain on pavement","upbeat jazz in background","whispered narration"
動きの強さを表す程度副詞
"slightly","gently","rapidly","violently","barely"
# Prompt builder utility
def build_prompt(
subject,
subject_action,
background,
camera="",
audio_hint="",
resolution="720p",
duration=5,
camera_fixed=False,
):
"""
Build a structured Seedance prompt.
Args:
subject: Who/what is in the scene
subject_action: What the subject is doing
9. エラーハンドリングと再試行ロジック
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def generate_with_retry(model, content, filename="output.mp4", max_retries=3, backoff=2):
"""
Generate a video with exponential backoff retry.
Retries on:
- Rate limit errors (429)
- Transient server errors (5xx)
Does NOT retry on:
- Invalid parameters (400)
- Authentication errors (401)
"""
for attempt in range(max_retries):
try:
logger.info(f"Attempt {attempt + 1}/{max_retries}")
task = client.content_generation.tasks.create(
model=model, content=content
)
logger.info(f"Task created: {task.id}")
result = poll_task(task.id, verbose=True)
if result:
return download_video(result.content.video_url, filename)
return None
except Exception as e:
error_str = str(e).lower()
if "401" in error_str or "invalid" in error_str:
logger.error(f"Non-retryable error: {e}")
raise
wait = backoff ** attempt
logger.warning(f"Error (attempt {attempt+1}): {e}. Retrying in {wait}s...")
if attempt < max_retries - 1:
time.sleep(wait)
else:
logger.error("Max retries exceeded.")
raise
return None
# Status codes and their meanings
STATUS_GUIDE = {
"queued": "Task waiting to be processed",
"running": "Video generation in progress",
"succeeded": "Video ready for download",
"failed": "Generation failed — check error message",
"cancelled": "Task was cancelled by user",
}
print("Status codes:")
for status, desc in STATUS_GUIDE.items():
print(f" {status:12} → {desc}")10. バッチ生成とコスト監視
def batch_generate(prompts, model=T2V_MODEL, resolution="720p", duration=5):
"""
Submit multiple video tasks and collect results.
Submits all tasks first, then polls — maximizes parallelism
within the concurrency limit (10 concurrent tasks per account).
"""
tasks = []
# Submit all tasks
for i, prompt in enumerate(prompts):
full_prompt = f"{prompt} --resolution {resolution} --duration {duration}"
try:
task = client.content_generation.tasks.create(
model=model,
content=[{"type": "text", "text": full_prompt}],
)
tasks.append({"id": task.id, "prompt": prompt[:50], "status": "queued"})
print(f"✅ Task {i+1}/{len(prompts)} submitted: {task.id}")
except Exception as e:
print(f"❌ Task {i+1} failed to submit: {e}")
tasks.append({"id": None, "prompt": prompt[:50], "status": "error"})
# Poll all tasks
results = []
for task_info in tasks:
if task_info["id"] is None:
results.append(None)
continue
print(f"\nPolling {task_info['id']}...")
result = poll_task(task_info["id"], verbose=False)
results.append(result)
task_info["status"] = result.status if result else "timeout"
print("\n📊 Batch Summary:")
for t in tasks:
print(f" {t['status']:12} | {t['prompt']}")
return results, tasks
# Example batch (3 prompts)
batch_prompts = [
"Ocean waves crashing on rocky cliffs at sunset, slow motion aerial",
"City timelapse at night, car light trails on a busy intersection",
"Coffee being poured into a cup, macro shot, steam rising",
]
estimate_cost("720p", 5)
print(f"\nEstimated cost for {len(batch_prompts)} videos:")
total = estimate_cost("720p", 5) * len(batch_prompts)
print(f"Total: ~${total:.4f}")
# Uncomment to run the batch
# results, summary = batch_generate(batch_prompts)11. タスクをキャンセルする
def cancel_task(task_id):
"""Cancel a running or queued task."""
try:
result = client.content_generation.tasks.cancel(id=task_id)
print(f"Cancelled task {task_id}: {result.status}")
return result
except Exception as e:
print(f"Failed to cancel: {e}")
return None
# cancel_task("your-task-id")
print("cancel_task() defined.")12. 完全なエンドツーエンドの例
完全なパイプライン: プロンプトを構築 → 動画を生成 → ローカルに保存 → インライン表示。
def run_full_example():
"""Complete end-to-end example with Seedance 1.5 Pro."""
# 1. Build a structured prompt
prompt = build_prompt(
subject="A red fox",
subject_action="trots through a snowy pine forest",
background="Snowflakes fall softly, pine branches bend under the weight of snow",
camera="Wide tracking shot follows the fox at low angle",
audio_hint="Soft crunch of snow underfoot, distant wind",
resolution="720p",
duration=7,
camera_fixed=False,
)
print("📝 Prompt:")
print(f" {prompt}\n")
# 2. Estimate cost
cost = estimate_cost("720p", 7, audio=True)
print()
# 3. Generate (with retry)
video_path = generate_with_retry(
model="seedance-1-5-pro-t2v-250612",
content=[{"type": "text", "text": prompt}],
filename="fox_in_snow.mp4",
max_retries=2,
)
# 4. Display
if video_path:
print(f"\n🎬 Video saved to: {video_path}")
display(Video(str(video_path), embed=True, width=640))
else:
print("Generation failed or timed out.")
# Uncomment to run the full example
# run_full_example()
print("run_full_example() defined — uncomment to execute.")まとめ
| 機能 | 詳細 |
|---|---|
| SDK | byteplus-python-sdk-v2 — pip install byteplus-python-sdk-v2 |
| 認証 | BytePlusコンソールから取得したARK_API_KEY |
| ベースURL | https://ark.ap-southeast.bytepluses.com/api/v3 |
| 使用モデル | T2V: seedance-1-5-pro-251215(最新) |
I2V: seedance-1-5-pro-251215(最新) |
|
| すべてのモデル | 5バリアントあり(1.5 Pro、1.0 Pro、1.0 Lite) — モデル概要を参照 |
| APIパターン | 非同期: 作成 → ポーリング → ダウンロード |
| 解像度 | 480p〜1080p(モデルによる) |
| 長さ | 4〜12秒 |
| 並列数 | アカウントあたり最大10件の同時タスク |
| 料金(1.5 Pro) | 音声付き5秒720p動画で約$0.26 |