Hình ảnh, video, nhạc và giọng nói
Khóa bạn dùng cho văn bản cũng tạo ra hình ảnh, video, nhạc và giọng nói, và chuyển đổi bản ghi âm thành văn bản, từ cùng một số dư. Chọn một mô hình trong bảng mô hình (hoặc ?type=image, ?type=music, ?type=audio); trang của mỗi mô hình hiển thị giá, loại và một yêu cầu hoạt động.
| Bạn muốn | Route | Ảnh nguồn đi vào |
|---|---|---|
| Một hình ảnh mới từ một prompt | POST /v1/images/generations |
(không có) |
| Một bức ảnh đã chỉnh sửa | POST /v1/images/edits |
image (hoặc image_url, input_images, images) |
| Một video từ một prompt | POST /v1/video/generations |
(không có) |
| Một video bắt đầu từ một bức ảnh | POST /v1/video/generations |
image_url (khung hình đầu tiên); end_image_url cho khung hình cuối cùng |
| Một video từ các ảnh tham chiếu | POST /v1/video/generations |
input_images với "role": "reference" |
| Một câu trả lời văn bản về một bức ảnh | POST /v1/chat/completions |
một phần image_url trong messages[].content |
| Nhạc | POST /v1/music/generations |
(không có) |
| Giọng nói từ văn bản | POST /v1/audio/speech |
(không có) |
| Văn bản từ một bản ghi âm | POST /v1/audio/transcriptions |
(không có; bản ghi âm đi vào file) |
Một ảnh nguồn là một liên kết https://, một URI data: (data:image/png;base64,iVBORw0…) hoặc base64 thuần túy của PNG, JPEG hoặc WebP, tối đa 8 cho mỗi yêu cầu. Các route hình ảnh cũng chấp nhận tải lên đa phần (xem bên dưới). Các liên kết phải là liên kết https:// công khai; các liên kết http:// bị từ chối. Một liên kết chuyển hướng (ví dụ https://picsum.photos/640/360) sẽ được theo dõi, tối đa 5 lần và chỉ đến các liên kết https:// công khai khác, và mô hình sẽ nhận được liên kết cuối cùng. Một liên kết không dẫn đến hình ảnh, hoặc chuyển hướng đến nơi chúng tôi không thể sử dụng, sẽ bị từ chối với 400 invalid_image_url trước khi bất kỳ thứ gì được giữ hoặc tính phí. Hình ảnh gửi nội tuyến làm cho yêu cầu lớn hơn: giữ nó dưới 10 MB, hoặc gửi liên kết.
Trong một tin nhắn trò chuyện (image_url trong messages[].content), một liên kết (https:// hoặc http://) được UberLLM mở và gửi đến mô hình dưới dạng URL data:, vì hầu hết các mô hình thị giác chỉ chấp nhận định dạng đó. Mỗi hình ảnh có thể lên đến 20 MB (40 MB cho mỗi yêu cầu), và các chuyển hướng được theo dõi tối đa 5 lần, chỉ đến các địa chỉ công khai. Các mô hình Gemini nhận liên kết nguyên trạng. Một liên kết không dẫn đến hình ảnh sẽ bị từ chối với 400 invalid_image_url, và không có gì được tính phí.
Tạo ảnh
Ảnh sẽ được trả về trong câu trả lời.
curl https://api.uberllm.dev/v1/images/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "venice/z-image-turbo", "prompt": "a red apple on a white table", "n": 1, "size": "1024x1024"}'
{ "created": 1792429247, "data": [{ "url": "https://api.uberllm.dev/v1/media/artifacts/<id>/0" }],
"usage": { "cost_usd": 0.0099, "max_cost_usd": 0.0109 } }
usage.cost_usd là chi phí của bức ảnh (cũng có trong tiêu đề X-UberLLM-Cost-USD). Trong những trường hợp hiếm hoi mà giá chưa được biết, nó là null. Bạn trả theo phí mà nhà cung cấp đã tính, không bao giờ nhiều hơn max_cost_usd, số tiền đã được giữ cho nó.
Theo mặc định, response_format là url, áp dụng cho cả /v1/images/generations và /v1/images/edits. Hãy gửi "response_format": "b64_json" để nhận ảnh trực tiếp trong câu trả lời. Khi mô hình trả về ảnh, UberLLM sẽ lưu nó dưới dạng tệp trong tài khoản của bạn trong 24 giờ và trả lời bằng liên kết của ảnh (https://api.uberllm.dev/v1/files/file_…/content), liên kết này cũng có thể dùng làm ảnh gốc để chỉnh sửa sau này. Tải xuống một url với cùng khóa:
curl -L -o image.png -H "Authorization: Bearer $UBERLLM_API_KEY" \
"https://api.uberllm.dev/v1/media/artifacts/<id>/0"
n là 1 đến 10.
Chỉnh sửa ảnh
Sử dụng một mô hình có chức năng chỉnh sửa (ID của nó thường kết thúc bằng -edit) và gửi ảnh gốc trong image:
curl https://api.uberllm.dev/v1/images/edits \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "google/nano-banana-pro-edit", "prompt": "make the sky a sunset",
"image": "https://example.com/skyline.png"}'
Bạn có thể gửi ảnh tương tự dưới các dạng sau:
"image": "data:image/png;base64,iVBORw0…""image_url": "https://…""input_images": ["https://…", "https://…"]: ảnh đầu tiên là ảnh cần chỉnh sửa, phần còn lại là ảnh tham chiếu. Một mục cũng có thể là{"url": "…", "role": "reference"}."images": [{"image_url": "https://…"}], định dạng mà các SDK của OpenAI gửi
Base64 thuần túy cũng hoạt động, và "input_image" được đọc là "image".
Hoặc tải tệp lên, tương tự như cách chỉnh sửa ảnh của OpenAI:
curl https://api.uberllm.dev/v1/images/edits \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F model=google/nano-banana-pro-edit -F prompt="make the sky a sunset" \
-F [email protected]
Yêu cầu chỉnh sửa không có ảnh gốc sẽ bị từ chối với 400 image_required. Mặt nạ (inpainting) không được hỗ trợ.
Tải ảnh lên một lần
Tải một hình ảnh lên /v1/files và sử dụng nó trong bao nhiêu yêu cầu tùy thích trong 24 giờ, thay vì gửi nó trong mỗi yêu cầu:
curl https://api.uberllm.dev/v1/files \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F [email protected]
{ "id": "file_3f9c…", "object": "file", "bytes": 482113, "content_type": "image/png",
"filename": "skyline.png", "created_at": 1792540800, "expires_at": 1792627200,
"url": "https://api.uberllm.dev/v1/files/file_3f9c…/content" }
Sau đó đặt ID, hoặc url, vào bất cứ đâu cần ảnh nguồn: "image": "file_3f9c…",
"image": {"file_id": "file_3f9c…"}, "image_url": "file_3f9c…", một mục nhập của
input_images, hoặc khung hình bắt đầu của video. Chỉ tài khoản của bạn mới có thể sử dụng các tệp của nó.
- PNG, JPEG, WebP, GIF, HEIC hoặc AVIF, tối đa 10 MB mỗi tệp, tối đa 500 tệp được giữ cho mỗi tài khoản cùng một lúc.
- Được giữ trong 24 giờ, sau đó bị xóa.
GET /v1/files/{id}mô tả một tệp,GET /v1/files/{id}/contenttải xuống tệp đó,DELETE /v1/files/{id}xóa tệp đó ngay bây giờ.
Tạo video
Một video mất một phút hoặc hơn, vì vậy đây là một công việc: bắt đầu, kiểm tra, tải xuống.
1. Bắt đầu
curl https://api.uberllm.dev/v1/video/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"model": "fal-ai/vidu/q3/text-to-video/turbo", "prompt": "a red ball bouncing on green grass",
"duration_seconds": 5, "models": ["fal-ai/kling-video/v3/standard/text-to-video"]}'
models là tùy chọn: các mô hình dự phòng được thử theo thứ tự chỉ khi mô hình đầu tiên không có nhà cung cấp miễn phí vào lúc này, để một thời điểm bận rộn không làm hỏng yêu cầu của bạn (xem Mô hình dự phòng). Video trên mất khoảng một phút và có giá khoảng $0.33.
Để bắt đầu từ một bức ảnh, hãy sử dụng mô hình image-to-video và thêm image_url:
-d '{"model": "bytedance/seedance-2-0-image-to-video", "prompt": "slow push-in as the waves roll",
"image_url": "https://example.com/first-frame.png", "duration_seconds": 5}'
Một mô hình pha trộn hai bức ảnh cũng lấy end_image_url (khung hình cuối cùng). Một mô hình image-to-video hoặc reference-to-video không thể tạo video chỉ từ văn bản sẽ bị từ chối với 400 image_required khi yêu cầu không có ảnh, trước khi có bất kỳ khoản phí nào. Một mô hình reference-to-video lấy các bức ảnh trong input_images:
-d '{"model": "pixverse/pixverse-c1-reference-to-video", "prompt": "the cat walks across the room",
"input_images": [{"url": "https://example.com/cat.png", "role": "reference"}],
"aspect_ratio": "16:9", "duration_seconds": 5}'
Các trường khác, nơi mô hình cung cấp chúng: resolution (480p, 720p, 1080p…), aspect_ratio (16:9, 9:16, 1:1…) và audio (true / false; một mô hình không có cài đặt âm thanh sẽ không được gửi cài đặt đó và tạo clip như bình thường). Một mô hình reference-to-video cần một hình dạng, vì vậy khi bạn bỏ qua aspect_ratio, nó sẽ được gửi dưới dạng 16:9 (hoặc hình dạng đầu tiên của mô hình nếu nó không tạo 16:9); schema của mô hình hiển thị mặc định đó. Các lựa chọn của mỗi mô hình được liệt kê bởi GET /v1/models/<model id> (xem Tùy chọn của từng mô hình).
Mỗi mô hình chỉ tạo ra các độ dài clip, độ phân giải và hình dạng nhất định. Một yêu cầu cho một loại mà nó không tạo ra sẽ bị từ chối với một thông báo liệt kê những loại nó có thể tạo, trước khi có bất kỳ khoản phí nào.
HTTP 202:
{
"id": "6f1c…",
"object": "media.job",
"kind": "video",
"status": "queued",
"model": "fal-ai/vidu/q3/text-to-video/turbo",
"estimated_cost_usd": 0.32725,
"estimated_cost_usdc": "327250",
"max_cost_usd": 0.359975,
"max_cost_usdc": "359975",
"poll_url": "/v1/video/generations/6f1c…",
"cancel_url": "/v1/video/generations/6f1c…"
}
model là mô hình đã nhận công việc (một bản dự phòng từ models khi mô hình đầu tiên không thể). Chi phí kết thúc bằng _usdc là phần triệu của một đô la (327250 = $0.33). estimated_cost_usd là giá niêm yết cho những gì bạn yêu cầu: cùng một số validate và POST /v1/quote trả lời như cost_usd. Đó là giá hiện tại của mô hình nhân với số giây (ở độ phân giải yêu cầu), số ảnh hoặc các đơn vị khác. Công việc được tính phí theo những gì nhà cung cấp đã tính, có thể nhiều hơn hoặc ít hơn. max_cost_usd là số tiền được giữ từ số dư của bạn cho công việc: con số này không đổi trong khi nó chạy và sau khi kết thúc, và là số tiền tối đa công việc được tính phí. Một mô hình video có giá mỗi second được tính phí mỗi giây của clip; một mô hình có giá mỗi job thì chi phí đó cho mỗi video.
2. Kiểm tra mỗi 5–10 giây:
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/video/generations/<job id>
HTTP 202 khi công việc đang chạy, HTTP 200 khi nó kết thúc:
{
"id": "6f1c…",
"status": "succeeded",
"results": [{ "artifact_index": 0, "url": "https://api.uberllm.dev/v1/media/artifacts/6f1c…/0",
"content_type": "video/mp4", "duration_seconds": 5 }],
"usage": { "cost_usdc": "40000", "cost_usd": 0.04 }
}
Mô hình báo cáo phí chính xác của công việc một chút sau khi tệp sẵn sàng, thường trong vòng 30 giây. Cho đến lúc đó, một công việc succeeded hiển thị "usage": { "cost_usd": null, "cost_pending": true }; hãy hỏi lại vài giây sau. Nếu phí chưa đến trong vòng 30 phút, công việc sẽ được tính phí theo giá niêm yết (estimated_cost_usd) và usage.cost_note sẽ thông báo điều đó.
3. Tải xuống
curl -L -o video.mp4 -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/media/artifacts/<job id>/0
Yêu cầu dừng một công việc bạn không còn cần: DELETE /v1/video/generations/<job id>. Chúng tôi yêu cầu nhà cung cấp dừng nó; một công việc đã được tạo sẽ được tính phí như bình thường, và một công việc nó dừng sẽ kết thúc canceled và không tốn phí.
Mô hình video Fal
Các mô hình có ID bắt đầu bằng fal-ai/ chạy trên Fal, với giá thấp hơn giá của Fal:
bạn trả giá của Fal trừ đi chiết khấu của người bán Fal rẻ nhất trên thị trường hiện tại (giảm 15% cho 30 tháng 10, 2026; giảm 25% bất cứ khi nào người bán đó đang bán). Giá được cố định dựa trên yêu cầu của bạn — số giây × tỷ lệ cho độ phân giải, và liệu clip có âm thanh hay không — vì vậy chi phí công việc được biết ngay khi bắt đầu và estimated_cost_usd chính xác là số tiền bạn phải trả. Một công việc thất bại không tốn phí. Việc dừng một công việc là nỗ lực tốt nhất: nếu Fal đã tạo clip, bạn sẽ bị tính phí.
curl https://api.uberllm.dev/v1/video/generations \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "fal-ai/wan/v2.7/text-to-video", "prompt": "a woman twirls at a garden party at night",
"duration_seconds": 15, "resolution": "720p", "aspect_ratio": "9:16"}'
Giá của Fal mỗi giây (giá của bạn là giá này trừ đi chiết khấu trực tiếp; trang của mỗi mô hình, GET /v1/models và POST /v1/quote hiển thị giá chính xác hiện tại):
| Mô hình | Độ dài (s) | Giá của Fal mỗi giây, từ |
|---|---|---|
fal-ai/wan/v2.7/text-to-video, …/image-to-video |
2–15 | 720p $0.10 · 1080p $0.15 |
fal-ai/kling-video/v3/standard/text-to-video, …/image-to-video |
3–15 | $0.084 · có âm thanh $0.126 |
fal-ai/kling-video/v3/pro/text-to-video, …/image-to-video |
3–15 | $0.112 · có âm thanh $0.168 |
fal-ai/kling-video/o3/standard/text-to-video, …/image-to-video |
3–15 | $0.084 · có âm thanh $0.112 |
fal-ai/kling-video/v2.6/pro/text-to-video, …/image-to-video |
5, 10 | $0.07 · có âm thanh $0.14 |
fal-ai/veo3.1/fast, fal-ai/veo3.1/fast/image-to-video |
4, 6, 8 | 720p/1080p $0.10 · có âm thanh $0.15 · 4k $0.30 |
fal-ai/veo3.1, fal-ai/veo3.1/image-to-video |
4, 6, 8 | 720p/1080p $0.20 · có âm thanh $0.40 · 4k $0.40 |
fal-ai/veo3.1/lite |
4, 6, 8 | 720p $0.03 · có âm thanh $0.05 · 1080p $0.05 |
fal-ai/ltx-2.3/text-to-video/fast, …/image-to-video/fast |
6, 8, 10 | 1080p $0.06 · 1440p $0.12 · 2160p $0.24 |
fal-ai/ltx-2.3/text-to-video |
6, 8, 10 | 1080p $0.08 |
fal-ai/minimax/hailuo-02/standard/text-to-video, …/image-to-video |
6, 10 | 768P $0.045 · 512P (ảnh) $0.017 |
fal-ai/vidu/q3/text-to-video/turbo, …/image-to-video/turbo |
1–16 | 360p/540p $0.035 · 720p/1080p $0.077 |
fal-ai/vidu/q3/text-to-video, …/image-to-video |
1–16 | 360p/540p $0.07 · 720p/1080p $0.154 |
Mỗi mức giá là của riêng Fal; chiết khấu được áp dụng khi công việc bắt đầu. Nếu người bán rẻ nhất từ chối một công việc, một người bán đắt hơn sẽ thực hiện nó và công việc được tính phí theo giá của người bán đó, không bao giờ quá estimated_cost_usd trong phản hồi.
Một số mô hình tốn của chúng tôi ít hơn so với mức chiết khấu của người bán. Cứ sau 6 giờ chúng tôi so sánh những gì thị trường đã tính phí chúng tôi cho mỗi mô hình trong 7 ngày qua với giá của Fal cho cùng các công việc đó. Một mô hình có ít nhất 20 công việc trong thời gian đó sau đó được định giá theo tỷ lệ thực tế đó cộng thêm 5%, khi mức giá đó thấp hơn. Trang mô hình, /v1/models và hóa đơn đều sử dụng cùng một mức giá. Nếu con số đó đã quá 3 ngày, chiết khấu của người bán sẽ được áp dụng lại.
Các trường là của chúng tôi: duration_seconds, resolution, aspect_ratio, audio và image_url (hoặc input_images). Cách viết của Fal (duration, generate_audio, start_image_url) cũng hoạt động. Kling, Veo và Kling 2.6 thêm âm thanh trừ khi bạn gửi "audio": false.
Trạng thái công việc
status |
HTTP | Ý nghĩa |
|---|---|---|
queued |
202 | Đã chấp nhận, đang chờ một mô hình bắt đầu thực hiện |
running |
202 | Đang được thực hiện; progress chuyển từ 0 sang 1 khi mô hình báo cáo |
succeeded |
200 | Hoàn thành; tải xuống results[].url |
failed |
200 | Chưa thực hiện. error.message cho biết lý do; error.retryable cho biết liệu có thể thử lại được không |
canceled |
200 | Đã dừng trước khi được thực hiện |
expired |
200 | Không hoàn thành kịp thời gian |
Đây là sáu giá trị duy nhất. failed, canceled và expired không tốn phí. Một
DELETE là yêu cầu dừng, không phải lời hứa: một công việc mà nhà cung cấp vẫn hoàn thành sẽ kết thúc succeeded và được tính phí.
Khi bận, chúng tôi sẽ tự động thử lại cho bạn. Khi không có nhà cung cấp nào rảnh để tạo video của bạn,
hoặc một nhà cung cấp nào đó đang quá bận, UberLLM sẽ tự động bắt đầu lại công việc, tối đa thêm hai lần nữa
trong vòng 10 phút. Nó giữ nguyên job id và mức chi phí tối đa.
Công việc chỉ mất thêm một chút thời gian. Bạn chỉ thấy failed khi mọi lần thử đều thất bại, và một
công việc thất bại không tốn phí.
Chờ đợi. Gửi callback_url và chúng tôi sẽ thông báo cho bạn khi công việc kết thúc (xem
Callbacks), hoặc hỏi URL thăm dò mỗi 5–10 giây. Hầu hết các video mất
1–5 phút; một số công việc dài hoặc 4K sẽ mất nhiều thời gian hơn. Bạn không cần phải liên tục hỏi về
việc thanh toán: một công việc không ai kiểm tra vẫn sẽ được UberLLM hoàn thành và tính phí (hoặc
hoàn tiền), và hiển thị trong
Dashboard → Activity.
Các Callback
Thêm callback_url vào một tác vụ video hoặc nhạc: một liên kết https:// trên một máy chủ công cộng.
Khi tác vụ kết thúc hoàn toàn, UberLLM sẽ gửi một POST đến đó với cùng một JSON mà GET trên tác vụ trả về.
{ "model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5,
"callback_url": "https://your-app.example/uberllm/jobs" }
- Khi nào. Một lần, khi tác vụ đã kết thúc và hóa đơn của nó là cuối cùng:
succeededvớiusage.cost_usdđược đặt (không bao giờcost_pending), hoặcfailed,canceledhoặcexpired(chi phí 0). Nó không được gửi lại khi chi phí đến, vì nó chỉ được gửi sau đó. Vớioutput_upload_urlnữa, callback sẽ đến sau khi quá trình tải lên hoàn tất, vì vậyoutput_upload.statusđã làdeliveredhoặcfailed. - Headers.
Content-Type: application/json,UberLLM-Event: job.succeeded(hoặcjob.failed,job.canceled,job.expired),UberLLM-Event-Id: <job id>:<status>vàUberLLM-Signature: t=<unix seconds>,v1=<hex>. - Thử lại. Trả lời bằng bất kỳ 2xx nào trong vòng 15 giây. Bất kỳ câu trả lời nào khác, hoặc không có câu trả lời, sẽ được thử lại sau 30 giây, 2 phút, 10 phút, 30 phút và 2 giờ, sau đó sẽ bị bỏ qua. Bạn vẫn có thể thăm dò trạng thái tác vụ bất cứ lúc nào.
- Lặp lại. Một tin nhắn có thể đến nhiều hơn một lần (ví dụ khi câu trả lời của bạn bị mất). ID sự kiện vẫn giữ nguyên, vì vậy hãy bỏ qua những cái bạn đã xử lý.
- Trạng thái. Tác vụ hiển thị kết quả:
"callback": { "status": "delivered", "attempts": 1, "http_status": 200, "delivered_at": 1792540990 }.statuslàpending,deliveredhoặcfailed(vớierrorbằng lời thường). - Liên kết phải là
https://trên một máy chủ công cộng, không có tên người dùng hoặc mật khẩu trong đó. Nó không bao giờ được hiển thị lại và bị xóa ngay sau khi callback kết thúc.webhook_urlđược đọc là cùng một trường. Hình ảnh và giọng nói không sử dụng nó: chúng được trả về trong chính câu trả lời.
Kiểm tra chữ ký
Mọi tin nhắn đều được ký bằng webhook secret của tài khoản của bạn. Tìm nó trong Dashboard → API keys → Webhook signing secret; nó được tạo lần đầu tiên bạn mở nó, và Replace secret sẽ thay thế nó ngay lập tức.
v1 là hex HMAC-SHA256 của <t>.<raw body>, được khóa bằng toàn bộ secret (whsec_…). Tính toán nó trên các byte thô bạn nhận được (trước khi phân tích cú pháp JSON), so sánh trong thời gian không đổi, và từ chối một t đã quá 5 phút.
Node.js (Express):
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.UBERLLM_WEBHOOK_SECRET; // whsec_…
app.post("/uberllm/jobs", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("UberLLM-Signature") || "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const expected = crypto.createHmac("sha256", SECRET)
.update(`${parts.t}.`).update(req.body).digest("hex");
const ok = parts.v1 && parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected)) &&
Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
if (!ok) return res.status(400).send("bad signature");
const job = JSON.parse(req.body);
// Drop a repeat: req.get("UberLLM-Event-Id") is the same each time.
console.log(job.id, job.status, job.usage?.cost_usd);
res.sendStatus(204);
});
Python (Flask):
import hashlib, hmac, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["UBERLLM_WEBHOOK_SECRET"].encode() # whsec_…
@app.post("/uberllm/jobs")
def uberllm_job():
raw = request.get_data() # the raw bytes, before any JSON parsing
parts = dict(p.split("=", 1) for p in request.headers.get("UberLLM-Signature", "").split(",") if "=" in p)
expected = hmac.new(SECRET, parts.get("t", "").encode() + b"." + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(parts.get("v1", ""), expected) or abs(time.time() - int(parts.get("t", "0"))) > 300:
abort(400)
job = request.get_json()
# Drop a repeat: request.headers["UberLLM-Event-Id"] is the same each time.
print(job["id"], job["status"], job.get("usage", {}).get("cost_usd"))
return "", 204
Cảnh báo đến một webhook
Các email cảnh báo cũng có thể được gửi đến một webhook: đặt một liên kết dưới Dashboard → Credits → For developers: also send alerts to a webhook, hoặc PUT /api/v1/billing/alerts {"alerts_webhook_url": "https://…"} (null sẽ tắt nó). Các tin nhắn được ký, thử lại và nhận dạng theo cùng một cách như các callback. Nội dung là:
{ "id": "evt_…", "object": "event", "type": "balance.low", "created": 1792540990,
"data": { "balance_usd": 4.2, "threshold_usd": 5, "message": "Your balance is $4.20, below the $5.00 you set. Requests stop once it runs out.",
"add_credits_url": "https://uberllm.dev/dashboard/credits" } }
balance.low: số dư đã giảm xuống dưới mức bạn đặt cho email cảnh báo số dư thấp. Được gửi một lần mỗi khi nó giảm xuống dưới mức đó; không có gì được gửi cho đến khi bạn đặt một mức.hold.not_released: tiền dành cho một tác vụ vẫn bị giữ hơn 15 phút sau khi tác vụ kết thúc.data.jobsliệt kê chúng (id,kind,model,ended_at,held_usd) vàdata.held_usdlà tổng số. Số tiền vẫn là của bạn và đội ngũ của chúng tôi đã được thông báo.
Tệp được lưu trữ trong bao lâu
Hãy tải kết quả xuống ngay sau khi được tạo:
- Tệp video và nhạc được lưu trữ trong khoảng 3 giờ sau khi công việc kết thúc.
- Liên kết hình ảnh đến
/v1/media/artifacts/…được lưu trữ trong khoảng 15 phút; liên kết hình ảnh đến/v1/files/…trong 24 giờ. Yêu cầu"response_format": "b64_json"để nhận hình ảnh trong câu trả lời và tự lưu trữ. - Hình ảnh bạn tải lên
/v1/filesđược lưu trữ trong 24 giờ.
Sau thời gian đó, đường dẫn tải xuống sẽ trả về 404 artifact_expired.
Gửi kết quả đến bộ nhớ của riêng bạn
Thêm output_upload_url vào một công việc video hoặc nhạc: một liên kết https:// chấp nhận HTTP PUT, chẳng hạn như liên kết tải lên S3, R2 đã được ký trước hoặc Google Cloud Storage. Khi công việc thành công, UberLLM sẽ tải tệp lên đó với loại nội dung của nó. Đối với một công việc tạo ra nhiều tệp, hãy gửi output_upload_urls, mỗi tệp một liên kết theo thứ tự (tối đa 4).
{ "model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5,
"output_upload_url": "https://my-bucket.s3.amazonaws.com/ball.mp4?X-Amz-Signature=…" }
Trạng thái của công việc sau đó sẽ có output_upload:
"output_upload": { "status": "delivered", "attempts": 1, "delivered_at": 1792540990,
"files": [{ "artifact_index": 0, "http_status": 200, "bytes": 5242880 }] }
statuslàpendingcho đến khi quá trình tải lên hoàn tất, sau đó làdeliveredhoặcfailed(vớierrorbằng lời thường).- Một lần tải lên thất bại sẽ được thử lại sau 30 giây, 2, 10 và 30 phút, sau đó được đánh dấu
failed; tệp vẫn có thể được tải xuống từresults[].urltrong khi nó được lưu trữ. Hãy đảm bảo liên kết có hiệu lực ít nhất một giờ. - Liên kết phải là
https://trên một máy chủ công cộng, không có tên người dùng hoặc mật khẩu. Nó không bao giờ được hiển thị lại và sẽ bị xóa ngay sau khi quá trình tải lên kết thúc. - Hình ảnh không sử dụng nó: một hình ảnh sẽ được trả về trong chính câu trả lời.
Âm nhạc
Ba bước tương tự tại /v1/music/generations. curl -OJ lưu bản nhạc dưới tên tệp mà chúng ta gửi.
Giọng nói
Văn bản được đưa vào, và một tệp âm thanh sẽ được trả về làm câu trả lời.
curl https://api.uberllm.dev/v1/audio/speech \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "x-ai/tts-xai-v1", "input": "Hello from UberLLM."}' \
-o speech.mp3
Bạn cũng có thể gửi voice, response_format (ví dụ mp3 hoặc wav) và speed.
Mỗi mô hình có các giọng nói riêng (GET /v1/models/{id} liệt kê chúng). Với
best-price:speech hoặc fastest:speech, bạn không biết trước mô hình nào được sử dụng,
vì vậy giọng nói sẽ được điều chỉnh cho phù hợp: giọng nói mà mô hình có sẽ được giữ lại, tên của OpenAI sẽ được ánh xạ tới
giọng nói phù hợp của mô hình nếu có (alloy → af_alloy), và bất kỳ giọng nói nào khác, hoặc
không có giọng nói nào, sẽ nhận giọng nói đầu tiên của mô hình. Khi bạn chỉ định một mô hình, giọng nói của bạn sẽ được gửi nguyên trạng.
Nó được tính phí theo mỗi 1K ký tự input đã bắt đầu. Câu trả lời là tệp âm thanh;
tiêu đề X-UberLLM-Cost-USD của nó cho biết chi phí là bao nhiêu, và X-Request-Id là ID của yêu cầu
như được liệt kê trong Hoạt động. "validate": true, max_cost, metadata, models và
provider.max_price hoạt động tương tự như trên hình ảnh (xem Bạn phải trả bao nhiêu).
Chuyển bản ghi âm thành văn bản
Gửi bản ghi âm dưới dạng biểu mẫu với file và model:
curl https://api.uberllm.dev/v1/audio/transcriptions \
-H "Authorization: Bearer $UBERLLM_API_KEY" \
-F model=venice/whisper-large-v3 \
-F [email protected]
{ "text": "Hello from UberLLM.", "duration": 4.2,
"usage": { "type": "duration", "seconds": 5, "cost_usd": 0.00055, "max_cost_usd": 0.00726 } }
usage.cost_usd là chi phí (cũng có trong tiêu đề X-UberLLM-Cost-USD, nơi duy nhất để trả lời text, srt và vtt). Các trường riêng của chúng tôi cũng được đưa vào biểu mẫu và không bao giờ được gửi đến mô hình: -F max_cost=0.10, -F "metadata[project]=podcast", -F validate=true.
Bạn cũng có thể gửi language, prompt, temperature và response_format: json (mặc định), hoặc text, srt hoặc vtt để nhận lại văn bản thuần túy. Nó được tính phí theo mỗi phút âm thanh. Tệp có thể có dung lượng lên đến 40 MB. Định dạng (mp3, wav, ogg, flac, m4a/mp4, webm, aac) được đọc từ chính bản ghi âm, chứ không phải tên tệp của nó, vì vậy một bản tải lên có tên tmp123.out vẫn hoạt động.
Với OpenAI SDK
from openai import OpenAI
client = OpenAI(base_url="https://api.uberllm.dev/v1", api_key="<your UberLLM key>")
speech = client.audio.speech.create(model="x-ai/tts-xai-v1", voice="eve", input="Hello from UberLLM.")
speech.write_to_file("speech.mp3")
with open("speech.mp3", "rb") as f:
text = client.audio.transcriptions.create(model="venice/whisper-large-v3", file=f)
print(text.text)
Bạn thanh toán gì
- Giá của sản phẩm được tạo ra: là phí nhà cung cấp tính, không có phí UberLLM. Một câu trả lời hình ảnh hoặc bản ghi và một công việc hoàn thành sẽ có giá
usage.cost_usd(đô la Mỹ); mọi câu trả lời tạo ra sản phẩm cũng sẽ có giá đó trong header phản hồiX-UberLLM-Cost-USD(đối với giọng nói, header là nơi duy nhất, vì câu trả lời là tệp âm thanh). Nó hiển thị trong Dashboard → Activity. Phần còn lại của khoản giữ sẽ được hoàn lại. - Không tính phí cho công việc
failed, bịcanceledhoặcexpired, hoặc cho yêu cầu hình ảnh, giọng nói hoặc bản ghi bị lỗi. - Nhà cung cấp rẻ nhất tạo ra chính xác những gì bạn yêu cầu. Nhiều mô hình hình ảnh và video có nhiều hơn một nhà cung cấp; mỗi yêu cầu sẽ được gửi đến nhà cung cấp rẻ nhất có thể tạo ra sản phẩm với cài đặt của bạn, và đến một nhà cung cấp khác nếu nhà cung cấp đó không thể xử lý. Danh sách mô hình và mỗi trang mô hình hiển thị giá của nhà cung cấp rẻ nhất hiện đang hoạt động.
- Xem số dư của bạn và số tiền đang được giữ với
GET /v1/balance(bên dưới).
Kiểm tra giá trước khi chi tiêu
Thêm "validate": true vào bất kỳ yêu cầu hình ảnh, video, âm nhạc hoặc giọng nói nào (đối với bản ghi, gửi validate=true dưới dạng trường biểu mẫu cùng với bản ghi). Yêu cầu được kiểm tra như thể là thật (mô hình, tùy chọn, hình ảnh nguồn), không có gì được tạo ra và không có gì bị tính phí, và HTTP 200 cho biết chi phí của nó theo giá niêm yết (cost_usd, giá hiển thị trên trang của mô hình; bạn trả phí mà nhà cung cấp tính, có thể khác) và số tiền được giữ trong khi nó chạy (max_cost_usd, số tiền tối đa được tính):
{ "object": "quote", "model": "bytedance/seedance-2-0-image-to-video", "kind": "video",
"valid": true, "cost_usd": 0.2117, "max_cost_usd": 0.4235, "unit": "second", "units": 5, "duration_seconds": 5,
"note": "Nothing was charged. …" }
Nếu nhà cung cấp của mô hình cần một cài đặt mà bạn đã bỏ qua (một mô hình tham chiếu video cần aspect_ratio), giá trị mặc định được gửi cùng sẽ hiển thị trên schema của mô hình và trong báo giá là defaults_applied, ví dụ "defaults_applied": {"aspect_ratio": "16:9"}.
Một yêu cầu sẽ bị từ chối thì cũng bị từ chối theo cách tương tự, kèm theo lý do.
Giữ giá trong 15 phút
POST /v1/quote nhận cùng một body với yêu cầu hình ảnh, video, âm nhạc hoặc giọng nói và trả về chi phí niêm yết (cost_usd), số tiền được giữ trong khi nó chạy (max_cost_usd, số tiền tối đa được tính) và một quote_id (đối với bản ghi, gửi model và duration_seconds; bản ghi tự nó không cần quote_id, hãy dùng max_cost để giới hạn):
curl https://api.uberllm.dev/v1/quote \
-H "Authorization: Bearer $UBERLLM_API_KEY" -H "Content-Type: application/json" \
-d '{"model": "kling/kling-o3", "prompt": "a red ball bouncing", "duration_seconds": 5}'
{ "object": "quote", "id": "6f1c…", "quote_id": "6f1c…", "model": "kling/kling-o3",
"kind": "video", "cost_usd": 0.225, "max_cost_usd": 0.495, "unit": "job", "units": 1,
"expires_at": 1792541700, "note": "Nothing was charged. …" }
Gửi cùng một yêu cầu với "quote_id": "6f1c…" trong vòng 15 phút và nó sẽ được tính phí theo những gì nhà cung cấp đã tính, tối đa max_cost_usd; nếu số tiền phải giữ khi nó bắt đầu vượt quá max_cost_usd, nó sẽ bị hủy mà không tính phí. Không có gì bị tính phí hoặc giữ cho báo giá đó.
- Một báo giá bắt đầu một yêu cầu. Sử dụng lại nó sẽ trả về
409 quote_used; một công việc chưa bao giờ đến được mô hình sẽ hoàn lại báo giá. - Yêu cầu phải hỏi cùng một thứ: cùng mô hình và cùng cài đặt (prompt, kích thước, độ dài clip, hình ảnh nguồn…). Bất cứ điều gì khác sẽ bị từ chối với
400 quote_mismatch.max_cost,metadatavàoutput_upload_urlcó thể khác. - Sau 15 phút nó trả về
400 quote_expired. Các mô hình trò chuyện được tính phí theo token và không có báo giá: hãy giới hạn chúng bằngprovider.max_price.
Mô hình dự phòng và giới hạn giá
"models": ["model-b", "model-c"] liệt kê các mô hình để thử theo thứ tự khi mô hình đầu tiên không thể được phục vụ ngay bây giờ (no_available_provider) hoặc vượt quá provider.max_price của bạn. Bất kỳ từ chối nào khác sẽ được trả lời ngay lập tức. model của câu trả lời đặt tên cho mô hình đã tạo ra nó (một câu trả lời giọng nói là chính tệp âm thanh: Activity hiển thị mô hình của nó). Một yêu cầu với quote_id không cần models, và một bản ghi cũng không cần cả hai.
"provider": {"max_price": 0.05} là chi phí tối đa mà một đơn vị (đơn vị tính giá của mô hình unit: hình ảnh, giây, megapixel, phút, 1K ký tự hoặc yêu cầu) có thể tốn, tính bằng đô la Mỹ. Một mô hình vượt quá giới hạn này sẽ bị từ chối với 400 max_price_exceeded, và yêu cầu sẽ không bao giờ bị tính phí vượt quá max_price lần đơn vị của nó. Các tùy chọn provider khác bị từ chối với 400 unsupported_routing_option, vì lựa chọn nhà cung cấp cho các yêu cầu phương tiện không thể được điều hướng theo từng yêu cầu.
"model": "best-price:image" (hoặc image-edit, text-to-video, image-to-video, music, speech, transcription) chọn mô hình trực tiếp rẻ nhất cho công việc; fastest: chọn mô hình nhanh nhất được đo lường. Xem Model aliases.
Thẻ
"metadata": {"project": "spring-ads"} (tối đa 16 giá trị văn bản) được lưu trữ cùng với công việc, trả về trong trạng thái của nó, hiển thị trong Activity và trong xuất CSV, và không bao giờ được gửi đến mô hình. Đối với bản ghi, gửi chúng dưới dạng trường biểu mẫu: -F "metadata[project]=spring-ads". Xem Tags.
Đặt giới hạn tối đa
Gửi "max_cost" (đô la Mỹ, ví dụ 0.50) cùng với bất kỳ yêu cầu hình ảnh, video, âm nhạc hoặc giọng nói nào (một trường biểu mẫu trên bản ghi). Nếu nó có thể tốn nhiều hơn mức đó, nó sẽ bị từ chối với 400 max_cost_too_low và không có gì bị tính phí. Đối với công việc video hoặc âm nhạc, giới hạn tối đa chính xác được đặt khi công việc bắt đầu; nếu sau đó nó vượt quá max_cost của bạn, công việc sẽ bị hủy mà không tính phí. Với "validate": true, báo giá thêm within_max_cost.
Thử lại mà không phải trả tiền hai lần
Gửi một header Idempotency-Key (bất kỳ chuỗi duy nhất nào tối đa 255 ký tự, chẳng hạn như UUID) khi bạn bắt đầu một công việc video hoặc âm nhạc. Nếu kết nối của bạn bị gián đoạn và bạn gửi lại cùng một yêu cầu với cùng một key trong vòng 24 giờ, bạn sẽ nhận lại cùng một công việc thay vì một công việc thứ hai. Cùng một key với một yêu cầu khác sẽ bị từ chối với 409 idempotency_key_reused. Các yêu cầu hình ảnh, giọng nói và bản ghi không cần key: một yêu cầu bị lỗi sẽ không bị tính phí, vì vậy hãy gửi lại.
Số dư của bạn
curl -H "Authorization: Bearer $UBERLLM_API_KEY" https://api.uberllm.dev/v1/balance
{ "balance_usd": 12.40, "held_usd": 0.35, "available_usd": 12.05 }
held_usd được dành riêng cho các yêu cầu đang chạy; nó sẽ được hoàn lại (trừ đi chi phí thực tế) khi chúng kết thúc. available_usd là số tiền mà các yêu cầu mới có thể sử dụng.
Các tùy chọn của từng mô hình
GET /v1/models?type=image (hoặc video, music, speech, transcription,
audio cho cả hai loại đó, chat, all; nhiều mục được nối bằng dấu phẩy; nếu không có
type thì danh sách chỉ gồm các mô hình trò chuyện) liệt kê các mô hình bạn có thể gọi ngay bây giờ, mỗi mô hình có type của nó,
endpoints để gửi đến và pricing của nó. GET /v1/models/<model id> cung cấp một
mô hình, và đối với mô hình phương tiện, một đối tượng parameters: một JSON Schema của phần thân yêu cầu
với độ dài clip, độ phân giải, tỷ lệ khung hình và kích thước mà nó chấp nhận, cũng như
hình ảnh nguồn mà nó cần.
curl -H "Authorization: Bearer $UBERLLM_API_KEY" \
https://api.uberllm.dev/v1/models/pixverse/pixverse-c1-reference-to-video
pricing có usd (mức cao nhất mà một unit hiện có giá) và list_usd (
giá riêng của nhà sản xuất mô hình); một mô hình trò chuyện có input_usd, output_usd và
giá list_ của chúng trên mỗi 1M tokens.
Lỗi
| HTTP | code | meaning |
|---|---|---|
| 400 | wrong_endpoint |
ví dụ: một mô hình hình ảnh được gửi đến /v1/video/generations, một mô hình trò chuyện được gửi đến một tuyến hình ảnh, hoặc một mô hình giọng nói được gửi đến /v1/audio/transcriptions; thông báo nêu rõ đường dẫn chính xác. Không có phí nào được tính, và Hoạt động liệt kê nó là bị từ chối |
| 400 | invalid_request |
yêu cầu sai (thông báo cho biết lý do, ví dụ: thời lượng mà mô hình không cung cấp hoặc thiếu ảnh nguồn) |
| 400 | image_required |
một chỉnh sửa, hoặc một mô hình hình ảnh sang video hoặc tham chiếu sang video, không có ảnh nguồn |
| 400 | max_cost_too_low |
nó có thể tốn nhiều hơn max_cost của bạn; không có phí nào được tính |
| 409 | idempotency_key_reused |
Idempotency-Key đó đã được sử dụng cho một yêu cầu khác |
| 400 | quote_mismatch / quote_expired |
yêu cầu không phải là yêu cầu đã được báo giá, hoặc báo giá đã quá 15 phút |
| 404 | quote_not_found |
không có báo giá nào như vậy trên tài khoản của bạn |
| 409 | quote_used |
báo giá đó đã bắt đầu một yêu cầu |
| 400 | max_price_exceeded |
mô hình tốn nhiều hơn mỗi đơn vị so với provider.max_price của bạn |
| 400 | unsupported_routing_option |
một tùy chọn provider khác ngoài max_price |
| 404 | file_not_found |
không có tệp đã tải lên nào như vậy trên tài khoản của bạn, hoặc nó đã hết hạn |
| 413 | file_too_large |
một tệp tải lên vượt quá 10 MB |
| 429 | too_many_files |
500 tệp tải lên đã được giữ lại; hãy xóa một số hoặc đợi chúng hết hạn |
| 503 | files_unavailable |
tính năng tải lên hiện không khả dụng |
| 413 | request_too_large |
yêu cầu vượt quá giới hạn kích thước (40 MB); hãy gửi ảnh dưới dạng liên kết https:// và chia nhỏ các bản ghi âm dài |
| 402 | insufficient_credits |
số dư của bạn không đủ để chi trả chi phí tối đa của công việc; thông báo cho biết cần bao nhiêu |
| 404 | model_not_found / not_found |
không có mô hình nào như vậy, hoặc không có công việc nào như vậy trên tài khoản của bạn |
| 404 | artifact_expired |
tệp không còn được giữ lại (xem ở trên) |
| 429 | rate_limited |
hãy đợi số giây trong Retry-After (vài giây nếu nó không có), sau đó thử lại; X-RateLimit-Remaining cho biết còn bao nhiêu yêu cầu trong phút này |
| 503 | no_available_provider |
không có nhà cung cấp nào có thể thực hiện nó ngay bây giờ; UberLLM đã thử các nhà cung cấp khác rồi. Thông báo nêu tên các mô hình cùng loại đang hoạt động |