문서

문서

동영상 생성

Google Veo 3.1 제품군에서 텍스트-동영상과 이미지-동영상을 생성합니다. 두 가지 API 형식을 제공합니다. 클립이 준비될 때까지 대기하는 단일 동기 엔드포인트와 프로덕션 워크로드용 제출 및 폴링 비동기 엔드포인트 쌍입니다.

엔드포인트: POST /v1/video/generations(동기식, 먼저 설명) 및 POST /v1/videos + GET /v1/videos/{id}(비동기식, 프로덕션 권장). 생성은 모델과 길이에 따라 30초에서 몇 분까지 걸립니다. 동기식 엔드포인트의 경우 클라이언트 시간 제한을 넉넉하게 설정하세요(600s면 안전합니다).

텍스트-동영상

prompt를 전달하고 모델을 선택하세요. aspect_ratio는 선택 사항입니다.

import requests

resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane unfolding, soft light",
        "aspect_ratio": "16:9",
    },
    timeout=600,  # video generation can take minutes
)
print(resp.json()["data"][0]["url"])

duration은 초 단위 값으로, 초당 과금 모델, 즉 Seedance 모델들과 Wan 2.7에서 클립 길이를 지정합니다. Veo 모델은 이 값을 무시하며, 모든 Veo 클립은 8초이고 동영상당 과금됩니다.

# The models billed per second take a clip length: here 5 seconds of
# Seedance 2. Leave "duration" out and these models make a 5-second clip.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "seedance-2",
        "prompt": "a paper crane unfolds into a flock of birds over a city at dawn",
        "duration": 5,
        "aspect_ratio": "16:9",
    },
    timeout=600,
)
print(resp.json()["data"][0]["url"])

이미지-동영상

image_url를 추가하면 Veo가 해당 이미지를 바탕으로 애니메이션을 생성합니다. 기본적으로 정지 이미지가 동영상의 첫 프레임이 됩니다.

# Image-to-video: animate a still image. The source image can be an
# https URL, or inline base64 — Kunavo hosts it for the model automatically.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "the crane gently lifts off the desk",
        "image_url": "https://your-cdn.com/source.png",
    },
    timeout=600,
)
print(resp.json()["data"][0]["url"])
image_url에는 https:// URL 또는 인라인 data: base64 URI를 사용할 수 있습니다. 모델 실행 전에 base64를 디코딩해 Kunavo CDN에 자동으로 호스팅합니다.

첫 프레임, 마지막 프레임, 참조 이미지

image_mode는 Veo가 이미지를 사용하는 방식을 제어합니다. 이미지 여러 장을 보내려면 image_urls(배열)을 전달하세요.

  • frame(기본값) — 이미지 한 장은 첫 프레임이 됩니다. 두 장은 첫 프레임과 마지막 프레임이 되며 Veo가 그 사이의 전환을 생성합니다.
  • reference — 이미지 최대 세 장을 스타일 및 피사체 참조로 사용합니다. 이미지가 전체적인 모양을 이끌지만 프레임으로 등장하지는 않습니다.
# First + last frame: pass two images and Veo fills in the motion.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "a smooth transition between the two poses",
        "image_urls": [
            "https://your-cdn.com/first.png",
            "https://your-cdn.com/last.png",
        ],
        "image_mode": "frame",
    },
    timeout=600,
)

소스 프레임 업로드

로컬 파일만 있는 경우 POST /v1/files를 통해 한 번 업로드하고 반환된 영구 URL을 재사용하세요.

# No public URL? Upload the still first, then animate it.
with open("frame.png", "rb") as f:
    up = requests.post(
        "https://api.kunavo.com/v1/files",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": f},
    ).json()

resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "slow push-in, volumetric light",
        "image_url": up["url"],
    },
    timeout=600,
)

매개변수

매개변수유형참고
model문자열(필수) /v1/models에서 제공하는 동영상 모델 슬러그입니다.
prompt문자열(필수)장면에 대한 텍스트 설명입니다.
image_urlstring이미지-동영상 생성용 소스 이미지 하나입니다. URL 또는 data: URI.
image_urlsstring[]여러 소스 이미지(Veo). image_url보다 우선합니다.
image_modestringVeo: "frame"(기본값 — 첫 프레임/마지막 프레임) 또는 "reference"(스타일 참조).
durationint초당 과금 모델의 클립 길이(초)이며, 생략하면 5초입니다. Seedance 2, Seedance 2 Fast, Seedance 2.0 Mini는 4~15초, Seedance 2.5는 4~30초, Wan 2.7은 2~15초를 지원합니다. 모델의 범위를 벗어난 길이는 400 오류로 거부됩니다. Veo는 이 값을 무시하며, 모든 Veo 클립은 8초입니다.
aspect_ratiostring예: "16:9", "9:16", "1:1".
resolutionstring모델이 화질 등급을 제공하는 경우 사용합니다. 예: "720p", "1080p".
inputobject예외적인 사용자 지정 설정입니다. 아래 Raw input를 참조하세요.

원시 입력용 예외 처리

초당 과금 모델에서는 input이 Kunavo 어댑터가 구성했을 입력 대신 작성한 그대로 업스트림으로 전송됩니다. Veo 모델은 이 값을 무시합니다.

가격을 결정하는 필드는 예외입니다. resolution은 항상 모델의 등급 중 하나로 전송되며(생략하거나 해당 등급 중 하나가 아닌 경우 기본 등급), duration은 모델의 범위 내에 있는 초 단위의 정수여야 합니다(그 외의 값은 400 오류로 거부되고, 생략하면 5가 전송됩니다). input이 설정되면 요청 자체의 resolution 및 duration은 읽지 않습니다.

동영상 모델

슬러그제공자참고
veo-3GoogleVeo 3.1 Fast — Quality보다 빠르고 저렴하며, 네이티브 오디오 지원.
veo-3-qualityGoogleVeo 3.1 Quality — 최고 충실도.
veo-3-liteGoogleVeo 3.1 Lite — 미리보기용 저가 등급.
seedance-2-5ByteDanceSeedance 2.5 — 최대 30초 클립, 멀티모달 참조, 초당 과금.
seedance-2ByteDanceSeedance 2 — 여러 장면 간 일관성, 최대 1080p, 초당 과금.
seedance-2-fastByteDanceSeedance 2 Fast — 저가 등급, 최대 720p, 초당 과금.
seedance-2-miniByteDanceSeedance 2.0 Mini — 가장 저렴한 등급, 480p/720p만 지원, 초안과 대량 생성용.
wan-2-7AlibabaWan 2.7 — 영화 같은 텍스트-동영상 생성, 초당 과금.

실시간 모델 목록과 모델별 요금은 항상 /models에서 확인하세요.

지연 시간 및 시간 초과

  • Kunavo는 504를 반환하기 전에 최대 540초 동안 업스트림 작업을 폴링합니다.
  • 빠른 등급(Veo 3.1 Fast / Lite): 보통 30–90초.
  • Quality 등급과 긴 동영상: 2–5분.
  • HTTP 클라이언트 시간 제한을 최소 600s로 설정하세요.
  • 네트워크가 불안정하거나 모바일 클라이언트를 사용하는 경우 비동기 API를 사용하세요. 제출은 몇 초 안에 완료되고 결과는 폴링해 확인할 수 있습니다.

비동기 API(제출 + 폴링)

엔드포인트: POST /v1/videos + GET /v1/videos/{id}. 엔드포인트가 반환하는 작업 객체는 OpenAI의 비디오 객체와 동일한 필드 이름 및 상태 값을 사용하며, 클립의 URL이 담긴 output 필드가 추가되어 있습니다. 요청은 위의 매개변수를 포함하는 JSON 본문입니다.

앞서 설명한 동기식 엔드포인트는 HTTP 연결을 최대 9분 동안 열어 둡니다. 일회성 스크립트에는 편리하지만 모바일에서는 안정성이 낮고 서버 효율도 떨어집니다. 비동기 엔드포인트 쌍은 vid_* ID를 즉시 반환합니다. status가 completed 또는 failed가 될 때까지 GET /v1/videos/{id}를 폴링하세요. 모델, 요금, 보관된 URL은 동기식과 동일합니다.

import requests, time

# 1. Submit — returns immediately with a task id. No long-lived connection.
submit = requests.post(
    "https://api.kunavo.com/v1/videos",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        # Optional: retrying with the same key inside ~24h returns the
        # original task rather than submitting again.
        "Idempotency-Key": "my-task-uuid",
    },
    json={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane",
        "aspect_ratio": "16:9",
    },
    timeout=60,
).json()

task_id = submit["id"]              # "vid_abc..."
status  = submit["status"]          # "queued"

# 2. Poll until terminal. Recommended cadence: 5s, backing off to 30s.
while status not in ("completed", "failed"):
    time.sleep(5)
    r = requests.get(
        f"https://api.kunavo.com/v1/videos/{task_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=30,
    ).json()
    status = r["status"]

if status == "failed":
    raise RuntimeError(r["error"]["message"])
print(r["output"]["url"])

OpenAI SDK에서는 아래와 같이 client.post로 해당 본문을 전송하고 client.get으로 폴링하세요. SDK 자체의 client.videos.create는 여기서 작동하지 않습니다. 이 메서드는 Sora의 매개변수만 받으며 이를 멀티파트 폼으로 전송합니다(Python SDK 버전 2.27.0부터). 이 엔드포인트는 이러한 멀티파트 요청을 400 오류로 거부합니다.

import time
from openai import OpenAI

client = OpenAI(api_key=API_KEY, base_url="https://api.kunavo.com/v1")

# The same JSON body, sent with the client's own post().
task = client.post(
    "/videos",
    body={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane",
        "aspect_ratio": "16:9",
    },
    # object hands back the JSON as parsed. Passing dict instead raises
    # after the task has been created.
    cast_to=object,
    options={"headers": {"Idempotency-Key": "my-task-uuid"}},
)

while task["status"] not in ("completed", "failed"):
    time.sleep(5)
    task = client.get(f"/videos/{task['id']}", cast_to=object)

if task["status"] == "failed":
    raise RuntimeError(task["error"]["message"])
print(task["output"]["url"])

응답 형식

필드유형참고
idstringvid_ 접두사가 붙은 작업 ID입니다. 업스트림 변경과 관계없이 안정적으로 유지됩니다.
objectstring"video".
statusstringqueued | in_progress | completed | failed.
modelstring제출한 모델 슬러그
created_atint제출을 수락한 Unix 시간(초)
completed_at정수 | null종료 상태에 도달한 Unix 시간(초). 대기 중에는 null입니다.
expires_atintUnix 초 단위이며 제출 후 30일 시점입니다. 적어도 그때까지는 작업을 폴링할 수 있습니다. 결과 URL은 만료되지 않습니다.
progressint0–100. 현재는 작업이 종료 상태가 될 때까지 0을 반환하고, 이후 100을 반환합니다.
output객체 | null완료 시 {url, urls[], duration_seconds, resolution}입니다. duration_seconds는 모델에 요청한 클립 길이이며 Veo에서는 null입니다. resolution은 클립의 해상도 등급이며, 기록된 값이 없으면 null입니다.
error객체 | null실패 시 {code, message}입니다.

헤더 및 규칙

  • Idempotency-Key(선택 사항, 최대 128자) — 같은 계정에서 동일한 키로 두 번 제출하면 중복 작업을 만들지 않고 기존 작업을 반환합니다. 재시도 루프에 유용합니다.
  • 새 제출 시 POST /v1/videos는 202 Accepted를 반환합니다. 멱등성 키가 일치해 이전 결과를 재생할 때는 200 OK를 반환합니다.
  • GET /v1/videos/{id}는 소유자 기준으로 범위가 제한됩니다. 다른 계정에 속한 작업을 조회하면 404를 반환하며, 다른 사람의 작업 ID가 존재하는지는 알려주지 않습니다.
  • 권장 폴링 주기는 5초이며, 지수 백오프로 최대 30초까지 늘립니다. 작업은 모델과 해상도에 따라 보통 30초~5분 내에 완료됩니다.

사용 방식 선택

동기식 /v1/video/generations비동기식 /v1/videos
적합한 용도일회성 스크립트, 노트북프로덕션, 모바일, 장시간 실행 작업
네트워크연결을 최대 9분 동안 유지몇 초 만에 제출하고 원하는 일정에 따라 상태를 조회하세요.
오류 복구응답을 잃으면 작업을 잃습니다.expires_at 이전에는 언제든지 ID를 다시 조회
동시성호출마다 서버 워커 하나 사용제출 후 즉시 연결 해제
응답 형식OpenAI /images/generations 형식OpenAI /videos 형식

응답 및 저장

응답은 OpenAI의 표준 형식인 data[].url입니다. URL은 영구적인 files.kunavo.com 링크입니다. Kunavo는 모든 결과를 자체 CDN에 보관하므로 원본 업스트림 URL과 달리 만료되지 않습니다. 모든 클립은 /app/assets에도 표시됩니다.

다음 단계