🎙 Transcript Studio
Transcribe any English video — any length — into SRT / TXT / VTT / JSON, with per-speaker labels you can rename (Speaker 1 → "Alice"). 100% local: no cloud, no API keys, no accounts.
Features
- 🗣 Transcription — faster-whisper
(offline, free) with Silero VAD for clean timestamps. English by default,
--language autoto detect. Multi-hour videos work; progress is shown live. - 👥 Speaker detection — a real speaker-verification model
(NeMo Titanet
via sherpa-onnx, ONNX, no torch)
embeds every transcript segment and clusters the voices. The ~40 MB model
downloads automatically on first use (cached in
%LOCALAPPDATA%\transcript-studio\models). If it can't be installed, the app falls back to lightweight mel-based voice profiles. Built for panels and interviews: auto-detects up to 6 speakers, or force an exact count up to 8 (host + 7 guests). - ✏️ Rename speakers — labels come as
Speaker 1/2/…ordered by first appearance; give them real names in the UI or with--renameand the names are baked into every exported file. - 📦 Exports — SRT and TXT (with timestamps + speaker names), plus WebVTT and JSON as extras. Subtitle cues are auto-split to ≤6 s / ≤110 chars.
- 🌐 Input — local video or audio files, uploads, or any URL (via yt-dlp).
- ⚡ Caching — re-runs of the same file are instant (transcript + embeddings are cached; changing names/speaker-count re-exports immediately).
Install
Requirements: Python 3.11+, FFmpeg on PATH.
cd D:\Cline\transcript-studio
# isolated env (recommended — uv can fetch Python 3.11 itself)
uv venv .venv --python 3.11
uv pip install -r requirements.txt -p "D:\Cline\transcript-studio\.venv\Scripts\python.exe"
uv pip install -e . -p "D:\Cline\transcript-studio\.venv\Scripts\python.exe" # adds the `transcript-studio` command
# or once published to PyPI:
# pip install transcript-studio
ImportError: DLL load failed ... onnxruntime_pybind11_state— this machine'sSystem32only has the 2015 MSVC runtime. Copy the newer set shipped with Python 3.13 next to the ONNX DLLs (no admin needed):$src = "$env:LOCALAPPDATA\Programs\Python\Python313" $dst = "D:\Cline\transcript-studio\.venv\Lib\site-packages\onnxruntime\capi" Copy-Item "$src\msvcp140*.dll","$src\vcruntime140*.dll","$src\concrt140.dll" $dst
Quick start
# UI (opens http://localhost:8502) — double-click the desktop shortcut
python -m transcript_studio ui
# CLI: SRT + TXT next to the video, auto speaker count
python -m transcript_studio run "C:\Videos\podcast.mp4"
# rename speakers, pick formats, force the speaker count
python -m transcript_studio run "C:\Videos\podcast.mp4" `
--rename "Speaker 1=Alice,Speaker 2=Bob" `
--speakers 2 --formats srt,txt,vtt,json -o D:\outputs
# long video: auto-parallel (up to 4 workers) is already the default
python -m transcript_studio run "D:\Videos\podcast-ep12.mp4"
# fastest possible local run (coarse cue timing) — combine batching + workers
python -m transcript_studio run "D:\Videos\podcast-ep12.mp4" --fast --workers 4
# trickier audio: bigger model (slower on CPU), English-only
python -m transcript_studio run "D:\Videos\noisy-panel.mp4" --model small.en --speakers 4
# from YouTube (audio-only download, fast)
python -m transcript_studio run "https://youtu.be/XXXX"
# options
python -m transcript_studio run --help
CLI flags (run)
| flag | default | meaning |
|---|---|---|
-o, --output |
next to input file | output folder |
--model |
base.en |
tiny(.en)/base(.en)/small(.en)/medium/distil-*/large-v3-turbo/large-v3 |
--language |
en |
language code, or auto |
--fast |
off | batched decoding: ≈40 % faster, but longer subtitle cues |
--batch-size |
0 (off) |
batched decode batch size (--fast implies 8) |
--workers |
0 (auto) |
parallel chunk workers: auto = 1 short clips, up to 4 for long videos |
--chunk-length |
30 |
decoding window seconds (fast mode); smaller = finer cues |
--speakers |
0 (auto) |
0 = auto-detect, 1–8 = force count (panels) |
--rename |
– | Speaker 1=Alice,Speaker 2=Bob (bare 1=Alice also works) |
--formats |
srt,txt |
any of srt,vtt,txt,json |
--no-vad |
off | keep quiet speech (no silence cut) |
--pause |
off | wait for Enter before exiting (used by the drag-&-drop shortcut) |
Speed (measured on this machine)
Measured on an Intel i5-8350U (4 cores / 8 threads, no GPU) with the default
base.en model — WER is word error rate against known ground truth:
| input | mode | speed | WER vs truth |
|---|---|---|---|
| 56 s clip | single process | 6.0× | 1.0 % |
| 9 min audio | single process | 2.9× | 1.36 % |
| 9 min audio | auto / --workers 4 |
8.4× | 0.97 % |
| 9 min audio | --workers 4 --fast |
16.9× | 3.20 % (coarse cues) |
What that means in practice:
- Short clips (up to ~8 min) run single-process — process overhead isn't worth it.
- Long videos automatically use 4 parallel workers (
--workers 0= auto): chunks are cut at the quietest point near the boundary, each chunk decodes 6 s of overlap on both sides, and only segments whose midpoint falls inside its keep-zone are merged back — so the result has neither gaps nor duplicates. Measured: ~3× faster and slightly more accurate than a single pass (0.97 % vs 1.36 % WER). --fastadds batched decoding (≈40 % faster on short audio; 16.9× combined with workers on long audio), but it produces longer subtitle cues whose inner timing is interpolated — good for a quick text transcript, not for precise subtitles (its text accuracy also drops a little: 3.2 % vs 1.0 % WER).- Close other heavy apps first. On this 4-core CPU, background processes (Streamlit servers, browsers, agents) can cut throughput by 2× or more — during testing one orphaned server alone was burning 2 full cores.
- Big models (
distil-large-v3,large-v3-turbo,large-v3) need a GPU to be fast — measured:distil-large-v3runs at 0.85× realtime on this CPU (slower than real time), whilebase.enruns at 6×.
If you need real speed: a cloud API key
This CPU has a hard ceiling of roughly 5–17× realtime. A hosted speech API removes it
entirely — e.g. Groq's whisper-large-v3-turbo (very fast, ~$0.04 per hour of audio)
or OpenAI's gpt-4o-transcribe-diarize (fast and speaker-labelled in one call).
There is no "Cline API" to call — Cline is this coding agent, not a speech service.
If you drop a key into the environment (GROQ_API_KEY / OPENAI_API_KEY), I can wire
a --backend groq|openai path into the app in a few minutes.
Tests
python -m pytest # 27 tests: exporters, clustering, embeddings, sources
tests/make_two_voice.py and tests/make_multi_voice.py synthesize 2- and
4-voice conversations with ground-truth turn timelines (edge-tts, needs
network); tests/eval_diarization.py scores the real pipeline against them —
see the panel table below.
Multi-speaker panels (3–4+ guests)
Works out of the box — leave Speakers = Auto, or pass the exact count when
you know it (--speakers 4, UI dropdown 1–8) to be extra safe:
python -m transcript_studio run "C:\Videos\panel.mp4" --speakers 4 --rename "1=Host,2=Ann,3=Ben,4=Chloe"
Measured on synthetic ground truth (same pipeline as production):
| clip | auto result | per-segment accuracy |
|---|---|---|
| 2 voices (1 F, 1 M) | 2 speakers | 100 % |
| 4 voices (2 F + 2 M, incl. short backchannels) | 4 speakers | 100 % |
| 1 voice (84 s) | 1 speaker | no false speakers |
| 30-min lecture (144 segments) | 1 speaker | no content-based false split |
Reproduce it yourself:
python tests/make_multi_voice.py # needs network (edge-tts) — builds a 4-voice clip
python tests/eval_diarization.py --audio tests/data/multi_voice.wav `
--truth tests/data/multi_voice.truth.json --speakers 4 --diagnose
Guidance: prefer Auto or the true count. Forcing a higher number than
reality doesn't mix people up — it just fragments one voice into two labels
(e.g. 8 labels for 4 people, each still internally consistent).
How speaker detection works (and its limits)
- Whisper segments are extended into the half-gaps around them (silence only — never a neighbour's speech), chunked to ≤30 s windows, and embedded by Titanet into 192-dim L2-normalized vectors.
- Vectors are clustered with k-means (deterministic); the speaker count comes
from silhouette scoring with a minimum-cluster guard, or is forced by
--speakers. - Labels are ordered by first appearance →
Speaker 1,Speaker 2, …
Embeddings are content-invariant, so short punchy lines from the same voice
stay together (a plain pitch/timbre heuristic could not tell that apart).
Honest limits: overlapping speech (several people talking at once) is assigned
to the dominant voice of that segment; Whisper may merge a very short
backchannel ("Agreed.") into the next turn — such segments go to the majority
speaker. Voices that are literally identical (clones) may merge; the fallback
mel profile is cruder — install sherpa-onnx (it's in requirements.txt) for
the good path.
Use it from another computer (MacBook / phone on the same Wi-Fi)
The UI is a local web server, so any device on your network can drive it — the heavy work still runs on this laptop.
- Start the server on the laptop — double-click
Start_Transcript_Studio.bat(binds0.0.0.0:8502, so it accepts connections from other devices). - Allow it through the firewall — once — double-click
Allow_LAN_access.batand accept the UAC prompt (adds an inbound TCP-8502 rule; needs administrator, which is why it's a separate file). - On the MacBook, open
http://192.168.0.203:8502(check the laptop's current Wi-Fi address withipconfig; it changes if the network does). Upload the audio/video → pick formats → download the .srt it produces.
Server settings live in .streamlit/config.toml (address = "0.0.0.0",
port = 8502, maxUploadSize = 4096 MB).
Away from home: install Tailscale on both
machines and sign in — the MacBook then reaches the laptop from anywhere at
http://<laptop-tailscale-name>:8502, still private to your own devices, and no
firewall rule or public URL is involved.
License
MIT — see LICENSE.
Metadata
Release files for transcript-studio 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| transcript_studio-0.1.0.tar.gz | 37.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| transcript_studio-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.9 kB
Release files / transcript_studio-0.1.0.tar.gz
| Download URL | transcript_studio-0.1.0.tar.gz |
|---|---|
| Size | 37.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab2a8645438005cf342a44718fa6de8c43deddd06fd52f19d5a01f3f1c14ff63
|
|
BLAKE2b-256 checksum How to use checksums |
6fb145aa80d7b0c4df138ce51d3fe32d5192ff5ecdef776c19e3d4d0ef8d07a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / transcript_studio-0.1.0-py3-none-any.whl
| Download URL | transcript_studio-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
93bb99881e74c9d46ed0576167a921092bde108be7857ff5292161494000f1b9
|
|
BLAKE2b-256 checksum How to use checksums |
3049a8a42d81c74aba90ceb6de5ceac9c8ec720fb05e21e6e7ed2be24172c0eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log