AI
Video and Voice
Asynchronous video on Queues, speech synthesis, prices, limits, the task APIs and provider keys.
Before you start
Video and voice run through the bundled provider adapter, so live mode needs DASHSCOPE_API_KEY as a Worker secret (see AI overview). Without the key, live mode hides these models and the studios explain why. Mock mode serves playable sample media with no key.
Video
| Setting | Value |
|---|---|
| Length | 2 to 10 seconds |
| Resolution and price | 480P: 6, 720P: 12, 1080P: 23 credits per second |
| Ratios | 16:9, 9:16, 1:1, 4:3, 3:4 |
| Input | Text, or text plus a first frame from the library (image-to-video renders 1:1) |
| Audio | Generated with the clip unless audio is false |
A 5-second 720P clip reserves 60 credits.
How a video task runs
/app/videosendsPOST /api/ai/videos. The server prices resolution × seconds and reserves the credits with the task and its outbox message.- The queue consumer leases the task and the adapter submits the provider job. Its id is stored on the task.
- The lease is released and a delayed message (
JOBS.send(..., { delaySeconds })) checks again later. Nothing waits inside a request, and people can close the tab. - When the job finishes, the MP4 is copied into R2 and served from
/api/ai/assets/{id}/contentwith range requests, so the player can seek. - A job still unfinished 30 minutes after its first claim fails and returns its credits. The five-minute cron also reclaims expired leases.
{
"requestId": "0b8d5e2a-7f3c-4c1d-9a6e-2f4b8c1d3e5a",
"model": "your-video-model-key",
"prompt": "Steam rises from the coffee, the camera slowly pushes in",
"resolution": "720P",
"ratio": "16:9",
"seconds": 5,
"audio": true,
"firstFrame": "optional-library-asset-id"
}The prompt is up to 2,000 characters. The model key comes from VIDEO_MODELS in packages/ai/src/video.ts.
Voice
| Setting | Value |
|---|---|
| Voices | Seven curated voices: Chinese narration, news, documentary and expressive styles, plus one English voice |
| Script | Up to 2,000 characters per clip |
| Price | 2 credits per 1,000 characters, rounded up, so every clip costs at least 1 credit |
| Output | MP3 in the library, playable and downloadable |
POST /api/ai/speech takes requestId, model, voice and text. The task is reserved, leased from JOBS, synthesized by the adapter and written to R2 like every other output. Voice keys and labels live in SPEECH_MODELS in packages/ai/src/speech.ts.
Shared behavior
- Both endpoints return
201with the task and refuse with402,429or503like the image studio. GET /api/ai/tasks/{id}reports progress;POST /api/ai/tasks/{id}/cancelcancels a queued task and returns its credits.- Provider content refusals return credits while
ai.refundOnContentRefusalistrue. - Each task's estimated upstream cost counts toward
ai.dailyBudgetUsd.
Troubleshooting
- Model missing in live mode: the provider key is not set for this environment.
- Stuck in rendering: check that the queue consumer is deployed, the
JOBSbinding exists and the cron trigger runs. The task fails with a refund after 30 minutes. - Video does not seek: load it through
/api/ai/assets/{id}/content, which answers range requests, not through a copied URL.