EmbeddingGemma 2's 5.5-minute audio limit: cut a long track
EmbeddingGemma 2 fits 5.5 minutes of audio. A 28-minute video needs six 300-second audio detach ranges at $0.01 per job, $0.06 in total.

EmbeddingGemma 2 takes up to 5.5 minutes of audio in its 8,000-token window, so a 28-minute (1,680-second) video has to be cut into pieces first. On Sume, six audio detach calls with 300-second ranges do it: each is a $0.01 job, so $0.06 in all, and each returns a new wav or mp3 artifact you can hand to your own embedder.
Sume has no embeddings endpoint, so the embedding step runs on your side. Sume supplies the audio cutting.
Why 300 seconds and not 330?
Google's post says the window fits up to 5.5 minutes of audio, which is 330 seconds. That window is shared with any frames or images in the same call, so a round 300 seconds leaves a margin. If you embed audio alone you can push closer to 330; if you add video frames, shrink the audio range.
How many ranges does a long video need?
Audio detach accepts a source up to 1,800 seconds and an output up to 900 seconds. A whole track over 900 seconds needs a range, so the 28-minute case would need ranges even without the embedder limit. The ranges below are half-open windows in seconds; the last one ends at the source duration.
| Call | Range start | Range end | Length (s) |
|---|---|---|---|
| 1 | 0 | 300 | 300 |
| 2 | 300 | 600 | 300 |
| 3 | 600 | 900 | 300 |
| 4 | 900 | 1200 | 300 |
| 5 | 1200 | 1500 | 300 |
| 6 | 1500 | 1680 | 180 |
What does the request look like?
Import the video first with POST /v1/media-imports, because the API refuses off-host URLs. Send an Idempotency-Key per window so a retry does not queue a second job. The default mode is async, so poll GET /v1/jobs/:id/result, which returns audio_url, duration_seconds and source_duration_seconds.
The script prints the six bodies. The end of the last window is the known duration; a range.start past the probed duration is refused with detach_start_past_source.
import json
def windows(duration_s, size=300):
start = 0
while start < duration_s:
yield start, min(start + size, duration_s)
start += size
clip = "https://media.sume.com/artifacts/artf_demo/talk.mp4"
for n, (a, b) in enumerate(windows(1680), start=1):
body = {"video_url": clip, "format": "mp3", "channels": "mono",
"range": {"start": a, "end": b}}
print(f"audio-detach-{n:03d}", json.dumps(body))What if the video has no audio?
A silent source fails with detach_source_has_no_audio. Run a video inspect with frames: false first and read probe.has_audio; that probe-only call avoids sending six doomed jobs.
If you only need searchable speech, a transcript may be cheaper to index than audio vectors; the earlier post on audio embeddings versus a transcript compares the two.
Sources
Related posts
More in Developers
- EmbeddingGemma 2 takes 58 video frames: sample them with Sume
EmbeddingGemma 2 fits 58 video frames in its 8K window. Sume's video inspect returns 24 stills per call, so three calls with explicit times cover it.
- Erlang: verify a Sume webhook with crypto:mac and crypto:hash_equals
Verify a Sume webhook in Erlang/OTP 26+: crypto:mac over timestamp.raw_body, binary:encode_hex, crypto:hash_equals, rotation entries, and an empty-secret guard.
- Falcon ASGI: verify a Sume webhook with req.bounded_stream.read()
Read the raw Sume webhook body in Falcon ASGI with req.bounded_stream.read(), verify HMAC SHA-256, and set HTTP_204 or raise HTTPUnauthorized.
- Fastify raw body for a Sume webhook: parseAs string and verifyWebhook
Fastify parses JSON before your handler, which breaks signatures. Use addContentTypeParser with parseAs string and verifyWebhook from @sume-com/sdk.
Written by Sume