tqdm in Jupyter for a 30-second AI video render, no percentage
Sume gives job statuses, not a percent. Use a tqdm elapsed-time bar with the status as its label, and stop on terminal. Runs in a notebook cell.

Sume does not report a render percentage, so the honest progress bar for a 30-second video job is an elapsed-time counter labeled with the current status. Poll GET /v1/jobs/:id/status, update the bar's description with sume_status, and stop when terminal is true.
A job moves through queued, processing, and then one of completed, failed, or canceled. There is nothing between processing and completed to count, so a fake 0 to 100 bar would lie.
What the status call gives you
The status response carries booleans terminal and result_ready, the sume_status value, and, while the job runs, next_poll_after_seconds. When that hint is present, obey it; when it is not, back off yourself. Do not call the endpoint in a tight loop across many jobs.
queued is a normal state. When your workspace is at its concurrency limit, valid jobs wait in queued until a slot opens, so a bar that sits in queued is waiting its turn, not failing.
The notebook cell
Set SUME_JOB_ID to the id from your submit response. The cell uses a tqdm bar with no total, so it shows elapsed time and an updating label. A deadline of 20 minutes is a reasonable client-side limit for a video job, and hitting it does not cancel the job.
import os, time, requests
from tqdm.auto import tqdm
job = os.environ["SUME_JOB_ID"]
url = f"https://api.sume.com/v1/jobs/{job}/status"
hdr = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
deadline = time.monotonic() + 20 * 60
delay = 5.0
with tqdm(total=None, bar_format="{desc} | {elapsed}") as bar:
while time.monotonic() < deadline:
s = requests.get(url, headers=hdr, timeout=15).json()
bar.set_description(s.get("sume_status", "?"))
if s.get("terminal"):
break
wait = s.get("next_poll_after_seconds") or delay
delay = min(delay * 1.5, 30.0)
time.sleep(wait)
print(s.get("sume_status"), "result_ready:", s.get("result_ready"))Reading the label
| sume_status | Terminal | Bar label idea |
|---|---|---|
| queued | No | waiting for a slot |
| processing | No | rendering |
| completed | Yes | done, fetch the result |
| failed | Yes | failed, read the error |
| canceled | Yes | canceled |
After the bar stops
Fetch GET /v1/jobs/:id/result only when result_ready is true or the status is completed. For any other status the result call answers 409 job_not_completed, so read the failure from the job record instead.
If your notebook kernel dies or the deadline passes, the job keeps running and billing. Keep the job id in a cell output or a file, and attach a new bar to it later rather than submitting again.
Stopping cleanly
If you interrupt the cell, the job is not canceled. Cancellation works only before generation starts, through POST /v1/jobs/:id/cancel. After processing begins the API answers 409 job_generation_already_started and the render finishes and bills normally. Treat the interrupt as stopping the wait, not the work.
Wrap the loop in try/finally and print the job id in the finally block, so a stopped notebook always leaves you the id you need to resume.
Show the queue honestly
Sume shows queue counts for the workspace but no per-job queue position or ETA. If you submit a few clips at once on a small plan, some will sit in queued by design. Show that label rather than a spinner, so the person watching the notebook knows nothing is stuck.
If you want a rough sense of timing, read GET /v1/jobs/:id/events after the fact. The job.started event tells you when the wait in the queue ended and the render began.
Where the bar belongs
Use the notebook widget version of tqdm for a cell that runs for minutes, so the output does not scroll. Close the bar in a finally block so an interrupted cell leaves a clean display.
Sources
Related posts
More in Developers
- Transcribe 1,000 twenty-second clips: pack 20 per file, then run STT
1,000 clips of 20 s cost $10.00 on Sume STT if billed one minute each, but $4.00 if you pack 20 clips per file with Timeline audio.
- Transcribe a 9-minute recording in two calls for ten cents
Detach the audio at 16 kHz mono ($0.01), then send it to Sume STT ($0.01 a minute): nine minutes of speech to text for $0.10 in two requests.
- Transcribe a MAI-Voice-2.1 clip with Sume STT: Python audio_url run
Host a MAI-Voice-2.1 or Flash clip at a public HTTPS URL and Sume STT returns text, word times and sentences for 1 cent a minute. A 25-line Python run.
- Translate a pack into 8 languages in parallel: queue limits by plan
Eight Ideogram 4.5 edits fit the Pro queue (24 accepted jobs) but not Free (6), so 2 get 429 queue_full. Python thread pool with retry; cost is $0.60 at medium.
Written by Sume