Skip to content

Audio

Cut the stretch of audio a model actually needs and hand it over as 16-bit WAV at the rate that model expects.

from annotools import clip_audio, write_bytes

wav, info = clip_audio("talk.wav", start=2.0, end=8.0, sample_rate=16000)
write_bytes("clips/talk_002_008.wav", wav)

print(info["duration"], info["sample_rate"], info["channels"])

This prints 6.0 16000 1. The source can be a video file — clip_audio reads its first audio stream — and end is exclusive and clamped to the source duration, while a start beyond it is an error rather than an empty clip. write_bytes creates parent directories for local paths. Resampling is optional but usually worth it in the same call: most speech models expect 16 kHz, and a 44.1 kHz clip is nearly three times the bytes to upload for the same audio. It does not make the clip cheaper — audio is billed per second, not per sample — so the length of the window is the lever. Needs PyAV: uv add "annotools[media]".

clip_audio:

{
  "source": "talk.wav",
  "start": 2.0,
  "end": 8.0,
  "sample_rate": 16000,
  "save_to": "clips/talk_002_008.wav"
}

Returns a WAV audio block followed by one metadata object: source_duration, start, end, duration, sample_rate, channels, format, and saved_to when save_to was given. It is the only tool that returns audio rather than an image, and the only one whose save_to writes a single file with no companion preview.

Long recordings are worked in windows: clip a few minutes, transcribe or label them, then move the window on. Gemini bills audio at 32 tokens per second, so a 6-second clip is roughly 200 tokens — cheap enough to re-listen to a segment during a correction round.

Then: clip_audio for the parameters and the error rules, and clip_audio plus write_bytes for the library contract. There is no audio-specific skill yet; the store and pipeline conventions in skills/sqlite-annotation-store apply unchanged — keep the WAV on disk and store its path, never its bytes.