Skip to main content

chunkscribe

Split long audio at natural pauses and transcribe it with the OpenAI API.

Transcription endpoints cap uploads at 25 MB, which forces you to chunk anything longer than roughly ten minutes. Cutting on a fixed clock clips words mid-syllable at every boundary. chunkscribe cuts at silences instead: you set a target duration, and it extends to the next qualifying pause.

Install

pip install chunkscribe

Set your key in a .env file beside the audio, or in the environment:

OPENAI_API_KEY=sk-...

WAV input needs nothing else. Other formats require pip install chunkscribe[mp3] and an ffmpeg binary on PATH.

Use

chunkscribe SOURCE [OUTPUT] [options]

Inspect the split before spending anything:

chunkscribe lecture.wav --dry-run
14 chunks, 176.3 min of speech, ~$1.06
  part_000.wav      0.0 →    9.7 min ( 9.7 min, 18.6 MB)
  part_001.wav      9.8 →   19.2 min ( 9.4 min, 18.0 MB)
  ...

Then run it:

chunkscribe lecture.wav transcript.txt --language en --timestamps

Omit OUTPUT to write alongside the input as .txt.

Options

Flag Default
--dry-run off split and report, no API calls
-f, --overwrite off replace an existing output file
-q, --quiet off suppress the per-chunk listing
--workdir DIR .chunkscribe/ cache location
--min-dur SEC 420 earliest legal cut point
--max-dur SEC 600 hard ceiling; keeps chunks under 25 MB
--max-silence SEC 0.6 pause length that qualifies as a cut
--energy N 50 speech/silence threshold
--model NAME gpt-4o-transcribe
--language ISO autodetect e.g. en
--prompt TERMS — seed names, jargon, expected spellings
--timestamps off prefix each chunk with its source offset

Tuning the split

Run --dry-run and read the chunk list. Two failure modes:

One region, or very few. --energy is too low, so room tone counts as speech and no pause ever qualifies. Raise it to 55–60.

Most chunks land on exactly --max-dur. No qualifying pause is being found, so every cut is a blind ceiling cut. Raise --max-silence to 0.4, or lower --energy. A warning fires automatically when this happens to more than half the chunks.

A three-hour lecture typically settles at 18–25 regions.

Caching and resume

Chunk audio and per-chunk transcripts are cached under --workdir. Interrupt a run and re-issue the same command: completed chunks are reused and cost nothing.

The cache directory name includes a fingerprint of the split settings, so changing --energy or --min-dur writes to a fresh directory rather than pairing new boundaries with stale transcripts. Old directories are never cleaned up automatically — rm -rf .chunkscribe/ when you're done.

Accuracy notes

--prompt seeds the first chunk's vocabulary. After that each chunk is primed with the tail of the previous transcript, which keeps names and terminology consistent across boundaries. Put rare terms in --prompt even if they appear late; the carry-over window is only 800 characters.

Because transcription is sequential to preserve that carry-over, a long file takes a while. Parallelising would be faster and less consistent.

Silences longer than --max-silence are dropped between regions, so chunk durations won't sum to the full runtime. That's expected. Timestamps come from each region's true offset in the source, not from accumulated durations.

Python API

from pathlib import Path
from chunkscribe import transcribe, SplitConfig

text = transcribe(
    "lecture.wav",
    split_cfg=SplitConfig(min_dur=300, max_dur=540, energy_threshold=55),
    timestamps=True,
)
Path("transcript.txt").write_text(text, encoding="utf-8")

Lower-level pieces, if you want the chunk boundaries themselves:

from chunkscribe import SplitConfig, TranscribeConfig, split, transcribe_chunks, render, workdir_for

cfg = SplitConfig()
chunks = split(Path("lecture.wav"), workdir_for(Path("lecture.wav"), cfg), cfg)
for c in chunks:
    print(c.index, c.start, c.end, c.size)

results = transcribe_chunks(chunks, TranscribeConfig(language="en"))
print(render(results, timestamps=True))

Exit codes

0 success · 1 split failure · 2 bad arguments · 130 interrupted

Cost

The --dry-run estimate uses a hardcoded per-minute rate. Verify it against current OpenAI pricing before relying on it.

License

MIT

Metadata

Release files for chunkscribe 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chunkscribe 0.1.0
File Size Uploaded
chunkscribe-0.1.0.tar.gz 9.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for chunkscribe 0.1.0
File Interpreter ABI Platform
chunkscribe-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 21.7 kB

Release files / chunkscribe-0.1.0.tar.gz

Download URL chunkscribe-0.1.0.tar.gz
Size 9.6 kB
Tags Source
SHA-256 checksum
How to use checksums
31a7be6b556459a47402c8263720f465021927ff73c9e5e44bfce72fb0fc43bc
BLAKE2b-256 checksum
How to use checksums
0ed3368a6d52fe131c12819dd7c016a2e72654df66bb2062851a6f2150d7e560
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release files / chunkscribe-0.1.0-py3-none-any.whl

Download URL chunkscribe-0.1.0-py3-none-any.whl
Size 12.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5caa798e872f38199d3662a95af26cc52e562af450ed5b12a11bc13136f2e65e
BLAKE2b-256 checksum
How to use checksums
0b9bc5fb917e4137180335559a34cc7bbdce72c9e85abb05b70ee7f33a65bbe6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page