튜토리얼
hailuo 2.3 Fast 이미지-투-비디오 API 사용 방법: curl, Python 및 실행 가능한 요청
정지 이미지 한 장을 짧은 동영상으로 바꾸고 싶다고 해봅시다. 이 가이드는 hiapi 작업 API를 통해 hailuo-2.3-fast/image-to-video에 접근하는 방법을 다룹니다. 정확한 입력 스키마(온라인 검증기와 대조하여 검증 완료), 그대로 복사해 실행할 수 있는 curl 요청, 작업이 완료될 때까지 폴링하는 완전한 Python 스크립트, 그리고 프로덕션 환경의 세부 사항—콜백, 멱등성 재시도, 그리고 실제로 만나게 될 오류 응답까지 포함합니다.
준비물
- hiapi API 키—콘솔에서 발급받으세요. 키는
sk-...형태이며,Authorization: Bearer요청 헤더에 넣습니다. - 공개적으로 접근 가능한 HTTPS URL에 호스팅된 소스 이미지. API는 업로드 파일이 아니라 URL을 받습니다.
- 아무 HTTP 클라이언트나 가능합니다. 아래 예제는 curl과 Python의
requests를 사용합니다.
이 모델의 초 단위 과금 가격은 가격 페이지에 나와 있습니다.
입력 스키마(검증 완료)
hailuo-2.3-fast/image-to-video는 통합 비동기 작업 엔드포인트를 사용합니다. POST /v1/tasks로 작업을 생성하고, GET /v1/tasks/<taskId>로 작업을 폴링합니다. 입력 스키마는 엄격합니다—알 수 없는 필드는 조용히 무시되지 않고 400과 함께 거부됩니다.
| 필드 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
prompt |
string | ✅ | 원하는 움직임을 설명 |
image_url |
string | ✅ | 단수형—URL 문자열 하나이며, image_urls 배열이 아닙니다 |
duration |
string | 선택 | "6" 또는 "10"—숫자가 아니라 문자열입니다 |
prompt_optimizer |
boolean | 선택 | 백엔드가 움직임에 맞게 프롬프트를 다시 작성하도록 함 |
검증기가 잡아내는 세 가지 함정:
duration은 반드시 문자열이어야 합니다."duration": 6을 보내면400과 함께duration: got number, want string이 반환됩니다."duration": "6"을 보내세요.- 필드는 단수형
image_url입니다. 플랫폼의 다른 많은 동영상 모델(Grok Imagine, Kling)은image_urls배열을 받습니다. 이 모델은 문자열 하나를 받습니다. resolution,aspect_ratio,seed,watermark,end_image_url은 없습니다. 모두additional properties ... not allowed를 반환합니다. 출력 화면 비율은 소스 이미지를 따르며, 움직임 제어는 프롬프트로만 가능합니다.
최소 실행 가능 요청: curl
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hailuo-2.3-fast/image-to-video",
"input": {
"prompt": "카메라가 천천히 다가가고, 커피잔 위로 증기가 피어오르며, 부드러운 아침 햇살",
"image_url": "https://your-cdn.example.com/coffee.jpg",
"duration": "6"
}
}'
성공 응답:
{
"code": 200,
"data": { "taskId": "tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V" },
"message": "success"
}
그런 다음 폴링합니다:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V \
-H "Authorization: Bearer sk-YOUR_KEY"
동영상이 렌더링되는 동안 data.status는 "handling"입니다:
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V",
"model": "hailuo-2.3-fast/image-to-video",
"status": "handling",
"storage": "temp",
"completed": 0,
"created": 1783648872
},
"message": "success"
}
종료 상태는 "success"(동영상 URL은 data.output[0].url)와 "fail"(상세 내용은 data.error)입니다.
완전한 Python 스크립트
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"] # sk-...
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def create_task(prompt: str, image_url: str, duration: str = "6") -> str:
resp = requests.post(
API_BASE,
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "hailuo-2.3-fast/image-to-video",
"input": {
"prompt": prompt,
"image_url": image_url,
"duration": duration, # 문자열: "6" 또는 "10"
},
},
timeout=60,
)
body = resp.json()
if resp.status_code != 200 or not body.get("data", {}).get("taskId"):
raise RuntimeError(f"create failed: {resp.status_code} {body}")
return body["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
task = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
status = task.get("status")
if status == "success":
return task
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} still running after {timeout_s}s")
if __name__ == "__main__":
task_id = create_task(
prompt="고양이가 눈을 깜빡이고, 머리를 창문 쪽으로 돌리며, 산들바람이 털을 스쳐 지나간다",
image_url="https://your-cdn.example.com/cat.jpg",
duration="6",
)
print("task:", task_id)
task = wait_task(task_id)
video_url = task["output"][0]["url"]
print("video:", video_url)
# URL은 유효 기간이 있는 임시 저장소에 있습니다—즉시 다운로드하고 직접 외부 링크하지 마세요.
mp4 = requests.get(video_url, timeout=120).content
with open("output.mp4", "wb") as f:
f.write(mp4)
print(f"saved output.mp4 ({len(mp4)} bytes)")
이 스크립트는 급하게 짜맞춘 구현이 흔히 놓치는 두 가지를 올바르게 처리합니다:
- 동영상을 즉시 다운로드합니다.
storage: "temp"는 출력 URL에 유효 기간(expireAt)이 있음을 뜻합니다. 바이트를 자체 저장소에 영구 보관하세요. 반환된 URL을 데이터베이스에 저장하지 마세요. fail을 종료 상태로 취급합니다. 실패한 작업을 다시 폴링해도 되살아나지 않습니다—새 작업을 생성하세요.
프로덕션 환경 고려 사항
폴링 대신 콜백 사용
스크립트 외부의 사용 사례라면 작업 생성 시 webhook을 등록하고 폴링 루프를 완전히 건너뛰세요:
{
"model": "hailuo-2.3-fast/image-to-video",
"input": { "prompt": "...", "image_url": "https://...", "duration": "6" },
"callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}
"when": "final"을 사용하면 작업이 success 또는 fail에 도달할 때 엔드포인트가 한 번 호출됩니다. 경험칙: 폴링은 CLI, 배치 작업, 모든 임시 상황에 적합합니다. 이미 수신 대기 중인 서버가 있다면 콜백이 더 낫습니다—동영상 작업은 몇 분간 실행되며, 그 몇 분 동안 폴링 루프는 점유된 연결 슬롯 하나와 낭비된 워커 하나일 뿐입니다.
멱등성
생성 호출 자체는 멱등하지 않습니다—검증을 통과한 POST /v1/tasks는 매번 새(과금되는) 작업을 생성합니다. 작업 실행기가 타임아웃 시 재시도한다면, 결과를 처리하기 전에 받은 taskId를 자체 요청 id를 키로 저장하세요. 재시도 시 해당 키에 이미 taskId가 있으면 중복 작업을 생성하지 말고 그것을 폴링하세요.
실제로 만나게 될 오류
| 증상 | 의미 | 해결 |
|---|---|---|
401 — {"error":{"code":"permission_denied","type":"hiapi_error"}} |
키가 유효하지 않거나 해당 키로 이 모델을 사용할 수 없음 | 콘솔에서 키 확인; 응답에 지원용 request_id가 포함됨 |
400 INVALID_REQUEST — duration: got number, want string |
문자열 대신 JSON 숫자를 사용함 | "duration": "6" |
400 INVALID_REQUEST — additional properties '...' not allowed |
스키마에 없는 필드를 보냄 | 해당 필드를 제거—메시지가 위반 필드 각각을 지목함 |
400 INVALID_REQUEST — missing required field "prompt" / "image_url" |
입력이 비었거나 필드명이 잘못됨 | 두 필드 모두 필수 |
작업 생성 후 fail에 도달 |
런타임 실패—흔한 원인은 백엔드가 가져올 수 없는 이미지 URL | 검증기는 생성 시 이미지를 가져오지 않음; URL이 공개적으로 접근 가능한지 확인 |
마지막 행은 강조할 가치가 있습니다: 생성 시 검증은 스키마만 검사합니다. 철자가 틀렸거나 비공개인 image_url은 정상처럼 보이는 taskId와 몇 분 뒤 죽는 작업을 돌려줍니다—그러므로 HTTP 오류뿐 아니라 fail에 대해서도 경보를 설정하세요.
관련 문서
- hailuo-2.3-fast/image-to-video 모델 페이지 — 플레이그라운드와 초 단위 가격
- 이미지-투-비디오 API 워크플로: 프로덕션 가이드 — i2v 엔드포인트를 둘러싼 배치, 저장소, 재시도 아키텍처
- 텍스트-투-비디오 vs 이미지-투-비디오 API — 소스 이미지에 기반해 생성을 고정해야 하는 경우
- Kling 이미지-투-비디오 API 가이드 — 동일한 작업 API, 다른 입력 스키마, 유용한 비교
자주 묻는 질문
해상도나 화면 비율을 설정할 수 있나요?
아니요. hailuo-2.3-fast/image-to-video의 스키마는 resolution과 aspect_ratio를 알 수 없는 필드로 거부합니다. 화면 비율은 소스 이미지를 따르며, 특정 화면 비율이 필요하면 입력 이미지를 미리 잘라내세요.
어떤 길이를 지원하나요?
정확히 두 가지: "6"과 "10"초이며, 문자열로 전달합니다. 다른 값은 400과 함께 value must be one of '6', '10'을 반환합니다.
참조 이미지를 여러 장 전달할 수 있나요?
아니요—해당 필드는 단일 image_url 문자열입니다. 이미지 배열을 받는 모델(예: Grok Imagine의 image_urls)은 다른 스키마를 사용합니다. 확인하지 않은 채 모델 간에 요청 본문을 복사하지 마세요.
움직임은 어떻게 제어하나요?
오직 prompt로만 가능합니다—움직임 강도나 카메라 파라미터는 없습니다. 움직임을 명확히 설명하세요(“카메라가 천천히 다가감”, “머리카락이 바람에 흔들림”). 선택적으로 "prompt_optimizer": true를 설정하면 백엔드가 프롬프트를 확장합니다.
더 느리고 더 높은 품질의 변형이 있나요?
있습니다—hailuo-2.3/image-to-video(-fast 없음)도 플랫폼에 출시되어 있으며, hailuo-2.3/text-to-video는 소스 이미지가 없는 시나리오를 지원합니다. 전환하기 전에 각 변형의 스키마를 확인하세요. 입력 필드가 일치한다고 보장되지 않습니다.
비용은 얼마인가요? 과금은 생성된 동영상의 초 단위로 계산되며 모델마다 다릅니다. 현재 요금은 가격 페이지에서 확인하세요.
체험에 API 키가 필요한가요?
필요합니다—모든 작업 API 호출에는 Bearer sk-... 키가 필요합니다. 콘솔에서 생성할 수 있으며, 먼저 모델 페이지의 플레이그라운드에서 테스트해 보세요.
관련 글
모든 아티클 보기 →-
튜토리얼
HiAPI API로 hailuo-2.3-fast/image-to-video 호출하는 방법: curl과 Python 실전
빠르고 저렴한 이미지-투-비디오 등급의 첫 실행 요청 — 모델 ID부터 MP4 다운로드까지
-
튜토리얼
HiAPI API로 hailuo-2.3/text-to-video를 호출하는 방법: curl, Python 및 실행 가능한 요청 예시
-
튜토리얼
HiAPI에서 Kandinsky 6.0 Pro 텍스트-투-비디오 사용하기: curl 및 Python 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드