HiAPI
블로그

튜토리얼

HiAPI API로 veo-3.1-lite/text-to-video를 호출하는 방법: curl과 Python

바로 복사할 수 있는 요청 예시, 프롬프트로 영상을 생성하는 흐름, 그리고 비동기 폴링 패턴

Nov 3, 2026
深炭底色上,一道琥珀色光带横向掠过,构图克制,是这篇教程文章的封面图。

veo-3.1-lite/text-to-video가 제공하는 것

veo-3.1-lite/text-to-video는 HiAPI의 텍스트-투-비디오 엔드포인트입니다. 텍스트 프롬프트를 보내면 모델이 생성된 영상 클립을 반환합니다. 이름에 들어 있는 "lite"는 모델을 선택할 때 가장 중요한 신호입니다. 경량 등급은 최고 수준의 충실도가 아니라 처리량과 빠른 반복을 위해 만들어졌으므로, 짧은 클립을 대량으로 필요로 할 때, 더 무거운 모델을 채택하기 전에 기능을 프로토타이핑할 때, 또는 해당 클립이 더 큰 자동화 파이프라인의 일부일 뿐이라 클립당 지연 시간과 배치 규모가 영화 같은 품질보다 더 중요할 때 좋은 기본 선택입니다.

클립 자체가 곧 제품일 때—예컨대 메인 비주얼 샷, 마케팅 소재, 또는 누군가 프레임 단위로 검토할 콘텐츠—에는 더 무거운 텍스트-투-비디오 모델로 전환해야 합니다. 반면 클립이 하나의 구성 요소일 때—예컨대 초안 미리보기, 배경 루프, 스토리보드 러프, 나중에 다듬을 1차 렌더링—에는 veo-3.1-lite/text-to-video를 선택하세요.

이 엔드포인트의 두 가지 특성이 이후 모든 내용을 결정합니다:

  • 비동기입니다. 생성 요청 하나가 같은 응답에서 재생 가능한 파일을 바로 주지는 않습니다. 작업을 제출하고, 해당 작업에 대한 참조를 받은 뒤, 작업이 완료되어 출력 URL을 사용할 수 있을 때까지 폴링합니다.
  • 프롬프트로 구동됩니다. 이 흐름에는 입력 이미지나 원본 영상이 없습니다. 보내는 텍스트가 곧 완전한 창작 브리프이므로, 프롬프트 품질이 여러분이 쥔 주요 레버입니다.

이 가이드의 나머지 부분은 실전 연습입니다: 요청 구성, curl로 제출, Python으로 이식, 올바른 폴링, 그리고 실제로 마주치게 될 실패 상황 처리.

사전 준비와 인증

첫 호출 전에 다음을 갖추었는지 확인하세요:

  • HiAPI 계정의 API 키. 데이터베이스 비밀번호처럼 신중하게 기밀 정보로 취급하세요.
  • HTTP 요청을 보낼 수단: 빠른 점검에는 curl, 스크립트 작업에는 requests 라이브러리가 있는 Python 3를 사용합니다.
  • 최종 클립을 보관할 위치, 출력이 URL 형태로 도착하므로 이를 다운로드해야 합니다.

키는 모든 요청에서 HTTP 헤더로 전달됩니다. 표시된 헤더 이름과 Bearer 접두사를 그대로 따르세요. 헤더 누락이나 형식 오류가 첫 호출 실패의 가장 흔한 원인입니다.

키를 소스 관리에서 멀리하기

실제 키를 커밋하게 될 파일에 절대 붙여 넣지 마세요. 대신 환경 변수를 사용하세요:

export HIAPI_API_KEY="your-key-here"

그런 다음 런타임에 읽으세요. 팀이나 CI 파이프라인에서 작업한다면 키를 비밀 관리자에 보관하고 배포 시 환경 변수로 주입하세요. 실수로 커밋되거나, 티켓에 붙여 넣어지거나, 로그에 출력되는 등 키가 한 번이라도 노출되었다면 아무도 눈치채지 못할 것이라 기대하지 말고 즉시 교체하세요.

다른 무엇을 디버깅하기 전에 환경 변수가 설정되었는지 빠르게 점검하세요:

test -n "$HIAPI_API_KEY" && echo "key is set" || echo "key is missing"

작동하는 curl 요청

아래는 텍스트-투-비디오 제출 요청의 형태입니다. 자리 표시자인 엔드포인트 기본 주소를 HiAPI 참조 문서에 기록된 주소로 바꾸고, 모델 식별자는 그대로 유지하세요: veo-3.1-lite/text-to-video.

curl -X POST "$HIAPI_BASE_URL/v1/videos/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1-lite/text-to-video",
    "prompt": "A slow dolly-in on a rain-soaked neon sign at night, shallow depth of field, gentle camera drift, cinematic color"
  }'

성공적인 제출은 영상 바이트를 반환하지 않습니다. 작업 객체를 반환합니다: 해당 작업의 식별자, queued 또는 processing 같은 초기 상태를 담은 status 필드, 그리고 생성 시간에 관한 메타데이터가 포함됩니다. 이 식별자가 이후 모든 작업의 핸들입니다—상태가 종료 상태가 될 때까지 폴링해야 하며, 그때에야 응답이 생성된 클립의 URL을 담습니다.

수동으로 테스트 중이라면 눈으로만 보지 말고 전체 응답을 캡처하세요:

curl -s -X POST "$HIAPI_BASE_URL/v1/videos/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"veo-3.1-lite/text-to-video","prompt":"A paper boat drifting down a sunlit gutter, macro lens"}' \
  | tee submission.json

지금부터 들일 만한 두 가지 습관이 있습니다. 첫째, 항상 Content-Type: application/json을 보내세요. JSON처럼 보이지만 JSON으로 선언되지 않은 요청 본문은 거부됩니다. 둘째, 호출이 실패하면 무엇이든 바꾸기 전에 오류 응답 본문을 먼저 읽으세요—HiAPI는 구조화된 메시지를 반환하며, 보통 상태 코드만 보는 것보다 문제(잘못된 키, 알 수 없는 모델, 누락된 필드)를 더 정확히 짚어 줍니다.

여기서 2xx가 아닌 상태 코드가 반환되면 작업이 수락되지 않은 것입니다. 실패한 제출에 대해 폴링하지 마세요. 먼저 요청을 고치세요.

같은 요청을 Python으로 구현하기

curl 호출은 그대로 이식할 수 있습니다. 아래 스크립트는 프롬프트를 제출하고, 제출 성공 여부를 확인하며, 폴링 단계에서 사용할 작업 참조를 저장합니다.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"]
API_KEY = os.environ["HIAPI_API_KEY"]

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "veo-3.1-lite/text-to-video",
    "prompt": (
        "A single lantern floating on still black water, "
        "soft ripples, warm light against cool darkness, slow push-in"
    ),
}

response = requests.post(
    f"{BASE_URL}/v1/videos/generations",
    headers=headers,
    json=payload,
    timeout=30,
)

if response.status_code >= 400:
    raise RuntimeError(f"Submission failed: {response.status_code} {response.text}")

job = response.json()
job_id = job["id"]
print(f"submitted job {job_id} with status {job.get('status')}")

이 코드 조각에는 몇 가지 의도적인 선택이 있습니다:

  • 문자열을 직접 조립하는 대신 json=payload를 사용합니다. 직렬화와 콘텐츠 유형 설정은 라이브러리에 맡기세요. 이렇게 하면 인용 부호 관련 버그 한 묶음을 피할 수 있습니다.
  • timeout을 명시적으로 설정합니다. 설정하지 않으면 연결이 멈출 때 스크립트가 무한정 대기합니다. 제출 호출은 빠르므로 여기서 넉넉한 타임아웃을 두어도 여전히 짧습니다.
  • 2xx가 아니면 즉시 실패합니다. 즉시 예외를 던지면 손상된 작업 ID가 폴링 루프로 전파되는 대신 오류가 원인 바로 옆에 드러납니다.
  • 키는 os.environ에서 가져옵니다. 파일 자체에는 어떤 기밀 정보도 기록되지 않습니다.

이를 job_id를 반환하는 함수로 감싸면 어떤 파이프라인이든 제출 부분을 갖추게 됩니다.

비동기 작업 폴링 및 클립 다운로드

영상 생성에는 시간이 걸립니다. 제출 호출은 1~2초 안에 반환되지만 실제 렌더링은 그렇지 않습니다. 첫 응답에 영상 URL이 포함된다고 가정하는 코드를 작성하면 실패합니다—API가 고장 난 것이 아니라, 아직 완료되지 않은 작업을 읽고 있기 때문입니다.

올바른 패턴은 유한 폴링입니다: 검사 사이에 잠시 쉬고, 대기 시간이 길어질수록 백오프하며, 최대 시도 횟수에 도달하면 무한 루프 대신 포기합니다.

import time
import requests

def wait_for_video(job_id, headers, base_url, max_attempts=60, initial_delay=5):
    delay = initial_delay
    for attempt in range(1, max_attempts + 1):
        r = requests.get(
            f"{base_url}/v1/videos/generations/{job_id}",
            headers=headers,
            timeout=30,
        )
        if r.status_code >= 400:
            raise RuntimeError(f"Poll failed: {r.status_code} {r.text}")

        data = r.json()
        status = data.get("status")
        print(f"attempt {attempt}: {status}")

        if status == "completed":
            return data
        if status in {"failed", "cancelled"}:
            raise RuntimeError(f"Job {job_id} ended as {status}: {data}")

        time.sleep(delay)
        delay = min(delay * 1.5, 30)

    raise TimeoutError(f"Job {job_id} did not finish within polling budget")

작업이 completed에 도달하면 응답이 출력 위치—즉 완료된 클립의 URL—을 담습니다. 클립이 크다면 메모리로 스트리밍하지 말고 다운로드하세요:

result = wait_for_video(job_id, headers, BASE_URL)
video_url = result["output"]["url"]

with requests.get(video_url, stream=True, timeout=120) as r:
    r.raise_for_status()
    with open(f"{job_id}.mp4", "wb") as f:
        for chunk in r.iter_content(chunk_size=1 << 16):
            f.write(chunk)

print("saved", f"{job_id}.mp4")

프로덕션에서는 두 가지 세부 사항이 중요합니다. 첫째, 출력 URL에는 시간 제한이 있을 수 있으므로 링크를 며칠간 저장해 두었다가 나중에 가져오지 말고 제때 다운로드하세요—파일을 영구 보관하거나 자체 스토리지에 복사하세요. 둘째, 모든 산출물 옆에 작업 ID를 기록하세요. 다운스트림에서 문제가 생기면 작업 ID를 통해 여러분의 기록과 API가 실제로 반환한 내용을 대조할 수 있습니다.

흔한 오류와 해결 방법

대부분의 첫 실행 실패는 몇 가지 유형에 속합니다. 아래에 각 유형의 증상과 바꿔야 할 점이 나와 있습니다.

인증 실패

제출 시 401 또는 403이 반환되면 키가 수락되지 않은 것입니다. 순서대로 확인하세요: 해당 셸이나 프로세스에 환경 변수가 실제로 값이 있는지, 헤더 이름이 Authorization인지, Bearer 접두사가 있고 뒤에 공백이 있는지, 키가 교체되거나 폐기되지 않았는지. 터미널에서는 키가 작동하지만 CI에서는 실패한다면 거의 항상 비밀이 해당 환경에 주입되지 않았다는 뜻입니다.

모델 식별자 무효

모델 이름을 지목하며 400 또는 404가 반환되면 문자열이 일치하지 않는 것입니다. 식별자는 veo-3.1-lite/text-to-video입니다—슬래시와 버전 번호도 그 일부입니다. 다시 입력하지 말고 복사해서 붙여 넣으세요. 여분의 공백 하나나 바뀐 버전 번호만으로도 실패하기에 충분합니다.

프롬프트 형식 오류 또는 비어 있음

빈 prompt, 누락된 prompt 필드, 또는 Content-Type: application/json 없이 요청 본문을 보내는 경우 생성이 시작되기 전에 거부됩니다. 프롬프트를 동적으로 구성한다면 호출이 실패할 때 보낸 정확한 문자열을 기록하세요—공백이나 잘린 프롬프트를 만드는 템플릿 버그는 흔하며, 실제로 출력해 보기 전에는 보이지 않습니다.

폴링 타임아웃

wait_for_video가 예산을 다 썼다면 즉시 다시 제출하지 마세요. 작업이 단지 아직 실행 중일 수 있습니다. 상태를 한 번 더 확인하고, 폴링 간격이 너무 길어 예산을 잠자는 데 다 써 버리지는 않았는지, 예산이 요청한 클립 길이에 현실적인지 확인하세요. 타임아웃마다 다시 제출하는 것이 바로 같은 클립에 대해 실수로 여러 번 비용을 지불하게 되는 이유입니다.

속도 제한

429는 백오프가 필요하다는 뜻입니다. 폴링 루프의 지수 지연이 이미 여기에 도움이 됩니다. 제출에도 같은 자제를 적용하고, 작업을 몰아서 보내지 말고 대기열에 넣으세요. 확실하지 않다면 먼저 응답 헤더의 재시도 안내를 따르고, 그다음 자신의 백오프 계획을 실행하세요.

프로덕션 전 비용과 반복에 관한 조언

영상 생성은 출력 기준—즉 여러분이 만들어 내는 콘텐츠의 길이—으로 과금되므로, 비용이 많이 드는 실수는 작은 아이디어를 긴 클립으로 테스트하는 것입니다. 가장 저렴한 워크플로는 필요 없는 클립을 절대 생성하지 않는 워크플로입니다.

최종 출력이 아니라 프롬프트 구조를 테스트하세요. 이 엔드포인트가 지원하는 가장 짧은 길이로 프롬프트를 작성하고 다듬으세요. 구도, 움직임, 카메라 언어가 짧은 클립에서 올바르게 읽힌다면, 최종 렌더링을 위해 길이를 늘리세요. 대부분의 프롬프트 반복은 길이가 아니라 문구에 관한 것이며, 짧은 렌더링도 문구 질문에는 똑같이 답합니다.

프롬프트 로그를 유지하세요. 각 테스트의 프롬프트, 길이, 자신의 평가를 기록하세요. 기록된 10번의 반복이 기록 없는 50번의 반복보다 이 모델이 무엇에 반응하는지 더 잘 알려 주며, 이미 기각한 프롬프트를 다시 테스트하지 않게 됩니다.

의식적으로 배치 처리하세요. 클립이 많이 필요하다면 대기열에 넣고 속도 제한 내에서 동시에 실행하되, 먼저 소량의 프롬프트로 전체 배치를 시범 실행하세요. 작업 200개를 제출한 뒤에야 체계적인 프롬프트 버그를 발견하는 것이 가장 피할 수 있는 비용입니다.

절제해서 폴링하세요. 자주 폴링한다고 렌더링이 더 빨리 끝나지 않으며, 속도 제한에 걸릴 수 있습니다. 적당한 초기 간격에 완만한 백오프를 더한 것이 올바른 기본값입니다.

일찍, 크게 실패하세요. 위 코드의 모든 방어 장치—제출 시 2xx가 아니면 예외, 폴링 중 종료 실패 감지, 유한한 시도 횟수—는 같은 작업에 두 번 비용을 지불하지 않도록 하기 위한 것입니다. 프로덕션에서도 이를 유지하세요.

짧은 프롬프트와 curl 요청으로 시작해 작업 수명 주기를 엔드투엔드로 확인한 뒤, 같은 흐름을 Python 파이프라인으로 옮기세요. 전체 엔드포인트 참조는 veo-3.1-lite/text-to-video에 관한 HiAPI 모델 문서 페이지에 있습니다.

영구 AI 아티팩트로 빌드 시작하기

API 키를 받아 태스크 기반의 하나의 API로 이미지, 비디오, 오디오 모델을 호출하세요.

API 문서 보기