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분 이내에 완료됩니다.
1단계: API 키 발급
- evolink.ai에서 무료 계정을 생성합니다
- 대시보드에서 API Keys 섹션으로 이동합니다
- 새 키를 생성하고 복사합니다
키는 sk-로 시작하며 다음과 같은 형태입니다: sk-XpXn...Ms1N.
2단계: 의존성 설치
pip install requests
이것으로 끝입니다. 별도의 SDK 설치도, 복잡한 인증 플로우도 필요 없습니다. API는 Bearer 토큰 인증과 함께 표준 REST를 사용합니다.
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.
차이점: 강한 프롬프트는 연속적인 동작(기지개 → 하품 → 웅크림), 환경적 움직임(햇빛 이동, 먼지 입자), 카메라 동작(고정, 얕은 심도)을 지정합니다.
단일 이미지 프롬프트의 핵심 원칙:
| 원칙 | 예시 |
|---|---|
| 외형이 아닌 동작을 설명 | "서 있는 사람"이 아닌 "앞으로 걸어감" |
| 2~3개의 동작을 나열 | "집어 들기 → 살펴보기 → 내려놓기" |
| 환경적 역학 추가 | "바람에 나뭇잎이 흔들림", "유리에 빗방울이 맺힘" |
| 카메라 움직임 지정 | "천천히 왼쪽으로 패닝", "카메라가 뒤로 물러나며 드러냄" |
| 이미지의 아트 스타일과 일치 | "회화적 붓터치 유지", "3D 렌더 품질" |
전체 프롬프트 엔지니어링 참고 자료는 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."
5개의 개별 이미지 — 캐릭터 1개, 환경 3개, 스타일 참조 1개 — 가 단일 연속 액션 시퀀스로 결합됩니다. 각 @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 호출로 대체합니다.
제품 영상의 과제
이커머스 플랫폼은 점점 더 영상 콘텐츠를 선호합니다. Amazon은 영상이 포함된 제품 목록이 더 높은 전환율을 보인다고 보고합니다. Instagram과 TikTok은 영상 우선 플랫폼입니다. 하지만 간단한 10초 제품 회전 영상 하나를 제작하는 데도 전통적으로 다음이 필요합니다:
- 물리적 턴테이블 설치
- 적절한 조명 장비
- 영상 촬영 전문가 (또는 직접 세심하게 촬영)
- 편집 및 색보정
- 내보내기 및 업로드
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은 사실적인 인간 얼굴 이미지에서의 이미지-투-비디오 생성을 차단합니다. 이것은 버그가 아닌 안전 정책입니다.
해결 방법: 일러스트, 스타일화된 또는 카툰 스타일의 캐릭터 이미지를 대신 사용하세요. 애니메이션 캐릭터, 유화 초상화, 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: 외형만 설명하는 정적 프롬프트
발생 현상: 생성된 영상에 움직임이 거의 또는 전혀 없습니다. 피사체가 가만히 서 있거나 미세한 카메라 드리프트만 발생합니다.
이유: 모델은 프롬프트를 문자 그대로 받아들입니다. 정적인 장면을 설명하면 ("창턱에 앉은 고양이"), 거의 정적인 영상을 얻습니다.
해결 방법: 항상 동작 동사, 연속적인 동작, 환경 역학을 포함하세요.
# 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 미사용
발생 현상: 프롬프트에서 @Image 태그를 사용하지 않고 3개 이상의 이미지를 전달하면 모델이 어떤 이미지가 어떤 용도인지 추측합니다. 결과가 예측 불가능합니다 — 때로는 배경 이미지가 캐릭터로 사용되거나, 스타일 참조가 장면 요소로 처리됩니다.
해결 방법: 이미지를 두 개 이상 전달할 때는 항상 @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: 프롬프트와 이미지 콘텐츠의 충돌
발생 현상: 출력 영상이 혼란스러워 보입니다 — 이미지의 요소와 프롬프트의 요소가 주도권을 다투며 시각적 아티팩트나 비일관적인 장면을 만듭니다.
이유: 프롬프트에서 참조 이미지와 직접적으로 모순되는 것을 설명했습니다. 예를 들어, 이미지는 빨간 자동차를 보여주는데 프롬프트에 "파란 스포츠카가 고속도로를 달립니다"라고 적었습니다.
해결 방법: 프롬프트는 이미지를 모순하는 것이 아니라 보완해야 합니다. 참조 이미지로 이미 정의된 요소의 외형이 아닌, 동작, 카메라 움직임, 환경 변화를 설명하세요.
# 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 | 예 (i2v의 경우) | [] | 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.
FAQ
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개의 비디오 또는 오디오 참조를 추가할 수 있습니다.
이미지-투-비디오와 오디오 생성을 결합할 수 있습니까?
네. 요청 페이로드에서 image_urls와 함께 generate_audio: true를 설정하세요. 모델이 시각적 콘텐츠에 맞는 동기화된 오디오를 생성합니다 — 걷는 장면에는 발소리, 자연 장면에는 주변 소리, 제품 회전에는 기계 소리. audio_urls를 통해 자체 오디오를 제공하고 프롬프트에서 @Audio1로 참조할 수도 있습니다.
프로덕션에서 비디오 URL 만료를 어떻게 처리합니까?
생성된 비디오 URL은 24시간 후 만료됩니다. 프로덕션 시스템의 경우 파이프라인에 즉시 다운로드 단계를 구현하세요. 작업 상태가 completed로 변경된 후, 애플리케이션에 URL을 반환하기 전에 비디오 파일을 자체 스토리지(S3, GCS, 또는 로컬 디스크)에 다운로드하세요. API가 생성한 URL을 영구 참조로 저장하지 마세요. callback_url을 사용하는 경우 웹훅 핸들러의 처리 로직에 다운로드 단계를 포함해야 합니다.
Seedance 2.0 이미지-투-비디오를 애니메이션 로고나 브랜드 인트로에 사용할 수 있습니까?
네, 이것은 가장 강력한 활용 사례 중 하나입니다. 로고 또는 브랜드 마크를 @Image1으로 업로드하고 원하는 애니메이션 스타일 — 파티클 조립, 리퀴드 리빌, 3D 회전 등 — 을 프롬프트하세요. 로고는 그래픽 요소이므로(사실적인 얼굴이 아님) 이미지-투-비디오 파이프라인에서 완벽하게 작동합니다. generate_audio: true를 설정하면 리빌에 동기화된 사운드 이펙트를 추가할 수 있습니다.
이미지-투-비디오 요청이 거부된 이유는 무엇입니까?
가장 일반적인 거부 사유는 입력 이미지에 사실적인 인간 얼굴이 포함된 경우입니다. Seedance 2.0은 안전상의 이유로 사실적인 얼굴 이미지를 자동으로 감지하고 차단합니다. 다른 거부 원인으로는 접근 불가능한 이미지 URL, 지원하지 않는 파일 형식, 9개 이미지 제한 초과, 또는 총 미디어 파일 수가 12개를 초과하는 경우가 있습니다. 구체적인 세부 사항은 failed 작업 응답의 오류 메시지를 확인하세요.
이미지 애니메이션을 시작하세요
이제 Seedance 2.0 API를 통해 정적 이미지를 영상으로 변환하는 세 가지 고유한 방법을 갖추었습니다: 빠른 캐릭터 또는 장면 모션을 위한 단일 이미지 애니메이션, 정밀한 시작-종료 전환을 위한 첫-마지막 프레임 제어, 그리고 복잡한 역할 지정 장면을 위한 @tags를 활용한 멀티 이미지 합성.
이 가이드의 코드 예제는 완전하며 바로 실행 가능합니다. 아무거나 복사하고, API 키를 입력하고, 자신의 이미지를 지정하면 몇 분 안에 생성된 영상을 얻을 수 있습니다.
제품 팀에게는 일괄 생성 워크플로우가 스튜디오 없이 전체 제품 카탈로그를 영상 자산으로 변환합니다. 크리에이티브 팀에게는 캐릭터 일관성 패턴이 단일 캐릭터 참조에서 멀티샷 스토리텔링을 가능하게 합니다. 개발자에게는 @tag 시스템이 현재 다른 어떤 AI 비디오 API도 제공하지 못하는 수준의 구성적 제어를 제공합니다.
이미지 애니메이션을 시작하세요. EvoLink에서 무료로 가입하기 →
이 가이드는 Seedance 2.0 튜토리얼 시리즈의 일부입니다. 이전 글: Seedance 2.0 프롬프트 가이드, 시작하기, 멀티모달 @Tags 가이드, 카메라 무브먼트 가이드.