A small, resumable pipeline for turning a large podcast (or any large audio) archive into something you can actually search and ask questions of — transcription, structured summaries, semantic search, and grounded Q&A, all scripted around the OpenAI API.
Built to process 230 episodes (~145 hours of audio) for about $33 total.
Full write-up of how it works and what broke along the way: see
technical-blog.html (open it directly in a
browser, or publish it wherever you like).
Why this exists
Feeding a large transcript archive into an LLM's context window doesn't scale, and reading it yourself doesn't either. This pipeline gives you three ways to actually use a large audio archive:
- Structured summaries — a fast, cheap overview per episode (topics, quotes, takeaways, tone)
- Semantic search — embed everything once, then find the exact passage relevant to any question in milliseconds
- RAG-based Q&A — ask a natural-language question and get an answer grounded in, and cited to, the actual source material — no hallucinated advice
Pipeline
transcribe.py mp3s → transcripts/*.txt
build_index.py transcripts → index/ (embeddings + metadata)
summarize.py transcripts → summaries/*.json
ask.py question → cited answer (stdout)
analyze_themes.py summaries → themes.json (cross-corpus synthesis)
Every script only reads from the previous stage's output directory and only writes to its own — nothing is ever mutated in place, and every script skips work that's already done. That means you can kill any stage mid-run, add more source files later, or swap models between batches, and just rerun.
Setup
python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt brew install ffmpeg # or your platform's equivalent
Create a .env file in the project root:
Usage
# 1. Drop your audio files into audio-files/, then: python transcribe.py # 2. Generate per-episode structured summaries: python summarize.py # 3. Build the semantic search index: python build_index.py # 4. Ask questions grounded in the transcripts: python ask.py "what did they say about X?" # 5. (Optional) synthesize themes across the whole corpus: python analyze_themes.py
summarize.py and analyze_themes.py both have a short constant near the
top (SHOW_DESCRIPTION, FOCUS_THEMES) you should edit to match your own
show and what you actually want extracted — they ship with generic
placeholders, not any specific podcast's content.
Notes on cost and models
- Transcription defaults to
gpt-4o-mini-transcribe;whisper-1also works and may transcribe slightly better for noisy audio, at roughly double the per-minute cost. - Source files get chunked to ~15-minute, 64kbps mono segments before upload — this keeps you well under API file-size limits and works for any audio length.
- Concurrency is capped at two levels (files × chunks-per-file) to stay
under provider rate limits without going fully sequential. Tune
FILE_WORKERS/CHUNK_WORKERS_PER_FILEintranscribe.pyfor your own rate limit tier. - The search index is a single
numpyarray + JSON metadata file — no vector database needed until you're well past tens of thousands of chunks.
What isn't in this repo
The actual transcripts, summaries, and embeddings produced by running this against a real show aren't included — that's someone else's copyrighted audio content, even in text form. This repo is the workflow, not any particular show's content. Point it at your own audio.
License
MIT — see LICENSE.