Tài liệu
Tạo video
Tạo video từ văn bản và từ hình ảnh với dòng mô hình Veo 3.1 của Google. API có hai dạng: endpoint đồng bộ một lần, chờ cho đến khi video sẵn sàng, và một cặp endpoint gửi tác vụ rồi thăm dò bất đồng bộ, dành cho khối lượng công việc môi trường sản xuất.
Endpoint: POST /v1/video/generations (đồng bộ, trình bày trước), và POST /v1/videos + GET /v1/videos/{id} (bất đồng bộ, được khuyến nghị cho môi trường sản xuất). Thời gian tạo dao động từ 30 giây đến vài phút tùy mô hình và thời lượng — với endpoint đồng bộ, hãy đặt thời gian chờ phía client đủ dài (600s là an toàn).
Hàm fetch tích hợp sẵn của Node ngừng chờ header phản hồi sau 300 giây, bất kể bạn đặt thời gian chờ là bao nhiêu: khi gọi từ Node, hãy dùng API bất đồng bộ, hoặc gọi hàm fetch từ gói undici với tùy chọn dispatcher: new Agent({ headersTimeout: 600_000 }).
Tạo video từ văn bản
Truyền prompt và chọn một mô hình. aspect_ratio là tùy chọn.
import os
import requests
API_KEY = os.environ["KUNAVO_API_KEY"]
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 (giây) đặt độ dài clip trên các mô hình tính phí theo giây: các mô hình Seedance và mô hình Wan 2.7. Các mô hình Veo bỏ qua tham số này; mỗi clip Veo dài 8 giây và được tính phí theo video.
# 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"])Chuyển hình ảnh thành video
Thêm image_url và Veo sẽ tạo chuyển động từ hình ảnh đó — mặc định, ảnh tĩnh trở thành khung hình đầu tiên của video.
# 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 chấp nhận URL https:// hoặc URI base64 nội tuyến data:. base64 sẽ được giải mã và tự động lưu trữ trên CDN của Kunavo trước khi mô hình chạy.Khung hình đầu, khung hình cuối và ảnh tham chiếu
image_mode điều khiển cách Veo sử dụng (các) hình ảnh. Truyền image_urls (một mảng) để gửi nhiều hơn một ảnh.
frame(mặc định) — một ảnh được dùng làm khung hình đầu; hai ảnh lần lượt làm khung hình đầu và cuối, Veo tạo phần chuyển tiếp giữa chúng.reference— tối đa ba ảnh được dùng làm ảnh tham chiếu phong cách và chủ thể. Chúng định hướng diện mạo nhưng không bao giờ xuất hiện thành khung hình.
# 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,
)Tải khung hình nguồn lên
Khi chỉ có tệp cục bộ, hãy tải tệp lên một lần qua POST /v1/files rồi dùng lại URL vĩnh viễn được trả về.
# 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,
)Tham số
| Tham số | Loại | Ghi chú |
|---|---|---|
model | string (bắt buộc) | Slug mô hình video từ /v1/models. |
prompt | string (bắt buộc) | Mô tả bằng văn bản về cảnh quay. |
image_url | string | Một hình ảnh nguồn cho tác vụ tạo video từ hình ảnh. URL hoặc URI data:. |
image_urls | string[] | Nhiều hình ảnh nguồn: hai khung hình hoặc ảnh tham chiếu. Được ưu tiên hơn image_url. |
image_mode | string | "frame" (mặc định — khung hình đầu/cuối) hoặc "reference" (ảnh tham chiếu phong cách). |
duration | int | Độ dài clip tính bằng giây trên các mô hình tính phí theo giây, là 5 khi không truyền: Seedance 2, Seedance 2 Fast và Seedance 2.0 Mini nhận 4–15, Seedance 2.5 nhận 4–30, Wan 2.7 nhận 2–15. Độ dài nằm ngoài phạm vi của một mô hình sẽ bị từ chối với lỗi 400. Veo bỏ qua tham số này: mỗi clip Veo dài 8 giây. |
aspect_ratio | string | ví dụ: "16:9", "9:16", "1:1". |
resolution | string | Khi mô hình cung cấp các mức — ví dụ: "720p", "1080p". |
input | object | Tham số mở rộng để bỏ qua giới hạn — xem Raw input bên dưới. |
GET /v1/models liệt kê giá trị của hai trong số các tham số ở trên mà từng mô hình chấp nhận. Trường kunavo.tiers cung cấp mọi cấp độ resolution cùng giá niêm yết của từng cấp độ, và cấp độ được áp dụng cho yêu cầu nếu yêu cầu không chỉ định cấp độ. Trường kunavo.duration_seconds cung cấp phạm vi duration của một mô hình được tính phí theo giây.
Một hình ảnh mà mô hình không nhận, hoặc một giá trị resolution không thuộc các cấp độ của mô hình, sẽ bị từ chối với lỗi 400 trước khi bất kỳ khoản phí nào được tính, và error.param của lỗi đó nêu tên trường tương ứng.
capabilities của một mô hình trong GET /v1/models liệt kê những hình ảnh mà mô hình đó nhận:
image-to-video— một ảnh, dùng làm khung hình đầu.first-last-frame— hai ảnh, dùng làm khung hình đầu và cuối.reference-image— ảnh tham chiếu, được gửi vớiimage_modeđặt thànhreference.max_reference_imageslà số ảnh tham chiếu tối đa mà một yêu cầu có thể gửi.
Tham số mở rộng để truyền dữ liệu thô
Trên các mô hình tính phí theo giây, input được gửi nguyên văn lên thượng nguồn, thay cho phần đầu vào mà bộ chuyển đổi của chúng tôi sẽ tạo. Các mô hình Veo bỏ qua tham số này.
Các trường quyết định giá là ngoại lệ: resolution luôn được gửi dưới dạng một trong các cấp độ của mô hình (cấp độ mặc định nếu trường này không được cung cấp hoặc giá trị không phải một trong các cấp độ đó), còn duration phải là số giây nguyên nằm trong phạm vi của mô hình (mọi giá trị khác đều bị từ chối với lỗi 400; 5 được gửi nếu trường này không được cung cấp). Khi input được thiết lập, resolution và duration của chính yêu cầu sẽ không được đọc.
Các mô hình video
| Slug | Nhà cung cấp | Ghi chú |
|---|---|---|
veo-3 | Veo 3.1 Fast — nhanh hơn và rẻ hơn Quality, âm thanh tích hợp sẵn. | |
veo-3-quality | Veo 3.1 Quality — độ trung thực cao nhất. | |
veo-3-lite | Veo 3.1 Lite — mức tiết kiệm cho bản xem trước. | |
seedance-2-5 | ByteDance | Seedance 2.5 — video tối đa 30s, tham chiếu đa phương thức, tính phí theo giây. |
seedance-2 | ByteDance | Seedance 2 — tính nhất quán giữa nhiều cảnh quay, độ phân giải tối đa 1080p, tính phí theo giây. |
seedance-2-fast | ByteDance | Seedance 2 Fast — mức tiết kiệm, độ phân giải tối đa 720p, tính phí theo giây. |
seedance-2-mini | ByteDance | Seedance 2.0 Mini — mức giá thấp nhất, chỉ 480p/720p, dành cho bản nháp và khối lượng lớn. |
wan-2-7 | Alibaba | Wan 2.7 — tạo video điện ảnh từ văn bản, tính phí theo giây. |
Luôn kiểm tra /models để xem danh sách hiện tại và giá của từng mô hình.
Độ trễ & thời gian chờ
- Kunavo thăm dò tác vụ ở nhà cung cấp thượng nguồn tối đa 540 giây trước khi trả về lỗi 504.
- Các mức Fast (Veo 3.1 Fast / Lite): thường mất 30–90s.
- Các mức Quality và thời lượng dài hơn: 2–5 phút.
- Đặt thời gian chờ của client HTTP ít nhất là 600s.
- Hàm
fetchtích hợp sẵn của Node ngừng chờ header phản hồi sau 300 giây, bất kể bạn đặt thời gian chờ là bao nhiêu: khi gọi từ Node, hãy dùng API bất đồng bộ, hoặc gọi hàmfetchtừ góiundicivới tùy chọndispatcher: new Agent({ headersTimeout: 600_000 }). - Với mạng không ổn định hoặc client di động, hãy ưu tiên API bất đồng bộ — yêu cầu gửi tác vụ trả về trong vài giây, sau đó bạn thăm dò để lấy kết quả.
API bất đồng bộ (gửi yêu cầu + thăm dò)
Endpoint: POST /v1/videos + GET /v1/videos/{id}. Đối tượng tác vụ mà chúng trả về sử dụng tên trường và giá trị trạng thái của đối tượng video của OpenAI, đồng thời bổ sung output chứa URL của đoạn clip. Yêu cầu là một phần thân JSON với các tham số ở trên.
Endpoint đồng bộ ở trên giữ kết nối HTTP mở tối đa chín phút — tiện cho các tập lệnh chạy một lần nhưng kém tin cậy trên thiết bị di động và kém hiệu quả trên máy chủ. Cặp endpoint bất đồng bộ trả về ngay một mã vid_*; bạn thăm dò GET /v1/videos/{id} cho đến khi status là completed hoặc failed. Cùng mô hình, cùng giá, cùng URL lưu trữ.
import os
import time
import requests
API_KEY = os.environ["KUNAVO_API_KEY"]
# 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: a repeat under the same key returns the original task
# rather than submitting again. A new task needs a new key.
"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"])Với OpenAI SDK, hãy gửi phần thân đó bằng client.post và thăm dò trạng thái bằng client.get, như bên dưới. client.videos.create riêng của SDK không hoạt động ở đây: phương thức này chỉ nhận các tham số của Sora và gửi chúng dưới dạng biểu mẫu multipart (trong Python SDK kể từ phiên bản 2.27.0); endpoint này từ chối yêu cầu multipart đó với mã 400.
import os
import time
from openai import OpenAI
client = OpenAI(
api_key=os.environ["KUNAVO_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"])Cấu trúc phản hồi
| Trường | Loại | Ghi chú |
|---|---|---|
id | string | ID tác vụ có tiền tố vid_. Ổn định qua các thay đổi ở nhà cung cấp thượng nguồn. |
object | string | "video". |
status | string | đang chờ | đang xử lý | đã hoàn tất | thất bại. |
model | string | Slug model bạn đã gửi. |
created_at | int | Thời điểm Unix tính bằng giây khi chúng tôi chấp nhận yêu cầu. |
completed_at | int | null | Thời điểm Unix tính bằng giây khi tác vụ kết thúc — null khi đang chờ. |
expires_at | int | Giây Unix, 30 ngày sau khi gửi: có thể truy vấn tác vụ ít nhất cho đến lúc đó. URL kết quả của tác vụ không hết hạn. |
progress | int | 0–100. Hiện chúng tôi báo cáo 0 cho đến khi tác vụ kết thúc, sau đó là 100. |
output | object | null | {url, urls[], duration_ |
error | object | null | {code, message} khi thất bại. |
Tiêu đề và quy ước
Idempotency-Key(tùy chọn, tối đa 128 ký tự) — gửi hai lần cùng một khóa trên cùng tài khoản sẽ trả về tác vụ ban đầu thay vì tạo tác vụ trùng lặp. Hữu ích cho các vòng lặp thử lại.- Một khóa idempotency ứng với một yêu cầu: khóa đã được dùng để bắt đầu một tác vụ trên endpoint khác, cho model khác, hoặc cho một yêu cầu có prompt khác hay tham số khác sẽ bị từ chối với lỗi 400. Khóa dài hơn 128 ký tự và khóa được gửi kèm một yêu cầu đồng bộ cũng vậy. URL hình ảnh không được so sánh: yêu cầu dùng URL được ký lại vẫn là cùng một yêu cầu.
POST /v1/videostrả về 202 Accepted khi gửi mới và 200 OK khi khóa idempotency khớp và phát lại kết quả trước đó.GET /v1/videos/{id}được giới hạn theo chủ sở hữu: truy vấn tác vụ thuộc tài khoản khác sẽ trả về 404 — chúng tôi không bao giờ xác nhận rằng một ID tồn tại với người khác.- Nhịp thăm dò được khuyến nghị: 5 s, với thời gian chờ lũy tiến tối đa 30 s. Tác vụ thường hoàn tất trong 30 s – 5 min tùy mô hình và độ phân giải.
Webhook
Gửi webhook_url (https) khi tạo tác vụ; ngay khi tác vụ kết thúc, Kunavo sẽ POST sự kiện video.completed / video.failed có chữ ký đến đó — gửi kèm cơ chế thử lại với thời gian chờ tăng dần. Trường data của sự kiện chính xác là nội dung phản hồi GET ở trên.
X-Kunavo-Webhook-Id— mã sự kiện ổn định, giống hệt nhau qua các lần thử lại (dùng để khử trùng lặp).X-Kunavo-Webhook-Timestamp— thời điểm tính chữ ký, tính bằng giây Unix.X-Kunavo-Webhook-Signature— HMAC-SHA256 của{timestamp}.{rawBody}, được tính bằngsha256=và khóa bí mật webhook của bạn.
Nếu webhook_url không phải là URL https, hoặc có chứa tên người dùng hay mật khẩu, yêu cầu sẽ bị từ chối với lỗi 400, và không có gì được tạo ra hay bị tính phí.
Khóa bí mật webhook của bạn nằm trong bảng điều khiển, tại Cài đặt → Webhooks. Khóa này bắt đầu bằng kwh_, và cùng một khóa bí mật được dùng để ký mọi sự kiện hình ảnh, video và nhạc của tài khoản bạn. Bạn có thể thay khóa tại đó; mọi sự kiện được gửi sau khi thay khóa, kể cả các lần thử lại, đều được ký bằng khóa bí mật mới.
Khi nào nên dùng model nào
| Đồng bộ /v1/ | Bất đồng bộ /v1/videos | |
|---|---|---|
| Phù hợp nhất cho | Tập lệnh dùng một lần, notebook | Môi trường sản xuất, thiết bị di động, tác vụ chạy lâu |
| Mạng | Giữ kết nối tối đa 9 min | Gửi trong vài giây; thăm dò theo lịch của bạn |
| Khôi phục sau sự cố | Mất phản hồi = mất tác vụ | Truy vấn lại ID bất kỳ lúc nào trước khi expires_at hết hạn |
| Tính đồng thời | Một worker máy chủ cho mỗi lệnh gọi | Gửi tác vụ và trả kết nối ngay lập tức |
| Cấu trúc phản hồi | Cấu trúc /images/ | Cấu trúc /videos của OpenAI |
Phản hồi và lưu trữ
Phản hồi có cấu trúc tiêu chuẩn của OpenAI — data[].url. URL là liên kết vĩnh viễn files.kunavo.com: Kunavo lưu trữ mọi kết quả trên CDN riêng, vì vậy URL không bao giờ hết hạn như URL thô của nhà cung cấp thượng nguồn. Mọi video cũng xuất hiện trong /app/assets.