튜토리얼
HiAPI API로 kling-4.0/text-to-video를 사용하는 방법: curl, Python 및 실행 가능한 요청 예제
개발자를 위한 실전 가이드: 영화적 프롬프트, 동기화 오디오, 비동기 폴링 및 출력 다운로드
kling-4.0/text-to-video의 기능과 적용 시나리오
kling-4.0/text-to-video는 HiAPI 통합 API를 통해 제공되는 생성형 비디오 모델입니다. 텍스트 프롬프트를 주면 비디오 클립을 반환하며, 움직임, 카메라 무빙, 장면 구도는 전적으로 설명에 의해 결정됩니다. 소스 이미지를 애니메이션화할 필요가 없는 텍스트-비디오 엔드포인트이므로, 모델이 프레임 구성과 피사체 외형에 완전한 재량을 가집니다.
적용 시나리오:
- 스크립트나 프롬프트 템플릿에 따라 짧은 영화적 클립을 생성해야 하는 경우 — b-roll, 예고편, 컨셉 보드, 소셜 미디어 비디오.
- 무음 파일을 받아 후반에 음악을 입히는 대신, 동기화 오디오가 비디오와 함께 생성되길 원하는 경우.
- 비디오 생성이 여러 단계(스크립트 작성, 소재 준비, 게시) 중 하나일 뿐인 파이프라인을 구축 중이어서 웹 인터페이스가 아닌 HTTP API가 필요한 경우.
다만 특정 실제 피사체를 프레임 단위로 정밀 제어해야 하거나(이미지-비디오 또는 편집 모델이 더 적합), 사용자 요청에서 동기적으로 응답을 받아야 한다면 이 모델은 적합하지 않습니다. 비디오 생성에는 시간이 걸리므로 이 엔드포인트는 설계상 비동기입니다.
모든 요청이 HiAPI를 경유하므로 플랫폼의 어떤 모델을 사용하든 자격 증명, 요청/응답 형식, 작업 생명주기가 동일합니다. 이러한 일관성이 바로 이 위에서 구축하는 실질적 이유입니다. 나중에 모델을 추가하거나 교체해도 인증이나 폴링 계층을 다시 작성할 필요가 없습니다.
HiAPI의 사전 조건과 인증
첫 요청을 보내기 전에 다음을 갖추었는지 확인하세요:
- HiAPI 계정과 프로젝트 API 키. 기밀로 취급하세요 — 코드 저장소에 커밋하지 말고, 클라이언트 코드에 넣지 마세요.
- 선택한 HTTP 클라이언트. 아래 예제는
curl과 Python 3의requests를 사용합니다. - 카탈로그와 정확히 일치하는 모델 식별자:
kling-4.0/text-to-video. 모델 이름 오타는 첫 호출 실패의 가장 흔한 원인입니다.
자격 증명은 폴링 요청을 포함한 모든 요청에서 HTTP 헤더로 전송됩니다. HiAPI의 일반적인 패턴은 bearer 토큰입니다:
export HIAPI_API_KEY="your-api-key-here"
그런 다음 요청에:
Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json
기본 URL과 키는 하드코딩하지 말고 환경 변수나 비밀 관리자에 보관하세요. 로컬 개발에는 .env 파일과 Python의 os.environ 조회로 충분합니다. 배포된 서비스에는 런타임에 키를 주입하세요.
일찍 들이는 습관 하나: 비디오 작업을 디버깅하기 전에 아주 작은 '나는 누구인가'식 호출 — 가벼운 인증 요청 — 을 만들어 키와 기본 URL이 올바른지 확인하세요. 인증과 모델 로직을 분리하면 나중에 시간을 아낍니다.
실행 가능한 curl 요청
최소 호출은 작업을 생성하고 작업 식별자를 반환합니다. 구조는 다음과 같습니다:
curl -X POST "$HIAPI_BASE_URL/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-4.0/text-to-video",
"prompt": "A slow aerial push over a rain-soaked Tokyo alley at night, neon signs reflecting in puddles, steam rising from vents, shallow depth of field, cinematic color grading",
"generate_audio": true
}'
요청 본문 필드별 해설:
model— 모델 식별자. 필수.prompt— 장면 설명. 품질 예산의 대부분이 여기에 있습니다. 프롬프트 섹션을 참고하세요.generate_audio— 비디오와 함께 동기화 오디오 생성을 요청합니다. 비주얼 트랙만 필요하면 생략하거나 false로 설정하세요.
응답은 완성된 비디오가 아닌 작업 객체입니다. 상태 필드와 폴링에 사용할 id가 예상됩니다 — 예를 들어 상태가 queued 또는 processing이고 작업 id가 함께 옵니다. id를 즉시 저장하세요. 프로세스가 종료되면 그 id가 진행 중인 작업에 대한 유일한 증거입니다.
실용적 팁 두 가지. 첫째, 프롬프트가 길어지면 JSON을 파일에 저장하고 -d @payload.json을 사용하세요 — 여러 줄 프롬프트의 셸 따옴표 처리는 흔한 오류 원인입니다. 둘째, 응답 본문과 HTTP 상태 코드를 별도로 캡처하세요(curl -s -w "\n%{http_code}"). 거부된 요청과 네트워크 장애를 구분할 수 있습니다.
요청을 Python으로 변환
같은 요청을 Python으로 작성하면 구조가 실제 스크립트에 바로 도입하기 좋습니다:
import os
import requests
BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def create_video_job(prompt: str, generate_audio: bool = True) -> dict:
payload = {
"model": "kling-4.0/text-to-video",
"prompt": prompt,
"generate_audio": generate_audio,
}
resp = requests.post(
f"{BASE_URL}/video/generations",
headers=HEADERS,
json=payload,
timeout=30,
)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
job = create_video_job(
"A slow aerial push over a rain-soaked Tokyo alley at night, "
"neon signs reflecting in puddles, steam rising from vents, "
"shallow depth of field, cinematic color grading"
)
print(job)
이렇게 작성하는 이유:
requests.post(..., json=payload)가 직렬화와 콘텐츠 유형을 함께 처리하므로 수동json.dumps를 피할 수 있습니다.raise_for_status()는 4xx/5xx를 잡을 수 있는 예외로 변환하므로, 오류 응답 본문이 조용히 작업으로 파싱되지 않습니다.timeout은 필수입니다. 없으면 멈춘 연결이 워커를 무기한 차단합니다.- 설정은 환경에서 읽는 모듈 수준 상수에 있으므로 함수는 테스트 가능하고 재사용 가능합니다.
이 함수는 작업을 생성만 합니다. 작업 핸들을 즉시 반환하는데, 이는 웹 핸들러나 큐 워커에서 원하는 동작입니다. 결과를 기다리는 방법은 다음 섹션에서 다룹니다.
검증을 견디는 영화적 프롬프트 작성
텍스트-비디오 모델은 구조화된 입력을 선호합니다. 피사체, 카메라, 움직임, 분위기를 명시한 프롬프트는 한 문장 아이디어보다 항상 우수합니다. 각 요소가 모델이 무작위로 결정할 모호성을 제거하기 때문입니다.
사용 가능한 템플릿:
[주제 및 장면], [카메라 위치 및 움직임],
[화면 내 움직임], [조명], [분위기 또는 색보정], [스타일 참조]
적용 예:
새벽녘, 노란 우비를 입은 외로운 라이더가 돌다리를 가로지르고, 낮은 카메라가 바퀴 높이에서 평행으로 따라가며, 안개가 수면 위로 떠다니고, 부드러운 블루 아워 조명에 따뜻한 등불이 더해진, 차분하고 약간 우울한, 와이드스크린 아나모픽 렌즈 질감.
각 부분의 역할:
- 주제 및 장면 — 구체적 명사가 추상적 개념보다 우수합니다. '노란 우비를 입은 외로운 라이더'는 모델이 렌더링할 대상을 주지만, '자유'는 주지 못합니다.
- 카메라 — 위치(
로우 앵글,항공 촬영,아이 레벨)와 움직임(트래킹,느린 돌리 인,정지)은 제작 가치 느낌에 가장 강력한 지렛대입니다. - 화면 내 움직임 — 안개가 떠다니고, 천이 흔들리고, 수면에 물결이 이는 것. 비디오에는 움직임이 필요합니다. 명시하세요.
- 조명과 분위기 — 시간대, 색온도, 감정 톤. 서로 조화를 이루게 하세요.
- 스타일 — 렌즈나 포맷 언어(
아나모픽 렌즈,얕은 심도,시네마틱 컬러 그레이딩)가 감독을 지정하는 것보다 질감을 더 안정적으로 형성합니다.
프롬프트는 서로 경쟁하는 아이디어의 문단이 아니라 몇 문장의 밀도 높은 설명으로 유지하세요. 한 샷에 상반되는 두 동작이 필요하면 클립 두 개를 생성하세요. 그리고 반복하세요: 한 번에 변수 하나만 바꾸세요 — 먼저 카메라, 그다음 조명 — 그래야 모델이 무엇에 반응하는지 알 수 있고 추측하지 않게 됩니다.
비동기 작업 처리와 폴링
비디오 생성은 즉각적이지 않으므로 패턴은 먼저 생성, 그다음 폴링입니다. 생성 부분은 이미 있으니, 다음은 루프입니다:
import time
def wait_for_job(job_id: str, timeout: int = 600) -> dict:
deadline = time.monotonic() + timeout
delay = 2.0
while time.monotonic() < deadline:
resp = requests.get(
f"{BASE_URL}/video/generations/{job_id}",
headers=HEADERS,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
status = job.get("status")
if status == "succeeded":
return job
if status in ("failed", "cancelled"):
raise RuntimeError(f"Job {job_id} ended with status {status}: {job}")
time.sleep(delay)
delay = min(delay * 1.5, 15.0) # back off, cap at 15s
raise TimeoutError(f"Job {job_id} did not finish in {timeout}s")
프로덕션에서 중요한 설계 결정:
타이트 루프 대신 백오프 폴링 사용
짧은 간격에서 시작해 점차 늘리세요 — 위의 지수 백오프는 고정 상한에서 멈춥니다. 지속적인 빠른 폴링은 속도 제한을 소모할 뿐 이득이 없습니다. 생성 시간은 더 일찍 물어본다고 줄어들지 않기 때문입니다.
항상 데드라인 설정
모든 폴링 루프에는 최대 실시간 시간과 초과 시 명확한 오류가 필요합니다. 그렇지 않으면 멈춘 작업이 워커를 조용히 영구 점유합니다.
종료 상태를 최종 결과로 취급
진행 중 상태(queued, processing)와 종료 상태(succeeded, failed, cancelled)를 구분하세요. 성공일 때만 출력을 반환하고, 다른 상태는 계속 루프하지 말고 예외를 던지거나 재시도 경로로 전환해야 합니다.
폴링을 요청 핸들러와 분리
웹 서버에서는 HTTP 응답이 비디오를 기다리며 차단되지 않게 하세요. 작업을 생성하고 id를 클라이언트에 반환하며, 백그라운드 워커나 큐 소비자가 폴링합니다. 작업 id와 마지막으로 알려진 상태를 영속화하여 재시작 후에도 진행 중 작업 추적을 잃지 않게 하세요.
출력 다운로드 및 검증
작업이 succeeded에 도달하면 응답에는 생성된 미디어에 대한 참조가 포함됩니다 — 보통 완성된 파일의 URL입니다. 즉시 다운로드하고 그 URL은 임시로 취급하세요: 최종 사용자에게 제공자 URL을 그대로 전달하지 말고 가져와서 저장하고 자체 영속 위치를 기록하세요.
import pathlib
def download_output(job: dict, dest: pathlib.Path) -> pathlib.Path:
url = job["output"]["video_url"]
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
dest.parent.mkdir(parents=True, exist_ok=True)
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 20):
f.write(chunk)
return dest
누구에게 파일을 넘기기 전에 할 가치가 있는 검증 단계:
- 전송이 완료되었는지 확인. 청크로 스트리밍하고, 기록된 크기와
Content-Length(있는 경우)를 비교하며, 부족하게 읽었으면 크게 실패하세요. - 오디오 트랙 확인.
generate_audio를 요청했다면 파일에 오디오 스트림이 있어야 합니다.ffprobe로 빠르게 검사하는 것이 가장 저렴한 확인입니다:
ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output.mp4
video와 audio 행이 모두 보여야 합니다. 오디오가 없으면 생성 호출에서 플래그가 설정되었는지 다시 확인하세요 — 사후에는 추가할 수 없습니다.
- 길이와 해상도에 대한 기본 검증을 기대치와 비교하여 게시 전에 잘림이나 잘못된 사양의 렌더를 잡으세요.
- 결정적 키로 저장(작업 id + 해시), 먼저 임시 경로에 쓰고 성공 후 이름을 바꾸며, 추적을 위해 작업 id를 자산과 함께 보관하세요.
다운로드가 전송 중간에 실패하면 백오프로 재시도하세요. URL이 만료되었다면 새로운 참조를 얻기 위해 작업 기록을 다시 가져와야 합니다.
재사용 가능한 클라이언트로 캡슐화
위의 각 부분은 자연스럽게 하나의 클래스를 이룹니다. 함께 묶으면 복사하지 않고 프로젝트 간에 가져올 수 있는 것을 얻게 됩니다:
class KlingTextToVideo:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url.rstrip("/")
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
def generate(self, prompt: str, generate_audio: bool = True,
timeout: int = 600) -> dict:
job = create_video_job(prompt, generate_audio) # create half
return wait_for_job(job["id"], timeout=timeout) # poll half
클라이언트가 성숙해지면서 추가할 것들:
- 작업 id를 키로 한 구조화된 로그 — 상태 전환, 폴링 횟수, 경과 시간, 실패. 렌더가 이상할 때 작업 id가 로그 간의 상관 키입니다.
- 일시적 오류(네트워크, 5xx)에만 제한된 재시도. 거부된 요청을 무작정 재시도하지 마세요. 형식이 잘못된 요청 본문은 매번 동일하게 실패하며 할당량만 낭비합니다.
- 자체 계층에서 멱등성 구현. 서비스가 같은 프롬프트를 두 번 제출할 수 있다면 두 작업에 비용을 지불하지 말고 생성 호출 전에 중복 제거하세요.
- 프롬프트 템플릿을 코드가 아닌 데이터로. 영화적 템플릿을 설정 파일에 두면 배포 없이 프롬프트를 반복할 수 있습니다.
- 출력 초 단위로 비용 산정. 과금은 생성된 출력 사용량을 기준으로 하므로 작업별 생성 길이를 추적하면 지출을 기능이나 사용자에 귀속시킬 수 있습니다.
클라이언트가 준비되면 파이프라인은 짧습니다: 템플릿에서 프롬프트를 만들고, generate를 호출하고, 출력을 다운로드하고 검사한 다음, 저장된 파일을 애플리케이션에 넘깁니다. 나중에 HiAPI에 다른 모델을 추가해도 동일한 인증 헤더, 작업 생명주기, 다운로드 패턴이 그대로 적용됩니다 — 이것이 추상화 계층을 한 번만 구축하는 주요 이유입니다.
관련 글
모든 아티클 보기 →-
튜토리얼
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 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드