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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chunkscribe-0.1.0.tar.gz (9.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chunkscribe-0.1.0-py3-none-any.whl (12.2 kB view details)

Uploaded Python 3

File details

Details for the file chunkscribe-0.1.0.tar.gz.

File metadata

  • Download URL: chunkscribe-0.1.0.tar.gz
  • Upload date:
  • Size: 9.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.3

File hashes

Hashes for chunkscribe-0.1.0.tar.gz
Algorithm Hash digest
SHA256 31a7be6b556459a47402c8263720f465021927ff73c9e5e44bfce72fb0fc43bc
MD5 a9ea5521a738a7625452ccd6e39de031
BLAKE2b-256 0ed3368a6d52fe131c12819dd7c016a2e72654df66bb2062851a6f2150d7e560

See more details on using hashes here.

File details

Details for the file chunkscribe-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: chunkscribe-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.3

File hashes

Hashes for chunkscribe-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5caa798e872f38199d3662a95af26cc52e562af450ed5b12a11bc13136f2e65e
MD5 232ae60b5e61d677071300871dd18d4e
BLAKE2b-256 0b9bc5fb917e4137180335559a34cc7bbdce72c9e85abb05b70ee7f33a65bbe6

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page