Faster Whisper
Local speech-to-text using faster-whisper — a CTranslate2 reimplementation of OpenAI's Whisper that runs 4-6x faster with identical accuracy. With GPU acceleration, expect ~20x realtime transcription (a 10-minute audio file in ~30 seconds).
When to Use
Use this skill when you need to:
- Transcribe audio/video files — meetings, interviews, podcasts, lectures, YouTube videos
- Generate subtitles — SRT, VTT, ASS, LRC, or TTML broadcast-standard subtitles
- Identify speakers — diarization labels who said what (
--diarize)
- Transcribe from URLs — YouTube links and direct audio URLs (auto-downloads via yt-dlp)
- Transcribe podcast feeds —
--rss <feed-url> fetches and transcribes episodes
- Batch process files — glob patterns, directories, skip-existing support; ETA shown automatically
- Convert speech to text locally — no API costs, works offline (after model download)
- Translate to English — translate any language to English with
--translate
- Do multilingual transcription — supports 99+ languages with auto-detection
- Transcribe a batch of files in different languages —
--language-map assigns a different language per file
- Transcribe multilingual audio —
--multilingual for mixed-language audio
- Transcribe audio with specific terms — use
--initial-prompt for jargon-heavy content or any other terms to look out for
- Preprocess noisy audio (before transcription) —
--normalize and --denoise before transcription
- Stream output —
--stream shows segments as they're transcribed
- Clip time ranges —
--clip-timestamps to transcribe specific sections
- Search the transcript —
--search "term" finds all timestamps where a word/phrase appears
- Detect chapters —
--detect-chapters finds section breaks from silence gaps
- Export speaker audio —
--export-speakers DIR saves each speaker's turns as separate WAV files
- Spreadsheet output —
--format csv produces a properly-quoted CSV with timestamps
Trigger phrases:
"transcribe this audio", "convert speech to text", "what did they say", "make a transcript",
"audio to text", "subtitle this video", "who's speaking", "translate this audio", "translate to English",
"find where X is mentioned", "search transcript for", "when did they say", "at what timestamp",
"add chapters", "detect chapters", "find breaks in the audio", "table of contents for this recording",
"TTML subtitles", "DFXP subtitles", "broadcast format subtitles", "Netflix format",
"ASS subtitles", "aegisub format", "advanced substation alpha", "mpv subtitles",
"LRC subtitles", "timed lyrics", "karaoke subtitles", "music player lyrics",
"HTML transcript", "confidence-colored transcript", "color-coded transcript",
"separate audio per speaker", "export speaker audio", "split by speaker",
"transcript as CSV", "spreadsheet output", "transcribe podcast", "podcast RSS feed",
"different languages in batch", "per-file language",
"transcribe in multiple formats", "srt and txt at the same time", "output both srt and text",
"remove filler words", "clean up ums and uhs", "strip hesitation sounds", "remove you know and I mean",
"transcribe left channel", "transcribe right channel", "stereo channel", "left track only",
"wrap subtitle lines", "character limit per line", "max chars per subtitle",
"detect paragraphs", "paragraph breaks", "group into paragraphs", "add paragraph spacing"
⚠️ Agent guidance — keep invocations minimal:
CORE RULE: default command (./scripts/transcribe audio.mp3) is the fastest path — add flags only when the user explicitly asks for that capability.
Transcription:
- Only add
--diarize if the user asks "who said what" / "identify speakers" / "label speakers"
- Only add
--format srt/vtt/ass/lrc/ttml if the user asks for subtitles/captions in that format
- Only add
--format csv if the user asks for CSV or spreadsheet output
- Only add
--word-timestamps if the user needs word-level timing
- Only add
--initial-prompt if there's domain-specific jargon to prime
- Only add
--translate if the user wants non-English audio translated to English
- Only add
--normalize/--denoise if the user mentions bad audio quality or noise
- Only add
--stream if the user wants live/progressive output for long files
- Only add
--clip-timestamps if the user wants a specific time range
- Only add
--temperature 0.0 if the model is hallucinating on music/silence
- Only add
--vad-threshold if VAD is aggressively cutting speech or including noise
- Only add
--min-speakers/--max-speakers when you know the speaker count
- Only add
--hf-token if the token is not cached at ~/.cache/huggingface/token
- Only add
--max-words-per-line for subtitle readability on long segments
- Only add
--filter-hallucinations if the transcript contains obvious artifacts (music markers, duplicates)
- Only add
--merge-sentences if the user asks for sentence-level subtitle cues
- Only add
--clean-filler if the user asks to remove filler words (um, uh, you know, I mean, hesitation sounds)
- Only add
--channel left|right if the user mentions stereo tracks, dual-channel recordings, or asks for a specific channel
- Only add
--max-chars-per-line N when the user specifies a character limit per subtitle line (e.g., "Netflix format", "42 chars per line"); takes priority over --max-words-per-line
- Only add
--detect-paragraphs if the user asks for paragraph breaks or structured text output; --paragraph-gap (default 3.0s) only if they want a custom gap
- Only add
--speaker-names "Alice,Bob" when the user provides real names to replace SPEAKER_1/2 — always requires --diarize
- Only add
--hotwords WORDS when the user names specific rare terms not well served by --initial-prompt; prefer --initial-prompt for general domain jargon
- Only add
--prefix TEXT when the user knows the exact words the audio starts with
- Only add
--detect-language-only when the user only wants to identify the language, not transcribe
- Only add
--stats-file PATH if the user asks for performance stats, RTF, or benchmark info
- Only add
--parallel N for large CPU batch jobs; GPU handles one file efficiently on its own — don't add for single files or small batches
- Only add
--retries N for unreliable inputs (URLs, network files) where transient failures are expected
- Only add
--burn-in OUTPUT only when user explicitly asks to embed/burn subtitles into the video; requires ffmpeg and a video file input
- Only add
--keep-temp when the user may re-process the same URL to avoid re-downloading
- Only add
--output-template when user specifies a custom naming pattern in batch mode
- Multi-format output (
--format srt,text): only when user explicitly wants multiple formats in one pass; always pair with -o <dir>
- Any word-level feature auto-runs wav2vec2 alignment (~5-10s overhead)
--diarize adds ~20-30s on top of that
Search:
- Only add
--search "term" when the user asks to find/locate/search for a specific word or phrase in audio
--search replaces the normal transcript output — it prints only matching segments with timestamps
- Add
--search-fuzzy only when the user mentions approximate/partial matching or typos
- To save search results to a file, use
-o results.txt
Chapter detection:
- Only add
--detect-chapters when the user asks for chapters, sections, a table of contents, or "where does the topic change"
- Default
--chapter-gap 8 (8-second silence = new chapter) works for most podcasts/lectures; tune down for dense content
--chapter-format youtube (default) outputs YouTube-ready timestamps; use json for programmatic use
- Always use
--chapters-file PATH when combining chapters with a transcript output — avoids mixing chapter markers into the transcript text
- If the user only wants chapters (not the transcript), pipe stdout to a file with
-o /dev/null and use --chapters-file
- Batch mode limitation:
--chapters-file takes a single path — in batch mode, each file's chapters overwrite the previous. For batch chapter detection, omit --chapters-file (chapters print to stdout under === CHAPTERS (N) ===) or use a separate run per file
Speaker audio export:
- Only add
--export-speakers DIR when the user explicitly asks to save each speaker's audio separately
- Always pair with
--diarize — it silently skips if no speaker labels are present
- Requires ffmpeg; outputs
SPEAKER_1.wav, SPEAKER_2.wav, etc. (or real names if --speaker-names is set)
Language map:
- Only add
--language-map in batch mode when the user has confirmed different languages across files
- Inline format:
"interview*.mp3=en,lecture*.mp3=fr" — fnmatch globs on filename
- JSON file format:
@/path/to/map.json where the file is {"pattern": "lang_code"}
RSS / Podcast:
- Only add
--rss URL when the user provides a podcast RSS feed URL
- Default fetches 5 newest episodes;
--rss-latest 0 for all; --skip-existing to resume safely
- Always use
-o <dir> with --rss — without it, all episode transcripts print to stdout concatenated, which is hard to use; each episode gets its own file when -o <dir> is set
Output format for agent relay:
- Search results (
--search) → print directly to user; output is human-readable
- Chapter output → if no
--chapters-file, chapters appear in stdout under === CHAPTERS (N) === header after the transcript; with --format json, chapters are also embedded in the JSON under "chapters" key
- Subtitle formats (SRT, VTT, ASS, LRC, TTML) → always write to
-o file; tell the user the output path, never paste raw subtitle content
- Data formats (CSV, HTML, TTML, JSON) → always write to
-o file; tell the user the output path, don't paste raw XML/CSV/HTML
- ASS format → for Aegisub, VLC, mpv; write to file and tell user they can open it in Aegisub or play it in VLC/mpv
- LRC format → timed lyrics for music players (Foobar2000, AIMP, VLC); write to file
- Multi-format (
--format srt,text) → requires -o <dir>; each format goes to a separate file; tell user all paths written
- JSON format → useful for programmatic post-processing; not ideal to paste in full to user
- Text/transcript → safe to show directly to user for short files; summarise for long ones
- Stats output (
--stats-file) → summarise key fields (duration, processing time, RTF) for the user rather than pasting raw JSON
- Language detection (
--detect-language-only) → print the result directly; it's a single line
- ETA is printed automatically to stderr for batch jobs; no action needed
When NOT to use:
- Cloud-only environments without local compute
- Files <10 seconds where API call latency doesn't matter
faster-whisper vs whisperx:
This skill covers everything whisperx does — diarization (--diarize), word-level timestamps (--word-timestamps), SRT/VTT subtitles — so whisperx is not needed. Use whisperx only if you specifically need its pyannote pipeline or batch-GPU features not covered here.
Quick Reference
| Task |
Command |
Notes |
| Basic transcription |
./scripts/transcribe audio.mp3 |
Batched inference, VAD on, distil-large-v3.5 |
| SRT subtitles |
./scripts/transcribe audio.mp3 --format srt -o subs.srt |
Word timestamps auto-enabled |
| VTT subtitles |
./scripts/transcribe audio.mp3 --format vtt -o subs.vtt |
WebVTT format |
| Word timestamps |
./scripts/transcribe audio.mp3 --word-timestamps --format srt |
wav2vec2 aligned (~10ms) |
| Speaker diarization |
./scripts/transcribe audio.mp3 --diarize |
Requires pyannote.audio |
| Translate → English |
./scripts/transcribe audio.mp3 --translate |
Any language → English |
| Stream output |
./scripts/transcribe audio.mp3 --stream |
Live segments as transcribed |
| Clip time range |
./scripts/transcribe audio.mp3 --clip-timestamps "30,60" |
Only 30s–60s |
| Denoise + normalize |
./scripts/transcribe audio.mp3 --denoise --normalize |
Clean up noisy audio first |
| Reduce hallucination |
./scripts/transcribe audio.mp3 --hallucination-silence-threshold 1.0 |
Skip hallucinated silence |
| YouTube/URL |
./scripts/transcribe https://youtube.com/watch?v=... |
Auto-downloads via yt-dlp |
| Batch process |
./scripts/transcribe *.mp3 -o ./transcripts/ |
Output to directory |
| Batch with skip |
./scripts/transcribe *.mp3 --skip-existing -o ./out/ |
Resume interrupted batches |
| Domain terms |
./scripts/transcribe audio.mp3 --initial-prompt 'Kubernetes gRPC' |
Boost rare terminology |
| Hotwords boost |
./scripts/transcribe audio.mp3 --hotwords 'JIRA Kubernetes' |
Bias decoder toward specific words |
| Prefix conditioning |
./scripts/transcribe audio.mp3 --prefix 'Good morning,' |
Seed the first segment with known opening words |
| Pin model version |
./scripts/transcribe audio.mp3 --revision v1.2.0 |
Reproducible transcription with a pinned revision |
| Debug library logs |
./scripts/transcribe audio.mp3 --log-level debug |
Show faster_whisper internal logs |
| Turbo model |
./scripts/transcribe audio.mp3 -m turbo |
Alias for large-v3-turbo |
| Faster English |
./scripts/transcribe audio.mp3 --model distil-medium.en -l en |
English-only, 6.8x faster |
| Maximum accuracy |
./scripts/transcribe audio.mp3 --model large-v3 --beam-size 10 |
Full model |
| JSON output |
./scripts/transcribe audio.mp3 --format json -o out.json |
Programmatic access with stats |
| Filter noise |
./scripts/transcribe audio.mp3 --min-confidence 0.6 |
Drop low-confidence segments |
| Hybrid quantization |
./scripts/transcribe audio.mp3 --compute-type int8_float16 |
Save VRAM, minimal quality loss |
| Reduce batch size |
./scripts/transcribe audio.mp3 --batch-size 4 |
If OOM on GPU |
| TSV output |
./scripts/transcribe audio.mp3 --format tsv -o out.tsv |
OpenAI Whisper–compatible TSV |
| Fix hallucinations |
./scripts/transcribe audio.mp3 --temperature 0.0 --no-speech-threshold 0.8 |
Lock temperature + skip silence |
| Tune VAD sensitivity |
./scripts/transcribe audio.mp3 --vad-threshold 0.6 --min-silence-duration 500 |
Tighter speech detection |
| Known speaker count |
./scripts/transcribe meeting.wav --diarize --min-speakers 2 --max-speakers 3 |
Constrain diarization |
| Subtitle word wrapping |
./scripts/transcribe audio.mp3 --format srt --word-timestamps --max-words-per-line 8 |
Split long cues |
| Private/gated model |
./scripts/transcribe audio.mp3 --hf-token hf_xxx |
Pass token directly |
| Show version |
./scripts/transcribe --version |
Print faster-whisper version |
| Upgrade in-place |
./setup.sh --update |
Upgrade without full reinstall |
| System check |
./setup.sh --check |
Verify GPU, Python, ffmpeg, venv, yt-dlp, pyannote |
| Detect language only |
./scripts/transcribe audio.mp3 --detect-language-only |
Fast language ID, no transcription |
| Detect language JSON |
./scripts/transcribe audio.mp3 --detect-language-only --format json |
Machine-readable language detection |
| LRC subtitles |
./scripts/transcribe audio.mp3 --format lrc -o lyrics.lrc |
Timed lyrics format for music players |
| ASS subtitles |
./scripts/transcribe audio.mp3 --format ass -o subtitles.ass |
Advanced SubStation Alpha (Aegisub, mpv, VLC) |
| Merge sentences |
./scripts/transcribe audio.mp3 --format srt --merge-sentences |
Join fragments into sentence chunks |
| Stats sidecar |
./scripts/transcribe audio.mp3 --stats-file stats.json |
Write perf stats JSON after transcription |
| Batch stats |
./scripts/transcribe *.mp3 --stats-file ./stats/ |
One stats file per input in dir |
| Template naming |
./scripts/transcribe audio.mp3 -o ./out/ --output-template "{stem}_{lang}.{ext}" |
Custom batch output filenames |
| Stdin input |
ffmpeg -i input.mp4 -f wav - | ./scripts/transcribe - |
Pipe audio directly from stdin |
| Custom model dir |
./scripts/transcribe audio.mp3 --model-dir ~/my-models |
Custom HuggingFace cache dir |
| Local model |
./scripts/transcribe audio.mp3 -m ./my-model-ct2 |
CTranslate2 model dir |
| HTML transcript |
./scripts/transcribe audio.mp3 --format html -o out.html |
Confidence-colored |
| Burn subtitles |
./scripts/transcribe video.mp4 --burn-in output.mp4 |
Requires ffmpeg + video input |
| Name speakers |
./scripts/transcribe audio.mp3 --diarize --speaker-names "Alice,Bob" |
Replaces SPEAKER_1/2 |
| Filter hallucinations |
./scripts/transcribe audio.mp3 --filter-hallucinations |
Removes artifacts |
| Keep temp files |
./scripts/transcribe https://... --keep-temp |
For URL re-processing |
| Parallel batch |
./scripts/transcribe *.mp3 --parallel 4 -o ./out/ |
CPU multi-file |
| RTX 3070 recommended |
./scripts/transcribe audio.mp3 --compute-type int8_float16 |
Saves ~1GB VRAM, minimal quality loss |
| CPU thread count |
./scripts/transcribe audio.mp3 --threads 8 |
Force CPU thread count (default: auto) |
| Podcast RSS (latest 5) |
./scripts/transcribe --rss https://feeds.example.com/podcast.xml |
Downloads & transcribes newest 5 episodes |
| Podcast RSS (all episodes) |
./scripts/transcribe --rss https://... --rss-latest 0 -o ./episodes/ |
All episodes, one file each |
| Podcast + SRT subtitles |
./scripts/transcribe --rss https://... --format srt -o ./subs/ |
Subtitle all episodes |
| Retry on failure |
./scripts/transcribe *.mp3 --retries 3 -o ./out/ |
Retry up to 3× with backoff on error |
| CSV output |
./scripts/transcribe audio.mp3 --format csv -o out.csv |
Spreadsheet-ready with header row; properly quoted |
| CSV with speakers |
./scripts/transcribe audio.mp3 --diarize --format csv -o out.csv |
Adds speaker column |
| Language map (inline) |
./scripts/transcribe *.mp3 --language-map "interview*.mp3=en,lecture.wav=fr" |
Per-file language in batch |
| Language map (JSON) |
./scripts/transcribe *.mp3 --language-map @langs.json |
JSON file: {"pattern": "lang"} |
| Batch with ETA |
./scripts/transcribe *.mp3 -o ./out/ |
Automatic ETA shown for each file in batch |
| TTML subtitles |
./scripts/transcribe audio.mp3 --format ttml -o subtitles.ttml |
Broadcast-standard DFXP/TTML (Netflix, BBC, Amazon) |
| TTML with speaker labels |
./scripts/transcribe audio.mp3 --diarize --format ttml -o subtitles.ttml |
Speaker-labeled TTML |
| Search transcript |
./scripts/transcribe audio.mp3 --search "keyword" |
Find timestamps where keyword appears |
| Search to file |
./scripts/transcribe audio.mp3 --search "keyword" -o results.txt |
Save search results |
| Fuzzy search |
./scripts/transcribe audio.mp3 --search "aproximate" --search-fuzzy |
Approximate/partial matching |
| Detect chapters |
./scripts/transcribe audio.mp3 --detect-chapters |
Auto-detect chapters from silence gaps |
| Chapter gap tuning |
./scripts/transcribe audio.mp3 --detect-chapters --chapter-gap 5 |
Chapters on gaps ≥5s (default: 8s) |
| Chapters to file |
./scripts/transcribe audio.mp3 --detect-chapters --chapters-file ch.txt |
Save YouTube-format chapter list |
| Chapters JSON |
./scripts/transcribe audio.mp3 --detect-chapters --chapter-format json |
Machine-readable chapter list |
| Export speaker audio |
./scripts/transcribe audio.mp3 --diarize --export-speakers ./speakers/ |
Save each speaker's audio to separate WAV files |
| Multi-format output |
./scripts/transcribe audio.mp3 --format srt,text -o ./out/ |
Write SRT + TXT in one pass |
| Remove filler words |
./scripts/transcribe audio.mp3 --clean-filler |
Strip um/uh/er/ah/hmm and discourse markers |
| Left channel only |
./scripts/transcribe audio.mp3 --channel left |
Extract left stereo channel before transcribing |
| Right channel only |
./scripts/transcribe audio.mp3 --channel right |
Extract right stereo channel |
| Max chars per line |
./scripts/transcribe audio.mp3 --format srt --max-chars-per-line 42 |
Character-based subtitle wrapping |
| Detect paragraphs |
./scripts/transcribe audio.mp3 --detect-paragraphs |
Insert paragraph breaks in text output |
| Paragraph gap tuning |
./scripts/transcribe audio.mp3 --detect-paragraphs --paragraph-gap 5.0 |
Tune gap threshold (default 3.0s) |
Model Selection
Choose the right model for your needs:
digraph model_selection {
rankdir=LR;
node [shape=box, style=rounded];
start [label="Start", shape=doublecircle];
need_accuracy [label="Need maximum\naccuracy?", shape=diamond];
multilingual [label="Multilingual\ncontent?", shape=diamond];
resource_constrained [label="Resource\nconstraints?", shape=diamond];
large_v3 [label="large-v3\nor\nlarge-v3-turbo", style="rounded,filled", fillcolor=lightblue];
large_turbo [label="large-v3-turbo", style="rounded,filled", fillcolor=lightblue];
distil_large [label="distil-large-v3.5\n(default)", style="rounded,filled", fillcolor=lightgreen];
distil_medium [label="distil-medium.en", style="rounded,filled", fillcolor=lightyellow];
distil_small [label="distil-small.en", style="rounded,filled", fillcolor=lightyellow];
start -> need_accuracy;
need_accuracy -> large_v3 [label="yes"];
need_accuracy -> multilingual [label="no"];
multilingual -> large_turbo [label="yes"];
multilingual -> resource_constrained [label="no (English)"];
resource_constrained -> distil_small [label="mobile/edge"];
resource_constrained -> distil_medium [label="some limits"];
resource_constrained -> distil_large [label="no"];
}
Model Table
Standard Models (Full Whisper)
| Model |
Size |
Speed |
Accuracy |
Use Case |
tiny / tiny.en |
39M |
Fastest |
Basic |
Quick drafts |
base / base.en |
74M |
Very fast |
Good |
General use |
small / small.en |
244M |
Fast |
Better |
Most tasks |
medium / medium.en |
769M |
Moderate |
High |
Quality transcription |
large-v1/v2/v3 |
1.5GB |
Slower |
Best |
Maximum accuracy |
large-v3-turbo |
809M |
Fast |
Excellent |
High accuracy (slower than distil) |
Distilled Models (~6x Faster, ~1% WER difference)
| Model |
Size |
Speed vs Standard |
Accuracy |
Use Case |
distil-large-v3.5 |
756M |
~6.3x faster |
7.08% WER |
Default, best balance |
distil-large-v3 |
756M |
~6.3x faster |
7.53% WER |
Previous default |
distil-large-v2 |
756M |
~5.8x faster |
10.1% WER |
Fallback |
distil-medium.en |
394M |
~6.8x faster |
11.1% WER |
English-only, resource-constrained |
distil-small.en |
166M |
~5.6x faster |
12.1% WER |
Mobile/edge devices |
.en models are English-only and slightly faster/better for English content.
Note for distil models: HuggingFace recommends disabling condition_on_previous_text for all distil models to prevent repetition loops. The script auto-applies --no-condition-on-previous-text whenever a distil-* model is detected. Pass --condition-on-previous-text to override if needed.
Custom & Fine-tuned Models
WhisperModel accepts local CTranslate2 model directories and HuggingFace repo names — no code changes needed.
Load a local CTranslate2 model
./scripts/transcribe audio.mp3 --model /path/to/my-model-ct2
Convert a HuggingFace model to CTranslate2
pip install ctranslate2
ct2-transformers-converter \
--model openai/whisper-large-v3 \
--output_dir whisper-large-v3-ct2 \
--copy_files tokenizer.json preprocessor_config.json \
--quantization float16
./scripts/transcribe audio.mp3 --model ./whisper-large-v3-ct2
Load a model by HuggingFace repo name (auto-downloads)
./scripts/transcribe audio.mp3 --model username/whisper-large-v3-ct2
Custom model cache directory
By default, models are cached in ~/.cache/huggingface/. Use --model-dir to override:
./scripts/transcribe audio.mp3 --model-dir ~/my-models
Setup
Linux / macOS / WSL2
# Base install (creates venv, installs deps, auto-detects GPU)
./setup.sh
# With speaker diarization support
./setup.sh --diarize
Requirements:
- Python 3.10+
- ffmpeg is not required for basic transcription — PyAV (bundled with faster-whisper) handles audio decoding. ffmpeg is only needed for
--burn-in, --normalize, and --denoise.
- Optional: yt-dlp (for URL/YouTube input)
- Optional: pyannote.audio (for
--diarize, installed via setup.sh --diarize)
Platform Support
| Platform |
Acceleration |
Speed |
| Linux + NVIDIA GPU |
CUDA |
~20x realtime 🚀 |
| WSL2 + NVIDIA GPU |
CUDA |
~20x realtime 🚀 |
| macOS Apple Silicon |
CPU* |
~3-5x realtime |
| macOS Intel |
CPU |
~1-2x realtime |
| Linux (no GPU) |
CPU |
~1x realtime |
*faster-whisper uses CTranslate2 which is CPU-only on macOS, but Apple Silicon is fast enough for practical use.
GPU Support (IMPORTANT!)
The setup script auto-detects your GPU and installs PyTorch with CUDA. Always use GPU if available — CPU transcription is extremely slow.
| Hardware |
Speed |
9-min video |
| RTX 3070 (GPU) |
~20x realtime |
~27 sec |
| CPU (int8) |
~0.3x realtime |
~30 min |
RTX 3070 tip: Use --compute-type int8_float16 for hybrid quantization — saves ~1GB VRAM with minimal quality loss. Ideal for running diarization alongside transcription.
If setup didn't detect your GPU, manually install PyTorch with CUDA:
# For CUDA 12.x
uv pip install --python .venv/bin/python torch --index-url https://download.pytorch.org/whl/cu121
# For CUDA 11.x
uv pip install --python .venv/bin/python torch --index-url https://download.pytorch.org/whl/cu118
Usage
# Basic transcription
./scripts/transcribe audio.mp3
# SRT subtitles
./scripts/transcribe audio.mp3 --format srt -o subtitles.srt
# WebVTT subtitles
./scripts/transcribe audio.mp3 --format vtt -o subtitles.vtt
# Transcribe from YouTube URL
./scripts/transcribe https://youtube.com/watch?v=dQw4w9WgXcQ --language en
# Speaker diarization
./scripts/transcribe meeting.wav --diarize
# Diarized VTT subtitles
./scripts/transcribe meeting.wav --diarize --format vtt -o meeting.vtt
# Prime with domain terminology
./scripts/transcribe lecture.mp3 --initial-prompt "Kubernetes, gRPC, PostgreSQL, NGINX"
# Batch process a directory
./scripts/transcribe ./recordings/ -o ./transcripts/
# Batch with glob, skip already-done files
./scripts/transcribe *.mp3 --skip-existing -o ./transcripts/
# Filter low-confidence segments
./scripts/transcribe noisy-audio.mp3 --min-confidence 0.6
# JSON output with full metadata
./scripts/transcribe audio.mp3 --format json -o result.json
# Specify language (faster than auto-detect)
./scripts/transcribe audio.mp3 --language en
Options
Input:
AUDIO Audio file(s), directory, glob pattern, or URL
Accepts: mp3, wav, m4a, flac, ogg, webm, mp4, mkv, avi, wma, aac
URLs auto-download via yt-dlp (YouTube, direct links, etc.)
Model & Language:
-m, --model NAME Whisper model (default: distil-large-v3.5; "turbo" = large-v3-turbo)
--revision REV Model revision (git branch/tag/commit) to pin a specific version
-l, --language CODE Language code, e.g. en, es, fr (auto-detects if omitted)
--initial-prompt TEXT Prompt to condition the model (terminology, formatting style)
--prefix TEXT Prefix to condition the first segment (e.g. known starting words)
--hotwords WORDS Space-separated hotwords to boost recognition
--translate Translate any language to English (instead of transcribing)
--multilingual Enable multilingual/code-switching mode (helps smaller models)
--hf-token TOKEN HuggingFace token for private/gated models and diarization
--model-dir PATH Custom model cache directory (default: ~/.cache/huggingface/)
Output Format:
-f, --format FMT text | json | srt | vtt | tsv | lrc | html | ass | ttml (default: text)
Accepts comma-separated list: --format srt,text writes both in one pass
Multi-format requires -o <dir> when saving to files
--word-timestamps Include word-level timestamps (wav2vec2 aligned automatically)
--stream Output segments as they are transcribed (disables diarize/alignment)
--max-words-per-line N For SRT/VTT, split segments into sub-cues of at most N words
--max-chars-per-line N For SRT/VTT/ASS/TTML, split lines so each fits within N characters
Takes priority over --max-words-per-line when both are set
--clean-filler Remove hesitation fillers (um, uh, er, ah, hmm, hm) and discourse markers
(you know, I mean, you see) from transcript text. Off by default.
--detect-paragraphs Insert paragraph breaks (blank lines) in text output at natural boundaries.
A new paragraph starts when: silence gap ≥ --paragraph-gap, OR the previous
segment ends a sentence AND the gap ≥ 1.5s.
--paragraph-gap SEC Minimum silence gap in seconds to start a new paragraph (default: 3.0).
Used with --detect-paragraphs.
--channel {left,right,mix}
Stereo channel to transcribe: left (c0), right (c1), or mix (default: mix).
Extracts the channel via ffmpeg before transcription. Requires ffmpeg.
--merge-sentences Merge consecutive segments into sentence-level chunks
(improves SRT/VTT readability; groups by terminal punctuation or >2s gap)
-o, --output PATH Output file or directory (directory for batch mode)
--output-template TEMPLATE
Batch output filename template. Variables: {stem}, {lang}, {ext}, {model}
Example: "{stem}_{lang}.{ext}" → "interview_en.srt"
Inference Tuning:
--beam-size N Beam search size; higher = more accurate but slower (default: 5)
--temperature T Sampling temperature or comma-separated fallback list, e.g.
'0.0' or '0.0,0.2,0.4' (default: faster-whisper's schedule)
--no-speech-threshold PROB
Probability threshold to mark segments as silence (default: 0.6)
--batch-size N Batched inference batch size (default: 8; reduce if OOM)
--no-vad Disable voice activity detection (on by default)
--vad-threshold T VAD speech probability threshold (default: 0.5)
--vad-neg-threshold T VAD negative threshold for ending speech (default: auto)
--vad-onset T Alias for --vad-threshold (legacy)
--vad-offset T Alias for --vad-neg-threshold (legacy)
--min-speech-duration MS Minimum speech segment duration in ms (default: 0)
--max-speech-duration SEC Maximum speech segment duration in seconds (default: unlimited)
--min-silence-duration MS Minimum silence before splitting a segment in ms (default: 2000)
--speech-pad MS Padding around speech segments in ms (default: 400)
--no-batch Disable batched inference (use standard WhisperModel)
--hallucination-silence-threshold SEC
Skip silent sections where model hallucinates (e.g. 1.0)
--no-condition-on-previous-text
Don't condition on previous text (reduces repetition/hallucination loops;
auto-enabled for distil models per HuggingFace recommendation)
--condition-on-previous-text
Force-enable conditioning on previous text (overrides auto-disable for distil models)
--compression-ratio-threshold RATIO
Filter segments above this compression ratio (default: 2.4)
--log-prob-threshold PROB
Filter segments below this avg log probability (default: -1.0)
--max-new-tokens N Maximum tokens per segment (prevents runaway generation)
--clip-timestamps RANGE
Transcribe specific time ranges: '30,60' or '0,30;60,90' (seconds)
--progress Show transcription progress bar
--best-of N Candidates when sampling with non-zero temperature (default: 5)
--patience F Beam search patience factor (default: 1.0)
--repetition-penalty F Penalty for repeated tokens (default: 1.0)
--no-repeat-ngram-size N Prevent n-gram repetitions of this size (default: 0 = off)
Advanced Inference:
--no-timestamps Output text without timing info (faster; incompatible with
--word-timestamps, --format srt/vtt/tsv, --diarize)
--chunk-length N Audio chunk length in seconds for batched inference (default: auto)
--language-detection-threshold T
Confidence threshold for language auto-detection (default: 0.5)
--language-detection-segments N
Audio segments to sample for language detection (default: 1)
--length-penalty F Beam search length penalty; >1 favors longer, <1 favors shorter (default: 1.0)
--prompt-reset-on-temperature T
Reset initial prompt when temperature fallback hits threshold (default: 0.5)
--no-suppress-blank Disable blank token suppression (may help soft/quiet speech)
…(truncated)
1---2name: faster-whisper3description: Local speech-to-text using faster-whisper. 4-6x faster than OpenAI Whisper with identical accuracy; GPU acceleration enables ~20x realtime transcription. SRT/VTT/TTML/CSV subtitles, speaker diarization, URL/YouTube input, batch processing with ETA, transcript search, chapter detection, per-file language map.4---5
6# Faster Whisper
7
8Local speech-to-text using faster-whisper — a CTranslate2 reimplementation of OpenAI's Whisper that runs **4-6x faster** with identical accuracy. With GPU acceleration, expect **~20x realtime** transcription (a 10-minute audio file in ~30 seconds).
9
10## When to Use
11
12Use this skill when you need to:
13
14- **Transcribe audio/video files** — meetings, interviews, podcasts, lectures, YouTube videos
15- **Generate subtitles** — SRT, VTT, ASS, LRC, or TTML broadcast-standard subtitles
16- **Identify speakers** — diarization labels who said what (`--diarize`)
17- **Transcribe from URLs** — YouTube links and direct audio URLs (auto-downloads via yt-dlp)
18- **Transcribe podcast feeds** — `--rss <feed-url>` fetches and transcribes episodes
19- **Batch process files** — glob patterns, directories, skip-existing support; ETA shown automatically
20- **Convert speech to text locally** — no API costs, works offline (after model download)
21- **Translate to English** — translate any language to English with `--translate`
22- **Do multilingual transcription** — supports 99+ languages with auto-detection
23- **Transcribe a batch of files in different languages** — `--language-map` assigns a different language per file
24- **Transcribe multilingual audio** — `--multilingual` for mixed-language audio
25- **Transcribe audio with specific terms** — use `--initial-prompt` for jargon-heavy content or any other terms to look out for
26- **Preprocess noisy audio (before transcription)** — `--normalize` and `--denoise` before transcription
27- **Stream output** — `--stream` shows segments as they're transcribed
28- **Clip time ranges** — `--clip-timestamps` to transcribe specific sections
29- **Search the transcript** — `--search "term"` finds all timestamps where a word/phrase appears
30- **Detect chapters** — `--detect-chapters` finds section breaks from silence gaps
31- **Export speaker audio** — `--export-speakers DIR` saves each speaker's turns as separate WAV files
32- **Spreadsheet output** — `--format csv` produces a properly-quoted CSV with timestamps
33
34**Trigger phrases:**
35"transcribe this audio", "convert speech to text", "what did they say", "make a transcript",
36"audio to text", "subtitle this video", "who's speaking", "translate this audio", "translate to English",
37"find where X is mentioned", "search transcript for", "when did they say", "at what timestamp",
38"add chapters", "detect chapters", "find breaks in the audio", "table of contents for this recording",
39"TTML subtitles", "DFXP subtitles", "broadcast format subtitles", "Netflix format",
40"ASS subtitles", "aegisub format", "advanced substation alpha", "mpv subtitles",
41"LRC subtitles", "timed lyrics", "karaoke subtitles", "music player lyrics",
42"HTML transcript", "confidence-colored transcript", "color-coded transcript",
43"separate audio per speaker", "export speaker audio", "split by speaker",
44"transcript as CSV", "spreadsheet output", "transcribe podcast", "podcast RSS feed",
45"different languages in batch", "per-file language",
46"transcribe in multiple formats", "srt and txt at the same time", "output both srt and text",
47"remove filler words", "clean up ums and uhs", "strip hesitation sounds", "remove you know and I mean",
48"transcribe left channel", "transcribe right channel", "stereo channel", "left track only",
49"wrap subtitle lines", "character limit per line", "max chars per subtitle",
50"detect paragraphs", "paragraph breaks", "group into paragraphs", "add paragraph spacing"
51
52**⚠️ Agent guidance — keep invocations minimal:**
53
54_CORE RULE: default command (`./scripts/transcribe audio.mp3`) is the fastest path — add flags only when the user explicitly asks for that capability._
55
56**Transcription:**
57
58- Only add `--diarize` if the user asks "who said what" / "identify speakers" / "label speakers"
59- Only add `--format srt/vtt/ass/lrc/ttml` if the user asks for subtitles/captions in that format
60- Only add `--format csv` if the user asks for CSV or spreadsheet output
61- Only add `--word-timestamps` if the user needs word-level timing
62- Only add `--initial-prompt` if there's domain-specific jargon to prime
63- Only add `--translate` if the user wants non-English audio translated to English
64- Only add `--normalize`/`--denoise` if the user mentions bad audio quality or noise
65- Only add `--stream` if the user wants live/progressive output for long files
66- Only add `--clip-timestamps` if the user wants a specific time range
67- Only add `--temperature 0.0` if the model is hallucinating on music/silence
68- Only add `--vad-threshold` if VAD is aggressively cutting speech or including noise
69- Only add `--min-speakers`/`--max-speakers` when you know the speaker count
70- Only add `--hf-token` if the token is not cached at `~/.cache/huggingface/token`
71- Only add `--max-words-per-line` for subtitle readability on long segments
72- Only add `--filter-hallucinations` if the transcript contains obvious artifacts (music markers, duplicates)
73- Only add `--merge-sentences` if the user asks for sentence-level subtitle cues
74- Only add `--clean-filler` if the user asks to remove filler words (um, uh, you know, I mean, hesitation sounds)
75- Only add `--channel left|right` if the user mentions stereo tracks, dual-channel recordings, or asks for a specific channel
76- Only add `--max-chars-per-line N` when the user specifies a character limit per subtitle line (e.g., "Netflix format", "42 chars per line"); takes priority over `--max-words-per-line`
77- Only add `--detect-paragraphs` if the user asks for paragraph breaks or structured text output; `--paragraph-gap` (default 3.0s) only if they want a custom gap
78- Only add `--speaker-names "Alice,Bob"` when the user provides real names to replace SPEAKER_1/2 — always requires `--diarize`
79- Only add `--hotwords WORDS` when the user names specific rare terms not well served by `--initial-prompt`; prefer `--initial-prompt` for general domain jargon
80- Only add `--prefix TEXT` when the user knows the exact words the audio starts with
81- Only add `--detect-language-only` when the user only wants to identify the language, not transcribe
82- Only add `--stats-file PATH` if the user asks for performance stats, RTF, or benchmark info
83- Only add `--parallel N` for large CPU batch jobs; GPU handles one file efficiently on its own — don't add for single files or small batches
84- Only add `--retries N` for unreliable inputs (URLs, network files) where transient failures are expected
85- Only add `--burn-in OUTPUT` only when user explicitly asks to embed/burn subtitles into the video; requires ffmpeg and a video file input
86- Only add `--keep-temp` when the user may re-process the same URL to avoid re-downloading
87- Only add `--output-template` when user specifies a custom naming pattern in batch mode
88- **Multi-format output** (`--format srt,text`): only when user explicitly wants multiple formats in one pass; always pair with `-o <dir>`
89- Any word-level feature auto-runs wav2vec2 alignment (~5-10s overhead)
90- `--diarize` adds ~20-30s on top of that
91
92**Search:**
93
94- Only add `--search "term"` when the user asks to find/locate/search for a specific word or phrase in audio
95- `--search` **replaces** the normal transcript output — it prints only matching segments with timestamps
96- Add `--search-fuzzy` only when the user mentions approximate/partial matching or typos
97- To save search results to a file, use `-o results.txt`
98
99**Chapter detection:**
100
101- Only add `--detect-chapters` when the user asks for chapters, sections, a table of contents, or "where does the topic change"
102- Default `--chapter-gap 8` (8-second silence = new chapter) works for most podcasts/lectures; tune down for dense content
103- `--chapter-format youtube` (default) outputs YouTube-ready timestamps; use `json` for programmatic use
104- **Always use `--chapters-file PATH`** when combining chapters with a transcript output — avoids mixing chapter markers into the transcript text
105- If the user only wants chapters (not the transcript), pipe stdout to a file with `-o /dev/null` and use `--chapters-file`
106- **Batch mode limitation:** `--chapters-file` takes a single path — in batch mode, each file's chapters overwrite the previous. For batch chapter detection, omit `--chapters-file` (chapters print to stdout under `=== CHAPTERS (N) ===`) or use a separate run per file
107
108**Speaker audio export:**
109
110- Only add `--export-speakers DIR` when the user explicitly asks to save each speaker's audio separately
111- Always pair with `--diarize` — it silently skips if no speaker labels are present
112- Requires ffmpeg; outputs `SPEAKER_1.wav`, `SPEAKER_2.wav`, etc. (or real names if `--speaker-names` is set)
113
114**Language map:**
115
116- Only add `--language-map` in batch mode when the user has confirmed different languages across files
117- Inline format: `"interview*.mp3=en,lecture*.mp3=fr"` — fnmatch globs on filename
118- JSON file format: `@/path/to/map.json` where the file is `{"pattern": "lang_code"}`
119
120**RSS / Podcast:**
121
122- Only add `--rss URL` when the user provides a podcast RSS feed URL
123- Default fetches 5 newest episodes; `--rss-latest 0` for all; `--skip-existing` to resume safely
124- **Always use `-o <dir>`** with `--rss` — without it, all episode transcripts print to stdout concatenated, which is hard to use; each episode gets its own file when `-o <dir>` is set
125
126**Output format for agent relay:**
127
128- **Search results** (`--search`) → print directly to user; output is human-readable
129- **Chapter output** → if no `--chapters-file`, chapters appear in stdout under `=== CHAPTERS (N) ===` header after the transcript; with `--format json`, chapters are also embedded in the JSON under `"chapters"` key
130- **Subtitle formats** (SRT, VTT, ASS, LRC, TTML) → always write to `-o` file; tell the user the output path, never paste raw subtitle content
131- **Data formats** (CSV, HTML, TTML, JSON) → always write to `-o` file; tell the user the output path, don't paste raw XML/CSV/HTML
132- **ASS format** → for Aegisub, VLC, mpv; write to file and tell user they can open it in Aegisub or play it in VLC/mpv
133- **LRC format** → timed lyrics for music players (Foobar2000, AIMP, VLC); write to file
134- **Multi-format** (`--format srt,text`) → requires `-o <dir>`; each format goes to a separate file; tell user all paths written
135- **JSON format** → useful for programmatic post-processing; not ideal to paste in full to user
136- **Text/transcript** → safe to show directly to user for short files; summarise for long ones
137- **Stats output** (`--stats-file`) → summarise key fields (duration, processing time, RTF) for the user rather than pasting raw JSON
138- **Language detection** (`--detect-language-only`) → print the result directly; it's a single line
139- **ETA** is printed automatically to stderr for batch jobs; no action needed
140
141**When NOT to use:**
142
143- Cloud-only environments without local compute
144- Files <10 seconds where API call latency doesn't matter
145
146**faster-whisper vs whisperx:**
147This skill covers everything whisperx does — diarization (`--diarize`), word-level timestamps (`--word-timestamps`), SRT/VTT subtitles — so whisperx is not needed. Use whisperx only if you specifically need its pyannote pipeline or batch-GPU features not covered here.
148
149## Quick Reference
150
151| Task | Command | Notes |
152| ------------------------------ | -------------------------------------------------------------------------------------- | --------------------------------------------------- |
153| **Basic transcription** | `./scripts/transcribe audio.mp3` | Batched inference, VAD on, distil-large-v3.5 |
154| **SRT subtitles** | `./scripts/transcribe audio.mp3 --format srt -o subs.srt` | Word timestamps auto-enabled |
155| **VTT subtitles** | `./scripts/transcribe audio.mp3 --format vtt -o subs.vtt` | WebVTT format |
156| **Word timestamps** | `./scripts/transcribe audio.mp3 --word-timestamps --format srt` | wav2vec2 aligned (~10ms) |
157| **Speaker diarization** | `./scripts/transcribe audio.mp3 --diarize` | Requires pyannote.audio |
158| **Translate → English** | `./scripts/transcribe audio.mp3 --translate` | Any language → English |
159| **Stream output** | `./scripts/transcribe audio.mp3 --stream` | Live segments as transcribed |
160| **Clip time range** | `./scripts/transcribe audio.mp3 --clip-timestamps "30,60"` | Only 30s–60s |
161| **Denoise + normalize** | `./scripts/transcribe audio.mp3 --denoise --normalize` | Clean up noisy audio first |
162| **Reduce hallucination** | `./scripts/transcribe audio.mp3 --hallucination-silence-threshold 1.0` | Skip hallucinated silence |
163| **YouTube/URL** | `./scripts/transcribe https://youtube.com/watch?v=...` | Auto-downloads via yt-dlp |
164| **Batch process** | `./scripts/transcribe *.mp3 -o ./transcripts/` | Output to directory |
165| **Batch with skip** | `./scripts/transcribe *.mp3 --skip-existing -o ./out/` | Resume interrupted batches |
166| **Domain terms** | `./scripts/transcribe audio.mp3 --initial-prompt 'Kubernetes gRPC'` | Boost rare terminology |
167| **Hotwords boost** | `./scripts/transcribe audio.mp3 --hotwords 'JIRA Kubernetes'` | Bias decoder toward specific words |
168| **Prefix conditioning** | `./scripts/transcribe audio.mp3 --prefix 'Good morning,'` | Seed the first segment with known opening words |
169| **Pin model version** | `./scripts/transcribe audio.mp3 --revision v1.2.0` | Reproducible transcription with a pinned revision |
170| **Debug library logs** | `./scripts/transcribe audio.mp3 --log-level debug` | Show faster_whisper internal logs |
171| **Turbo model** | `./scripts/transcribe audio.mp3 -m turbo` | Alias for large-v3-turbo |
172| **Faster English** | `./scripts/transcribe audio.mp3 --model distil-medium.en -l en` | English-only, 6.8x faster |
173| **Maximum accuracy** | `./scripts/transcribe audio.mp3 --model large-v3 --beam-size 10` | Full model |
174| **JSON output** | `./scripts/transcribe audio.mp3 --format json -o out.json` | Programmatic access with stats |
175| **Filter noise** | `./scripts/transcribe audio.mp3 --min-confidence 0.6` | Drop low-confidence segments |
176| **Hybrid quantization** | `./scripts/transcribe audio.mp3 --compute-type int8_float16` | Save VRAM, minimal quality loss |
177| **Reduce batch size** | `./scripts/transcribe audio.mp3 --batch-size 4` | If OOM on GPU |
178| **TSV output** | `./scripts/transcribe audio.mp3 --format tsv -o out.tsv` | OpenAI Whisper–compatible TSV |
179| **Fix hallucinations** | `./scripts/transcribe audio.mp3 --temperature 0.0 --no-speech-threshold 0.8` | Lock temperature + skip silence |
180| **Tune VAD sensitivity** | `./scripts/transcribe audio.mp3 --vad-threshold 0.6 --min-silence-duration 500` | Tighter speech detection |
181| **Known speaker count** | `./scripts/transcribe meeting.wav --diarize --min-speakers 2 --max-speakers 3` | Constrain diarization |
182| **Subtitle word wrapping** | `./scripts/transcribe audio.mp3 --format srt --word-timestamps --max-words-per-line 8` | Split long cues |
183| **Private/gated model** | `./scripts/transcribe audio.mp3 --hf-token hf_xxx` | Pass token directly |
184| **Show version** | `./scripts/transcribe --version` | Print faster-whisper version |
185| **Upgrade in-place** | `./setup.sh --update` | Upgrade without full reinstall |
186| **System check** | `./setup.sh --check` | Verify GPU, Python, ffmpeg, venv, yt-dlp, pyannote |
187| **Detect language only** | `./scripts/transcribe audio.mp3 --detect-language-only` | Fast language ID, no transcription |
188| **Detect language JSON** | `./scripts/transcribe audio.mp3 --detect-language-only --format json` | Machine-readable language detection |
189| **LRC subtitles** | `./scripts/transcribe audio.mp3 --format lrc -o lyrics.lrc` | Timed lyrics format for music players |
190| **ASS subtitles** | `./scripts/transcribe audio.mp3 --format ass -o subtitles.ass` | Advanced SubStation Alpha (Aegisub, mpv, VLC) |
191| **Merge sentences** | `./scripts/transcribe audio.mp3 --format srt --merge-sentences` | Join fragments into sentence chunks |
192| **Stats sidecar** | `./scripts/transcribe audio.mp3 --stats-file stats.json` | Write perf stats JSON after transcription |
193| **Batch stats** | `./scripts/transcribe *.mp3 --stats-file ./stats/` | One stats file per input in dir |
194| **Template naming** | `./scripts/transcribe audio.mp3 -o ./out/ --output-template "{stem}_{lang}.{ext}"` | Custom batch output filenames |
195| **Stdin input** | `ffmpeg -i input.mp4 -f wav - \| ./scripts/transcribe -` | Pipe audio directly from stdin |
196| **Custom model dir** | `./scripts/transcribe audio.mp3 --model-dir ~/my-models` | Custom HuggingFace cache dir |
197| **Local model** | `./scripts/transcribe audio.mp3 -m ./my-model-ct2` | CTranslate2 model dir |
198| **HTML transcript** | `./scripts/transcribe audio.mp3 --format html -o out.html` | Confidence-colored |
199| **Burn subtitles** | `./scripts/transcribe video.mp4 --burn-in output.mp4` | Requires ffmpeg + video input |
200| **Name speakers** | `./scripts/transcribe audio.mp3 --diarize --speaker-names "Alice,Bob"` | Replaces SPEAKER_1/2 |
201| **Filter hallucinations** | `./scripts/transcribe audio.mp3 --filter-hallucinations` | Removes artifacts |
202| **Keep temp files** | `./scripts/transcribe https://... --keep-temp` | For URL re-processing |
203| **Parallel batch** | `./scripts/transcribe *.mp3 --parallel 4 -o ./out/` | CPU multi-file |
204| **RTX 3070 recommended** | `./scripts/transcribe audio.mp3 --compute-type int8_float16` | Saves ~1GB VRAM, minimal quality loss |
205| **CPU thread count** | `./scripts/transcribe audio.mp3 --threads 8` | Force CPU thread count (default: auto) |
206| **Podcast RSS (latest 5)** | `./scripts/transcribe --rss https://feeds.example.com/podcast.xml` | Downloads & transcribes newest 5 episodes |
207| **Podcast RSS (all episodes)** | `./scripts/transcribe --rss https://... --rss-latest 0 -o ./episodes/` | All episodes, one file each |
208| **Podcast + SRT subtitles** | `./scripts/transcribe --rss https://... --format srt -o ./subs/` | Subtitle all episodes |
209| **Retry on failure** | `./scripts/transcribe *.mp3 --retries 3 -o ./out/` | Retry up to 3× with backoff on error |
210| **CSV output** | `./scripts/transcribe audio.mp3 --format csv -o out.csv` | Spreadsheet-ready with header row; properly quoted |
211| **CSV with speakers** | `./scripts/transcribe audio.mp3 --diarize --format csv -o out.csv` | Adds speaker column |
212| **Language map (inline)** | `./scripts/transcribe *.mp3 --language-map "interview*.mp3=en,lecture.wav=fr"` | Per-file language in batch |
213| **Language map (JSON)** | `./scripts/transcribe *.mp3 --language-map @langs.json` | JSON file: {"pattern": "lang"} |
214| **Batch with ETA** | `./scripts/transcribe *.mp3 -o ./out/` | Automatic ETA shown for each file in batch |
215| **TTML subtitles** | `./scripts/transcribe audio.mp3 --format ttml -o subtitles.ttml` | Broadcast-standard DFXP/TTML (Netflix, BBC, Amazon) |
216| **TTML with speaker labels** | `./scripts/transcribe audio.mp3 --diarize --format ttml -o subtitles.ttml` | Speaker-labeled TTML |
217| **Search transcript** | `./scripts/transcribe audio.mp3 --search "keyword"` | Find timestamps where keyword appears |
218| **Search to file** | `./scripts/transcribe audio.mp3 --search "keyword" -o results.txt` | Save search results |
219| **Fuzzy search** | `./scripts/transcribe audio.mp3 --search "aproximate" --search-fuzzy` | Approximate/partial matching |
220| **Detect chapters** | `./scripts/transcribe audio.mp3 --detect-chapters` | Auto-detect chapters from silence gaps |
221| **Chapter gap tuning** | `./scripts/transcribe audio.mp3 --detect-chapters --chapter-gap 5` | Chapters on gaps ≥5s (default: 8s) |
222| **Chapters to file** | `./scripts/transcribe audio.mp3 --detect-chapters --chapters-file ch.txt` | Save YouTube-format chapter list |
223| **Chapters JSON** | `./scripts/transcribe audio.mp3 --detect-chapters --chapter-format json` | Machine-readable chapter list |
224| **Export speaker audio** | `./scripts/transcribe audio.mp3 --diarize --export-speakers ./speakers/` | Save each speaker's audio to separate WAV files |
225| **Multi-format output** | `./scripts/transcribe audio.mp3 --format srt,text -o ./out/` | Write SRT + TXT in one pass |
226| **Remove filler words** | `./scripts/transcribe audio.mp3 --clean-filler` | Strip um/uh/er/ah/hmm and discourse markers |
227| **Left channel only** | `./scripts/transcribe audio.mp3 --channel left` | Extract left stereo channel before transcribing |
228| **Right channel only** | `./scripts/transcribe audio.mp3 --channel right` | Extract right stereo channel |
229| **Max chars per line** | `./scripts/transcribe audio.mp3 --format srt --max-chars-per-line 42` | Character-based subtitle wrapping |
230| **Detect paragraphs** | `./scripts/transcribe audio.mp3 --detect-paragraphs` | Insert paragraph breaks in text output |
231| **Paragraph gap tuning** | `./scripts/transcribe audio.mp3 --detect-paragraphs --paragraph-gap 5.0` | Tune gap threshold (default 3.0s) |
232
233## Model Selection
234
235Choose the right model for your needs:
236
237```dot
238digraph model_selection {
239 rankdir=LR;
240 node [shape=box, style=rounded];
241
242 start [label="Start", shape=doublecircle];
243 need_accuracy [label="Need maximum\naccuracy?", shape=diamond];
244 multilingual [label="Multilingual\ncontent?", shape=diamond];
245 resource_constrained [label="Resource\nconstraints?", shape=diamond];
246
247 large_v3 [label="large-v3\nor\nlarge-v3-turbo", style="rounded,filled", fillcolor=lightblue];
248 large_turbo [label="large-v3-turbo", style="rounded,filled", fillcolor=lightblue];
249 distil_large [label="distil-large-v3.5\n(default)", style="rounded,filled", fillcolor=lightgreen];
250 distil_medium [label="distil-medium.en", style="rounded,filled", fillcolor=lightyellow];
251 distil_small [label="distil-small.en", style="rounded,filled", fillcolor=lightyellow];
252
253 start -> need_accuracy;
254 need_accuracy -> large_v3 [label="yes"];
255 need_accuracy -> multilingual [label="no"];
256 multilingual -> large_turbo [label="yes"];
257 multilingual -> resource_constrained [label="no (English)"];
258 resource_constrained -> distil_small [label="mobile/edge"];
259 resource_constrained -> distil_medium [label="some limits"];
260 resource_constrained -> distil_large [label="no"];
261}
262```
263
264### Model Table
265
266#### Standard Models (Full Whisper)
267
268| Model | Size | Speed | Accuracy | Use Case |
269| ---------------------- | ----- | --------- | --------- | ---------------------------------- |
270| `tiny` / `tiny.en` | 39M | Fastest | Basic | Quick drafts |
271| `base` / `base.en` | 74M | Very fast | Good | General use |
272| `small` / `small.en` | 244M | Fast | Better | Most tasks |
273| `medium` / `medium.en` | 769M | Moderate | High | Quality transcription |
274| `large-v1/v2/v3` | 1.5GB | Slower | Best | Maximum accuracy |
275| `large-v3-turbo` | 809M | Fast | Excellent | High accuracy (slower than distil) |
276
277#### Distilled Models (~6x Faster, ~1% WER difference)
278
279| Model | Size | Speed vs Standard | Accuracy | Use Case |
280| ----------------------- | ---- | ----------------- | --------- | ---------------------------------- |
281| **`distil-large-v3.5`** | 756M | ~6.3x faster | 7.08% WER | **Default, best balance** |
282| `distil-large-v3` | 756M | ~6.3x faster | 7.53% WER | Previous default |
283| `distil-large-v2` | 756M | ~5.8x faster | 10.1% WER | Fallback |
284| `distil-medium.en` | 394M | ~6.8x faster | 11.1% WER | English-only, resource-constrained |
285| `distil-small.en` | 166M | ~5.6x faster | 12.1% WER | Mobile/edge devices |
286
287`.en` models are English-only and slightly faster/better for English content.
288
289> **Note for distil models:** HuggingFace recommends disabling `condition_on_previous_text` for all distil models to prevent repetition loops. The script **auto-applies** `--no-condition-on-previous-text` whenever a `distil-*` model is detected. Pass `--condition-on-previous-text` to override if needed.
290
291## Custom & Fine-tuned Models
292
293WhisperModel accepts local CTranslate2 model directories and HuggingFace repo names — no code changes needed.
294
295### Load a local CTranslate2 model
296
297```bash
298./scripts/transcribe audio.mp3 --model /path/to/my-model-ct2
299```
300
301### Convert a HuggingFace model to CTranslate2
302
303```bash
304pip install ctranslate2
305ct2-transformers-converter \
306 --model openai/whisper-large-v3 \
307 --output_dir whisper-large-v3-ct2 \
308 --copy_files tokenizer.json preprocessor_config.json \
309 --quantization float16
310./scripts/transcribe audio.mp3 --model ./whisper-large-v3-ct2
311```
312
313### Load a model by HuggingFace repo name (auto-downloads)
314
315```bash
316./scripts/transcribe audio.mp3 --model username/whisper-large-v3-ct2
317```
318
319### Custom model cache directory
320
321By default, models are cached in `~/.cache/huggingface/`. Use `--model-dir` to override:
322
323```bash
324./scripts/transcribe audio.mp3 --model-dir ~/my-models
325```
326
327## Setup
328
329### Linux / macOS / WSL2
330
331```bash
332# Base install (creates venv, installs deps, auto-detects GPU)
333./setup.sh
334
335# With speaker diarization support
336./setup.sh --diarize
337```
338
339Requirements:
340
341- Python 3.10+
342- ffmpeg is **not required** for basic transcription — PyAV (bundled with faster-whisper) handles audio decoding. ffmpeg is only needed for `--burn-in`, `--normalize`, and `--denoise`.
343- Optional: yt-dlp (for URL/YouTube input)
344- Optional: pyannote.audio (for `--diarize`, installed via `setup.sh --diarize`)
345
346### Platform Support
347
348| Platform | Acceleration | Speed |
349| ---------------------- | ------------ | ---------------- |
350| **Linux + NVIDIA GPU** | CUDA | ~20x realtime 🚀 |
351| **WSL2 + NVIDIA GPU** | CUDA | ~20x realtime 🚀 |
352| macOS Apple Silicon | CPU\* | ~3-5x realtime |
353| macOS Intel | CPU | ~1-2x realtime |
354| Linux (no GPU) | CPU | ~1x realtime |
355
356\*faster-whisper uses CTranslate2 which is CPU-only on macOS, but Apple Silicon is fast enough for practical use.
357
358### GPU Support (IMPORTANT!)
359
360The setup script auto-detects your GPU and installs PyTorch with CUDA. **Always use GPU if available** — CPU transcription is extremely slow.
361
362| Hardware | Speed | 9-min video |
363| -------------- | -------------- | ----------- |
364| RTX 3070 (GPU) | ~20x realtime | ~27 sec |
365| CPU (int8) | ~0.3x realtime | ~30 min |
366
367> **RTX 3070 tip**: Use `--compute-type int8_float16` for hybrid quantization — saves ~1GB VRAM with minimal quality loss. Ideal for running diarization alongside transcription.
368
369If setup didn't detect your GPU, manually install PyTorch with CUDA:
370
371```bash
372# For CUDA 12.x
373uv pip install --python .venv/bin/python torch --index-url https://download.pytorch.org/whl/cu121
374
375# For CUDA 11.x
376uv pip install --python .venv/bin/python torch --index-url https://download.pytorch.org/whl/cu118
377```
378
379- **WSL2 users**: Ensure you have the [NVIDIA CUDA drivers for WSL](https://docs.nvidia.com/cuda/wsl-user-guide/) installed on Windows
380
381## Usage
382
383```bash
384# Basic transcription
385./scripts/transcribe audio.mp3
386
387# SRT subtitles
388./scripts/transcribe audio.mp3 --format srt -o subtitles.srt
389
390# WebVTT subtitles
391./scripts/transcribe audio.mp3 --format vtt -o subtitles.vtt
392
393# Transcribe from YouTube URL
394./scripts/transcribe https://youtube.com/watch?v=dQw4w9WgXcQ --language en
395
396# Speaker diarization
397./scripts/transcribe meeting.wav --diarize
398
399# Diarized VTT subtitles
400./scripts/transcribe meeting.wav --diarize --format vtt -o meeting.vtt
401
402# Prime with domain terminology
403./scripts/transcribe lecture.mp3 --initial-prompt "Kubernetes, gRPC, PostgreSQL, NGINX"
404
405# Batch process a directory
406./scripts/transcribe ./recordings/ -o ./transcripts/
407
408# Batch with glob, skip already-done files
409./scripts/transcribe *.mp3 --skip-existing -o ./transcripts/
410
411# Filter low-confidence segments
412./scripts/transcribe noisy-audio.mp3 --min-confidence 0.6
413
414# JSON output with full metadata
415./scripts/transcribe audio.mp3 --format json -o result.json
416
417# Specify language (faster than auto-detect)
418./scripts/transcribe audio.mp3 --language en
419```
420
421## Options
422
423```
424Input:
425 AUDIO Audio file(s), directory, glob pattern, or URL
426 Accepts: mp3, wav, m4a, flac, ogg, webm, mp4, mkv, avi, wma, aac
427 URLs auto-download via yt-dlp (YouTube, direct links, etc.)
428
429Model & Language:
430 -m, --model NAME Whisper model (default: distil-large-v3.5; "turbo" = large-v3-turbo)
431 --revision REV Model revision (git branch/tag/commit) to pin a specific version
432 -l, --language CODE Language code, e.g. en, es, fr (auto-detects if omitted)
433 --initial-prompt TEXT Prompt to condition the model (terminology, formatting style)
434 --prefix TEXT Prefix to condition the first segment (e.g. known starting words)
435 --hotwords WORDS Space-separated hotwords to boost recognition
436 --translate Translate any language to English (instead of transcribing)
437 --multilingual Enable multilingual/code-switching mode (helps smaller models)
438 --hf-token TOKEN HuggingFace token for private/gated models and diarization
439 --model-dir PATH Custom model cache directory (default: ~/.cache/huggingface/)
440
441Output Format:
442 -f, --format FMT text | json | srt | vtt | tsv | lrc | html | ass | ttml (default: text)
443 Accepts comma-separated list: --format srt,text writes both in one pass
444 Multi-format requires -o <dir> when saving to files
445 --word-timestamps Include word-level timestamps (wav2vec2 aligned automatically)
446 --stream Output segments as they are transcribed (disables diarize/alignment)
447 --max-words-per-line N For SRT/VTT, split segments into sub-cues of at most N words
448 --max-chars-per-line N For SRT/VTT/ASS/TTML, split lines so each fits within N characters
449 Takes priority over --max-words-per-line when both are set
450 --clean-filler Remove hesitation fillers (um, uh, er, ah, hmm, hm) and discourse markers
451 (you know, I mean, you see) from transcript text. Off by default.
452 --detect-paragraphs Insert paragraph breaks (blank lines) in text output at natural boundaries.
453 A new paragraph starts when: silence gap ≥ --paragraph-gap, OR the previous
454 segment ends a sentence AND the gap ≥ 1.5s.
455 --paragraph-gap SEC Minimum silence gap in seconds to start a new paragraph (default: 3.0).
456 Used with --detect-paragraphs.
457 --channel {left,right,mix}
458 Stereo channel to transcribe: left (c0), right (c1), or mix (default: mix).
459 Extracts the channel via ffmpeg before transcription. Requires ffmpeg.
460 --merge-sentences Merge consecutive segments into sentence-level chunks
461 (improves SRT/VTT readability; groups by terminal punctuation or >2s gap)
462 -o, --output PATH Output file or directory (directory for batch mode)
463 --output-template TEMPLATE
464 Batch output filename template. Variables: {stem}, {lang}, {ext}, {model}
465 Example: "{stem}_{lang}.{ext}" → "interview_en.srt"
466
467Inference Tuning:
468 --beam-size N Beam search size; higher = more accurate but slower (default: 5)
469 --temperature T Sampling temperature or comma-separated fallback list, e.g.
470 '0.0' or '0.0,0.2,0.4' (default: faster-whisper's schedule)
471 --no-speech-threshold PROB
472 Probability threshold to mark segments as silence (default: 0.6)
473 --batch-size N Batched inference batch size (default: 8; reduce if OOM)
474 --no-vad Disable voice activity detection (on by default)
475 --vad-threshold T VAD speech probability threshold (default: 0.5)
476 --vad-neg-threshold T VAD negative threshold for ending speech (default: auto)
477 --vad-onset T Alias for --vad-threshold (legacy)
478 --vad-offset T Alias for --vad-neg-threshold (legacy)
479 --min-speech-duration MS Minimum speech segment duration in ms (default: 0)
480 --max-speech-duration SEC Maximum speech segment duration in seconds (default: unlimited)
481 --min-silence-duration MS Minimum silence before splitting a segment in ms (default: 2000)
482 --speech-pad MS Padding around speech segments in ms (default: 400)
483 --no-batch Disable batched inference (use standard WhisperModel)
484 --hallucination-silence-threshold SEC
485 Skip silent sections where model hallucinates (e.g. 1.0)
486 --no-condition-on-previous-text
487 Don't condition on previous text (reduces repetition/hallucination loops;
488 auto-enabled for distil models per HuggingFace recommendation)
489 --condition-on-previous-text
490 Force-enable conditioning on previous text (overrides auto-disable for distil models)
491 --compression-ratio-threshold RATIO
492 Filter segments above this compression ratio (default: 2.4)
493 --log-prob-threshold PROB
494 Filter segments below this avg log probability (default: -1.0)
495 --max-new-tokens N Maximum tokens per segment (prevents runaway generation)
496 --clip-timestamps RANGE
497 Transcribe specific time ranges: '30,60' or '0,30;60,90' (seconds)
498 --progress Show transcription progress bar
499 --best-of N Candidates when sampling with non-zero temperature (default: 5)
500 --patience F Beam search patience factor (default: 1.0)
501 --repetition-penalty F Penalty for repeated tokens (default: 1.0)
502 --no-repeat-ngram-size N Prevent n-gram repetitions of this size (default: 0 = off)
503
504Advanced Inference:
505 --no-timestamps Output text without timing info (faster; incompatible with
506 --word-timestamps, --format srt/vtt/tsv, --diarize)
507 --chunk-length N Audio chunk length in seconds for batched inference (default: auto)
508 --language-detection-threshold T
509 Confidence threshold for language auto-detection (default: 0.5)
510 --language-detection-segments N
511 Audio segments to sample for language detection (default: 1)
512 --length-penalty F Beam search length penalty; >1 favors longer, <1 favors shorter (default: 1.0)
513 --prompt-reset-on-temperature T
514 Reset initial prompt when temperature fallback hits threshold (default: 0.5)
515 --no-suppress-blank Disable blank token suppression (may help soft/quiet speech)
516
517
518…(truncated)