babelscribe 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {babelscribe-0.3.1 → babelscribe-0.3.2}/PKG-INFO +20 -1
  2. {babelscribe-0.3.1 → babelscribe-0.3.2}/README.md +234 -215
  3. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/__init__.py +1 -1
  4. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/mcp_server.py +139 -136
  5. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/PKG-INFO +20 -1
  6. {babelscribe-0.3.1 → babelscribe-0.3.2}/pyproject.toml +1 -1
  7. {babelscribe-0.3.1 → babelscribe-0.3.2}/LICENSE +0 -0
  8. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/__main__.py +0 -0
  9. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/align.py +0 -0
  10. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/api.py +0 -0
  11. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/backend.py +0 -0
  12. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/cli.py +0 -0
  13. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/hybrid.py +0 -0
  14. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/models.py +0 -0
  15. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/transcribe.py +0 -0
  16. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe/writers.py +0 -0
  17. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/SOURCES.txt +0 -0
  18. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/dependency_links.txt +0 -0
  19. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/entry_points.txt +0 -0
  20. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/requires.txt +0 -0
  21. {babelscribe-0.3.1 → babelscribe-0.3.2}/babelscribe.egg-info/top_level.txt +0 -0
  22. {babelscribe-0.3.1 → babelscribe-0.3.2}/setup.cfg +0 -0
  23. {babelscribe-0.3.1 → babelscribe-0.3.2}/tests/test_core.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: babelscribe
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Transcribe any audio/video in 99 languages on any GPU (AMD, NVIDIA, Intel via Vulkan; NVIDIA via CUDA; Apple via Metal) or CPU — whisper.cpp with batteries included.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/phonology024/babelscribe
@@ -251,6 +251,25 @@ them to each `v*` release. Point `BABELSCRIBE_RELEASES` at another URL to self-h
251
251
  ภาษาไทยแนะนำ `babelscribe ไฟล์.mp4 -l th --accurate` — ข้อความจาก Pathumma Whisper (NECTEC) ที่ผิดน้อยที่สุดใน FLEURS (CER 8.9% เทียบ turbo 15.9%) + เวลาจาก large-v3-turbo
252
252
  หรือเลือก Thonburian Whisper เอง: `--text-model thai-thonburian`
253
253
 
254
+ ## Privacy Policy
255
+ babelscribe runs entirely on your own computer. Last updated 2026-10-06.
256
+
257
+ - **Data collection:** none. babelscribe has no telemetry, analytics, accounts or crash reporting, and never uploads your
258
+ audio, video, transcripts or file names anywhere.
259
+ - **What it processes and where:** the media file you choose is converted and transcribed locally; subtitles and text are
260
+ written to your disk (next to the file, or the folder you choose). Through MCP, the transcript text is returned to the AI
261
+ app that called the tool — what that app does with it is governed by that app's own privacy policy.
262
+ - **Network access (downloads only):** on first use it downloads the `whisper-cli` program from this project's GitHub
263
+ releases, speech models from Hugging Face (`huggingface.co/ggerganov/whisper.cpp`, and for `--accurate` Thai/Hindi the
264
+ fine-tune's own repository), and Python packages from PyPI when installed with pip/uv. These are plain downloads;
265
+ no personal data is sent. GitHub, Hugging Face and PyPI see a normal download request (IP address, user agent) under
266
+ their own privacy policies.
267
+ - **Storage and retention:** downloaded programs and models are cached in `~/.babelscribe` (or `BABELSCRIBE_HOME` /
268
+ `BABELSCRIBE_MODELS`) until you delete that folder. Outputs stay wherever they were written until you delete them.
269
+ babelscribe keeps no other data.
270
+ - **Third-party sharing:** none.
271
+ - **Contact:** open an issue at https://github.com/phonology024/babelscribe/issues
272
+
254
273
  ## Credits & licence
255
274
  MIT. Built on [whisper.cpp](https://github.com/ggml-org/whisper.cpp) (MIT) and OpenAI Whisper models (MIT).
256
275
  Fine-tunes belong to their authors: [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) by NECTEC,
@@ -1,215 +1,234 @@
1
- # babelscribe — free, offline speech-to-text and subtitles on any GPU (AMD, NVIDIA, Intel, Apple)
2
-
3
- <!-- mcp-name: io.github.phonology024/babelscribe -->
4
-
5
- [![PyPI](https://img.shields.io/pypi/v/babelscribe)](https://pypi.org/project/babelscribe/)
6
- [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
- [![MCP server](https://img.shields.io/badge/MCP-server-blue)](#use-it-from-an-ai-app-mcp--no-terminal-needed)
8
-
9
- **babelscribe turns any audio or video file into subtitles (SRT, VTT) and text, in any of Whisper's 99 languages, on your
10
- own graphics card — AMD Radeon, NVIDIA, Intel Arc or Apple Silicon — or the CPU. No CUDA needed, no cloud, free (MIT).**
11
- It runs OpenAI Whisper through [whisper.cpp](https://github.com/ggml-org/whisper.cpp) with Vulkan, CUDA or Metal, and works
12
- from the command line, from Python, or from AI apps (Claude, Codex, Antigravity, Gemini CLI, Cursor) as an MCP server.
13
-
14
- ```bash
15
- pip install babelscribe # Python 3.9+
16
- babelscribe interview.mp4 # auto-detects language, picks your best GPU -> interview.srt + interview.json
17
- ```
18
-
19
- babelscribe is a thin, friendly layer on top of [whisper.cpp](https://github.com/ggml-org/whisper.cpp). It exists because
20
- getting fast Whisper on a non-NVIDIA card (e.g. an AMD Radeon on Windows) still means building whisper.cpp with the
21
- Vulkan SDK yourself. babelscribe downloads a prebuilt `whisper-cli` for your system and handles the rest.
22
-
23
- | Your hardware | Backend used | Prebuilt asset |
24
- |---|---|---|
25
- | AMD / NVIDIA / Intel GPU on Windows | Vulkan | `windows-x64-vulkan` |
26
- | NVIDIA on Windows | Vulkan (same build) | `windows-x64-vulkan` |
27
- | NVIDIA on Linux (alternative) | CUDA | `linux-x64-cuda` (`--flavor cuda`) |
28
- | AMD / NVIDIA / Intel GPU on Linux | Vulkan | `linux-x64-vulkan` |
29
- | Apple Silicon | Metal | `macos-arm64-metal` |
30
- | No usable GPU | CPU | `*-cpu` (`--flavor cpu`) |
31
-
32
- A 19-minute English TED talk transcribes in 48 seconds on an AMD Radeon RX 9070 XT with 1.5% word error — see the benchmark below.
33
-
34
- ## Use it from an AI app (MCP) — no terminal needed
35
- babelscribe is also an [MCP](https://modelcontextprotocol.io) server, so any AI app that supports local MCP servers can
36
- transcribe files on **your** computer with **your** GPU. Ask in plain words — *"make Thai subtitles for the newest video in
37
- my Downloads"* — and the app finds the file, transcribes it, writes `.srt` / `.txt` next to it, and can then proofread names,
38
- translate or summarise the text for you.
39
-
40
- Tools: `transcribe` (file → subtitles + text), `find_media` (newest audio/video in Downloads, Videos, Desktop, …),
41
- `list_devices`, `list_languages_and_models`.
42
-
43
- **Claude Desktop (one click):** download `babelscribe.mcpb` from the [latest release](https://github.com/phonology024/babelscribe/releases/latest)
44
- and double-click it (or *Settings → Extensions → Install extension*).
45
-
46
- **Everything else** runs the same command — [uv](https://docs.astral.sh/uv/) fetches babelscribe for you:
47
- `uvx babelscribe mcp`
48
-
49
- | App | How to add it |
50
- |---|---|
51
- | Claude Code | `claude mcp add babelscribe -- uvx babelscribe mcp` |
52
- | OpenAI Codex CLI | `codex mcp add babelscribe -- uvx babelscribe mcp`, then in `~/.codex/config.toml` under `[mcp_servers.babelscribe]` set `tool_timeout_sec = 3600` and `startup_timeout_sec = 120` (defaults are 60 s / 10 s — too short for a long video or the first model download) |
53
- | Google Antigravity | agent panel → ⋯ → *MCP Servers* → *Manage MCP Servers* → *View raw config*, add the JSON below |
54
- | Gemini CLI | add the JSON below to `~/.gemini/settings.json` |
55
- | Cursor | add the JSON below to `~/.cursor/mcp.json` |
56
- | VS Code (Copilot) | `.vscode/mcp.json`: same entry under `"servers"` with `"type": "stdio"` |
57
-
58
- ```json
59
- {
60
- "mcpServers": {
61
- "babelscribe": { "command": "uvx", "args": ["babelscribe", "mcp"], "timeout": 3600000 }
62
- }
63
- }
64
- ```
65
- (`timeout` is in milliseconds and only some apps read it.) Already installed with pip? Use `"command": "babelscribe", "args": ["mcp"]`.
66
- Web-only chat apps (e.g. grok.com, chatgpt.com) can only reach servers on the internet, not your computer, so they can't use your GPU or files.
67
-
68
- ## Benchmark: real talks, human captions as the answer key
69
- Four TED / TEDx talks, scored against the **human-made captions in the spoken language** (`bench/bench.py`, reproducible).
70
- Error = word error rate (WER) for space-separated languages, character error rate (CER) for Japanese and Thai.
71
- GPU: AMD Radeon RX 9070 XT via Vulkan. *default* = `large-v3-turbo`; *accurate* = `--accurate` (see the FLEURS section).
72
-
73
- | Language | Talk | Length | default: time / error | `--accurate`: time / error |
74
- |---|---|---|---|---|
75
- | English | [Matt Walker — Sleep Is Your Superpower (TED)](https://youtu.be/5MuIMqhT8DM) | 19.3 min | 48 s (24x) · WER **1.5%** | 107 s (11x) · WER **1.5%** |
76
- | Japanese | [Kazunari Taguchi (TEDxHimi)](https://youtu.be/cjtmDEG-B7U) | 16.2 min | 47 s (20x) · CER 4.7% | 115 s (8x) · CER **4.2%** |
77
- | Spanish | [Adrià Solà Pastor — Cómo hablar (TEDxESIC University)](https://youtu.be/XUqrvbsTfck) | 19.9 min | 56 s (21x) · WER 13.8% | 134 s (9x) · WER 13.5% |
78
- | Thai | [นิติ ชัยชิตาทร — โปรดเรียกฉันด้วยนามอันแท้จริง (TEDxBangkok)](https://youtu.be/48A9SU6_bQ8) | 14.1 min | 74 s (12x) · CER 22.7% | 565 s (2x) · CER **16.4%** |
79
-
80
- How to read it: TED captions are edited for reading (fillers dropped, light rewording), so these numbers are an upper bound —
81
- most of the Spanish "errors" are the speaker's actual words versus the tidied caption. Thai is genuinely harder: fast,
82
- casual speech with slang; `--accurate` (Pathumma Whisper text + turbo timing) cuts its error by more than a quarter.
83
- Talks are used only to measure accuracy; their transcripts are not redistributed (TED content is CC BY-NC-ND).
84
-
85
- ## Benchmark: 16 languages on FLEURS
86
- [Google FLEURS](https://huggingface.co/datasets/google/fleurs) test set, 50 utterances per language, human-verified
87
- verbatim transcripts (`bench/fleurs.py`, reproducible). Same normaliser for every language (Whisper's rule: lower-case,
88
- drop punctuation and non-spacing marks, numbers spelled out). WER for space-separated languages, CER for ja / zh / ko / th.
89
-
90
- | Language | default (turbo) | `--accurate` | model `--accurate` uses | `--accurate`, edge-trimmed* |
91
- |---|---|---|---|---|
92
- | English | 6.1% | 5.7% | large-v3, beam 5 | 5.6% |
93
- | Spanish | 4.1% | 4.2% | large-v3, beam 5 | **2.6%** |
94
- | French | 7.4% | 7.3% | large-v3, beam 5 | 7.2% |
95
- | German | 4.3% | 4.0% | large-v3, beam 5 | **3.3%** |
96
- | Portuguese | 8.5% | 7.7% | large-v3, beam 5 | 5.3% |
97
- | Italian | 6.7% | 6.5% | large-v3, beam 5 | **3.8%** |
98
- | Russian | 6.8% | 5.8% | large-v3, beam 5 | 5.6% |
99
- | Arabic | 11.0% | 10.6% | large-v3, beam 5 | 9.7% |
100
- | Hindi | 28.4% | **12.6%** | [vasista22/whisper-hindi-large-v2](https://huggingface.co/vasista22/whisper-hindi-large-v2) + turbo timing | 11.1% |
101
- | Indonesian | 9.8% | 7.8% | large-v3, beam 5 | 5.6% |
102
- | Vietnamese | 10.8% | 9.1% | large-v3, beam 5 | 9.1% |
103
- | Turkish | 6.2% | 6.7% | large-v3, beam 5 | 5.8% |
104
- | Japanese (CER) | 6.4% | 5.7% | large-v3, beam 5 | **4.6%** |
105
- | Chinese (CER) | 6.3% | 5.3% | large-v3, beam 5 | **4.8%** |
106
- | Korean (CER) | 4.1% | 3.9% | large-v3, beam 5 | **3.1%** |
107
- | Thai (CER) | 15.9% | **8.9%** | [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) (NECTEC) + turbo timing | 8.8% |
108
-
109
- \* Some FLEURS clips contain more speech than their reference transcript, so a correct model is charged for words the
110
- reference leaves out. *Edge-trimmed* ignores extra words before the first / after the last reference word; both numbers
111
- are stored by `bench/fleurs.py`. 50 utterances per language means differences under ~0.5 points are noise.
112
-
113
- Also measured and **not** used, because large-v3 was as good or better: large-v2 (all languages),
114
- PhoWhisper-large (vi 19.0%), whisper-large-v3 dialectal / code-switching Arabic fine-tunes (12.2% / 15.2%),
115
- Typhoon Whisper (th 11.9%), Thonburian Whisper (th 9.1% — kept as an option), Vaani Hindi (16.5%).
116
-
117
- ## Why babelscribe (vs. what already exists)
118
- | | GPU on AMD / Intel | Windows, no build step | Video in, subtitles out | Long files don't loop | Better text for your language |
119
- |---|---|---|---|---|---|
120
- | **babelscribe** | ✅ Vulkan | ✅ prebuilt `whisper-cli` downloaded for you | ✅ ffmpeg bundled | ✅ `--max-context 0` by default | ✅ hybrid fine-tune text + turbo timing |
121
- | whisper.cpp (raw) | ✅ Vulkan — if you compile it | ❌ official releases ship no Windows Vulkan build | ❌ WAV 16 kHz only | ⚠️ you must know the flag | ❌ |
122
- | faster-whisper / WhisperX | ❌ GPU = NVIDIA CUDA only | ✅ pip | ✅ | ⚠️ | ⚠️ manual |
123
- | Cloud APIs | n/a (cloud) | ✅ | ✅ | ✅ | ❌ — and your audio leaves your machine, paid per minute |
124
-
125
- babelscribe does **not** replace those projects — it stands on whisper.cpp and simply removes the hard parts:
126
- compiling for your GPU, converting media, picking the right device, avoiding the long-file repeat bug, and combining
127
- a language-specific fine-tune with accurate timestamps.
128
-
129
- ## FAQ
130
- **How do I run Whisper on an AMD GPU on Windows?**
131
- `pip install babelscribe`, then `babelscribe video.mp4`. It downloads a Vulkan build of whisper.cpp that runs on AMD Radeon
132
- (and Intel Arc / NVIDIA) cards on Windows and Linux — no ROCm, no CUDA, no compiling.
133
-
134
- **How do I make subtitles (SRT) from a video for free, offline?**
135
- `babelscribe video.mp4 -f srt` writes `video.srt` next to the video. Nothing is uploaded; it runs on your own computer.
136
-
137
- **What is the most accurate free transcription for Thai?**
138
- `babelscribe video.mp4 -l th --accurate` — Pathumma Whisper (NECTEC) for the text plus Whisper turbo for timing:
139
- CER 8.9% on Google FLEURS vs 15.9% for plain Whisper turbo. Thonburian Whisper is available too (`--text-model thai-thonburian`).
140
-
141
- **Can Claude / ChatGPT Codex / Gemini transcribe a video on my computer?**
142
- Yes — add babelscribe as an MCP server (see *Use it from an AI app*). Claude Desktop installs it with one click from
143
- `babelscribe.mcpb`. The AI app can then find a file, transcribe it on your GPU, and proofread, translate or summarise the text.
144
-
145
- **How fast is it?**
146
- About 20x real time with Whisper large-v3-turbo on an AMD Radeon RX 9070 XT: a 19-minute talk in 48 seconds.
147
-
148
- **Which languages are supported?**
149
- All 99 Whisper languages, with automatic language detection. FLEURS error rates for 16 of them are in the benchmark table.
150
-
151
- **Is it better than faster-whisper or WhisperX?**
152
- Those are excellent on NVIDIA GPUs; on AMD / Intel GPUs they fall back to the CPU. babelscribe's niche is any GPU, zero setup,
153
- and better Thai / Hindi through community fine-tunes. If you have an NVIDIA card and like Python, faster-whisper is a fine choice.
154
-
155
- ## Languages
156
- All 99 languages Whisper was trained on, auto-detected or forced with `-l`:
157
- af am ar as az ba be bg bn bo br bs ca cs cy da de el en es et eu fa fi fo fr gl gu ha haw he hi hr ht hu hy id is it ja jw ka kk km kn ko la lb ln lo lt lv mg mi mk ml mn mr ms mt my ne nl nn no oc pa pl ps pt ro ru sa sd si sk sl sn so sq sr su sv sw ta te tg th tk tl tr tt uk ur uz vi yi yo yue zh
158
-
159
- Accuracy follows Whisper's own training data: excellent for high-resource languages (English, Spanish, Japanese, …),
160
- weaker for low-resource ones. That is what hybrid mode is for — a community fine-tune for one language can be plugged in
161
- with one line in `babelscribe/models.py` (Thai and Hindi so far). PRs adding fine-tunes for other
162
- languages are the most valuable contribution.
163
-
164
- ## Limitations (honest)
165
- - Tested end to end so far on an AMD Radeon RX 9070 XT (Windows, Vulkan). CUDA, Linux and macOS builds are produced by CI; reports from those machines are welcome.
166
- - Hybrid mode runs two models, so it is slower (≈1 min per minute of audio with a large fine-tune on that GPU).
167
- - Proper nouns can still be misspelled — check names before publishing subtitles.
168
-
169
- ## Features
170
- - **Any input** — mp4, mkv, mov, mp3, wav, m4a… (ffmpeg is bundled through `imageio-ffmpeg`).
171
- - **Any language** — `-l auto` detects it; or pass `-l th`, `-l ja`, `-l es`…
172
- - **Picks the right GPU** — prefers a discrete card over an integrated one; `babelscribe devices` lists them, `--device N` overrides.
173
- - **Long files that don't loop** — runs whisper with `--max-context 0`, which stops the classic "same sentence repeated forever" hallucination on long recordings.
174
- - **Hybrid mode for better spelling in your language** — community fine-tunes (e.g. Thai *Thonburian Whisper*) spell far better but often lose timestamps. `--text-model` takes the text from the fine-tune and the timing from `large-v3-turbo`, aligned character by character (works for languages without spaces), cut only at word boundaries, with the timing model filling any words the fine-tune skipped.
175
- - **`--accurate`** — slower, fewest errors: large-v3 with beam search, or for Thai and Hindi the best community fine-tune (hybrid). Chosen per language from the FLEURS benchmark above.
176
- - **Outputs** — `srt`, `vtt`, `txt`, `json` (segments with token timings).
177
-
178
- ## Usage
179
- ```bash
180
- babelscribe talk.mp4 -f srt,vtt,txt,json # all formats
181
- babelscribe podcast.mp3 -l en -m large-v3 # pick language and model
182
- babelscribe talk.mp4 -l hi --accurate # slower, fewest errors (best model per language)
183
- babelscribe vo.wav -l th --text-model thai-thonburian # hybrid: pick a Thai fine-tune yourself
184
- babelscribe devices # GPUs whisper.cpp can see
185
- babelscribe models # models and fine-tunes
186
- babelscribe talk.mp4 --bin /path/to/whisper-cli # use your own whisper.cpp build
187
- ```
188
- From Python:
189
- ```python
190
- from babelscribe.api import transcribe_file
191
- r = transcribe_file("talk.mp4", lang="auto", formats=["srt", "txt"]) # or accurate=True
192
- print(r["lang"], r["device"], r["files"]); print(r["text"][:200])
193
- ```
194
- Models download on first use to `~/.babelscribe/models` (`BABELSCRIBE_MODELS` to change). Hybrid fine-tunes are converted on your
195
- machine from their original Hugging Face repo — install `pip install "babelscribe[finetune]"` once; converted weights are never
196
- redistributed, so each fine-tune keeps its own licence. Thai word boundaries: `pip install "babelscribe[thai]"`.
197
-
198
- ## Add a language fine-tune
199
- Add one entry to `FINETUNES` in `babelscribe/models.py` (Hugging Face repo, language code, whether it needs beam search) and open a PR.
200
-
201
- ## Prebuilt binaries
202
- `.github/workflows/build-binaries.yml` builds `whisper-cli` + `whisper-quantize` for every row of the table above and attaches
203
- them to each `v*` release. Point `BABELSCRIBE_RELEASES` at another URL to self-host.
204
-
205
- ## ภาษาไทย
206
- ใช้ผ่าน Claude Desktop ได้โดยไม่ต้องพิมพ์คำสั่ง: โหลด `babelscribe.mcpb` จากหน้า Releases แล้วดับเบิลคลิก จากนั้นพิมพ์ในแชทว่า *"ทำซับไทยให้คลิปล่าสุดในโฟลเดอร์ดาวน์โหลด"*
207
- ถอดเสียงจากไฟล์เสียงหรือวิดีโอได้ทุกภาษา บนการ์ดจอทุกยี่ห้อ (AMD / NVIDIA / Intel ผ่าน Vulkan, Apple ผ่าน Metal) หรือ CPU
208
- ภาษาไทยแนะนำ `babelscribe ไฟล์.mp4 -l th --accurate` — ข้อความจาก Pathumma Whisper (NECTEC) ที่ผิดน้อยที่สุดใน FLEURS (CER 8.9% เทียบ turbo 15.9%) + เวลาจาก large-v3-turbo
209
- หรือเลือก Thonburian Whisper เอง: `--text-model thai-thonburian`
210
-
211
- ## Credits & licence
212
- MIT. Built on [whisper.cpp](https://github.com/ggml-org/whisper.cpp) (MIT) and OpenAI Whisper models (MIT).
213
- Fine-tunes belong to their authors: [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) by NECTEC,
214
- [Thonburian Whisper](https://huggingface.co/biodatlab/whisper-th-large-v3-combined) by biodatlab,
215
- [whisper-hindi-large-v2](https://huggingface.co/vasista22/whisper-hindi-large-v2) by vasista22 (Speech Lab, IIT Madras).
1
+ # babelscribe — free, offline speech-to-text and subtitles on any GPU (AMD, NVIDIA, Intel, Apple)
2
+
3
+ <!-- mcp-name: io.github.phonology024/babelscribe -->
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/babelscribe)](https://pypi.org/project/babelscribe/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
+ [![MCP server](https://img.shields.io/badge/MCP-server-blue)](#use-it-from-an-ai-app-mcp--no-terminal-needed)
8
+
9
+ **babelscribe turns any audio or video file into subtitles (SRT, VTT) and text, in any of Whisper's 99 languages, on your
10
+ own graphics card — AMD Radeon, NVIDIA, Intel Arc or Apple Silicon — or the CPU. No CUDA needed, no cloud, free (MIT).**
11
+ It runs OpenAI Whisper through [whisper.cpp](https://github.com/ggml-org/whisper.cpp) with Vulkan, CUDA or Metal, and works
12
+ from the command line, from Python, or from AI apps (Claude, Codex, Antigravity, Gemini CLI, Cursor) as an MCP server.
13
+
14
+ ```bash
15
+ pip install babelscribe # Python 3.9+
16
+ babelscribe interview.mp4 # auto-detects language, picks your best GPU -> interview.srt + interview.json
17
+ ```
18
+
19
+ babelscribe is a thin, friendly layer on top of [whisper.cpp](https://github.com/ggml-org/whisper.cpp). It exists because
20
+ getting fast Whisper on a non-NVIDIA card (e.g. an AMD Radeon on Windows) still means building whisper.cpp with the
21
+ Vulkan SDK yourself. babelscribe downloads a prebuilt `whisper-cli` for your system and handles the rest.
22
+
23
+ | Your hardware | Backend used | Prebuilt asset |
24
+ |---|---|---|
25
+ | AMD / NVIDIA / Intel GPU on Windows | Vulkan | `windows-x64-vulkan` |
26
+ | NVIDIA on Windows | Vulkan (same build) | `windows-x64-vulkan` |
27
+ | NVIDIA on Linux (alternative) | CUDA | `linux-x64-cuda` (`--flavor cuda`) |
28
+ | AMD / NVIDIA / Intel GPU on Linux | Vulkan | `linux-x64-vulkan` |
29
+ | Apple Silicon | Metal | `macos-arm64-metal` |
30
+ | No usable GPU | CPU | `*-cpu` (`--flavor cpu`) |
31
+
32
+ A 19-minute English TED talk transcribes in 48 seconds on an AMD Radeon RX 9070 XT with 1.5% word error — see the benchmark below.
33
+
34
+ ## Use it from an AI app (MCP) — no terminal needed
35
+ babelscribe is also an [MCP](https://modelcontextprotocol.io) server, so any AI app that supports local MCP servers can
36
+ transcribe files on **your** computer with **your** GPU. Ask in plain words — *"make Thai subtitles for the newest video in
37
+ my Downloads"* — and the app finds the file, transcribes it, writes `.srt` / `.txt` next to it, and can then proofread names,
38
+ translate or summarise the text for you.
39
+
40
+ Tools: `transcribe` (file → subtitles + text), `find_media` (newest audio/video in Downloads, Videos, Desktop, …),
41
+ `list_devices`, `list_languages_and_models`.
42
+
43
+ **Claude Desktop (one click):** download `babelscribe.mcpb` from the [latest release](https://github.com/phonology024/babelscribe/releases/latest)
44
+ and double-click it (or *Settings → Extensions → Install extension*).
45
+
46
+ **Everything else** runs the same command — [uv](https://docs.astral.sh/uv/) fetches babelscribe for you:
47
+ `uvx babelscribe mcp`
48
+
49
+ | App | How to add it |
50
+ |---|---|
51
+ | Claude Code | `claude mcp add babelscribe -- uvx babelscribe mcp` |
52
+ | OpenAI Codex CLI | `codex mcp add babelscribe -- uvx babelscribe mcp`, then in `~/.codex/config.toml` under `[mcp_servers.babelscribe]` set `tool_timeout_sec = 3600` and `startup_timeout_sec = 120` (defaults are 60 s / 10 s — too short for a long video or the first model download) |
53
+ | Google Antigravity | agent panel → ⋯ → *MCP Servers* → *Manage MCP Servers* → *View raw config*, add the JSON below |
54
+ | Gemini CLI | add the JSON below to `~/.gemini/settings.json` |
55
+ | Cursor | add the JSON below to `~/.cursor/mcp.json` |
56
+ | VS Code (Copilot) | `.vscode/mcp.json`: same entry under `"servers"` with `"type": "stdio"` |
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "babelscribe": { "command": "uvx", "args": ["babelscribe", "mcp"], "timeout": 3600000 }
62
+ }
63
+ }
64
+ ```
65
+ (`timeout` is in milliseconds and only some apps read it.) Already installed with pip? Use `"command": "babelscribe", "args": ["mcp"]`.
66
+ Web-only chat apps (e.g. grok.com, chatgpt.com) can only reach servers on the internet, not your computer, so they can't use your GPU or files.
67
+
68
+ ## Benchmark: real talks, human captions as the answer key
69
+ Four TED / TEDx talks, scored against the **human-made captions in the spoken language** (`bench/bench.py`, reproducible).
70
+ Error = word error rate (WER) for space-separated languages, character error rate (CER) for Japanese and Thai.
71
+ GPU: AMD Radeon RX 9070 XT via Vulkan. *default* = `large-v3-turbo`; *accurate* = `--accurate` (see the FLEURS section).
72
+
73
+ | Language | Talk | Length | default: time / error | `--accurate`: time / error |
74
+ |---|---|---|---|---|
75
+ | English | [Matt Walker — Sleep Is Your Superpower (TED)](https://youtu.be/5MuIMqhT8DM) | 19.3 min | 48 s (24x) · WER **1.5%** | 107 s (11x) · WER **1.5%** |
76
+ | Japanese | [Kazunari Taguchi (TEDxHimi)](https://youtu.be/cjtmDEG-B7U) | 16.2 min | 47 s (20x) · CER 4.7% | 115 s (8x) · CER **4.2%** |
77
+ | Spanish | [Adrià Solà Pastor — Cómo hablar (TEDxESIC University)](https://youtu.be/XUqrvbsTfck) | 19.9 min | 56 s (21x) · WER 13.8% | 134 s (9x) · WER 13.5% |
78
+ | Thai | [นิติ ชัยชิตาทร — โปรดเรียกฉันด้วยนามอันแท้จริง (TEDxBangkok)](https://youtu.be/48A9SU6_bQ8) | 14.1 min | 74 s (12x) · CER 22.7% | 565 s (2x) · CER **16.4%** |
79
+
80
+ How to read it: TED captions are edited for reading (fillers dropped, light rewording), so these numbers are an upper bound —
81
+ most of the Spanish "errors" are the speaker's actual words versus the tidied caption. Thai is genuinely harder: fast,
82
+ casual speech with slang; `--accurate` (Pathumma Whisper text + turbo timing) cuts its error by more than a quarter.
83
+ Talks are used only to measure accuracy; their transcripts are not redistributed (TED content is CC BY-NC-ND).
84
+
85
+ ## Benchmark: 16 languages on FLEURS
86
+ [Google FLEURS](https://huggingface.co/datasets/google/fleurs) test set, 50 utterances per language, human-verified
87
+ verbatim transcripts (`bench/fleurs.py`, reproducible). Same normaliser for every language (Whisper's rule: lower-case,
88
+ drop punctuation and non-spacing marks, numbers spelled out). WER for space-separated languages, CER for ja / zh / ko / th.
89
+
90
+ | Language | default (turbo) | `--accurate` | model `--accurate` uses | `--accurate`, edge-trimmed* |
91
+ |---|---|---|---|---|
92
+ | English | 6.1% | 5.7% | large-v3, beam 5 | 5.6% |
93
+ | Spanish | 4.1% | 4.2% | large-v3, beam 5 | **2.6%** |
94
+ | French | 7.4% | 7.3% | large-v3, beam 5 | 7.2% |
95
+ | German | 4.3% | 4.0% | large-v3, beam 5 | **3.3%** |
96
+ | Portuguese | 8.5% | 7.7% | large-v3, beam 5 | 5.3% |
97
+ | Italian | 6.7% | 6.5% | large-v3, beam 5 | **3.8%** |
98
+ | Russian | 6.8% | 5.8% | large-v3, beam 5 | 5.6% |
99
+ | Arabic | 11.0% | 10.6% | large-v3, beam 5 | 9.7% |
100
+ | Hindi | 28.4% | **12.6%** | [vasista22/whisper-hindi-large-v2](https://huggingface.co/vasista22/whisper-hindi-large-v2) + turbo timing | 11.1% |
101
+ | Indonesian | 9.8% | 7.8% | large-v3, beam 5 | 5.6% |
102
+ | Vietnamese | 10.8% | 9.1% | large-v3, beam 5 | 9.1% |
103
+ | Turkish | 6.2% | 6.7% | large-v3, beam 5 | 5.8% |
104
+ | Japanese (CER) | 6.4% | 5.7% | large-v3, beam 5 | **4.6%** |
105
+ | Chinese (CER) | 6.3% | 5.3% | large-v3, beam 5 | **4.8%** |
106
+ | Korean (CER) | 4.1% | 3.9% | large-v3, beam 5 | **3.1%** |
107
+ | Thai (CER) | 15.9% | **8.9%** | [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) (NECTEC) + turbo timing | 8.8% |
108
+
109
+ \* Some FLEURS clips contain more speech than their reference transcript, so a correct model is charged for words the
110
+ reference leaves out. *Edge-trimmed* ignores extra words before the first / after the last reference word; both numbers
111
+ are stored by `bench/fleurs.py`. 50 utterances per language means differences under ~0.5 points are noise.
112
+
113
+ Also measured and **not** used, because large-v3 was as good or better: large-v2 (all languages),
114
+ PhoWhisper-large (vi 19.0%), whisper-large-v3 dialectal / code-switching Arabic fine-tunes (12.2% / 15.2%),
115
+ Typhoon Whisper (th 11.9%), Thonburian Whisper (th 9.1% — kept as an option), Vaani Hindi (16.5%).
116
+
117
+ ## Why babelscribe (vs. what already exists)
118
+ | | GPU on AMD / Intel | Windows, no build step | Video in, subtitles out | Long files don't loop | Better text for your language |
119
+ |---|---|---|---|---|---|
120
+ | **babelscribe** | ✅ Vulkan | ✅ prebuilt `whisper-cli` downloaded for you | ✅ ffmpeg bundled | ✅ `--max-context 0` by default | ✅ hybrid fine-tune text + turbo timing |
121
+ | whisper.cpp (raw) | ✅ Vulkan — if you compile it | ❌ official releases ship no Windows Vulkan build | ❌ WAV 16 kHz only | ⚠️ you must know the flag | ❌ |
122
+ | faster-whisper / WhisperX | ❌ GPU = NVIDIA CUDA only | ✅ pip | ✅ | ⚠️ | ⚠️ manual |
123
+ | Cloud APIs | n/a (cloud) | ✅ | ✅ | ✅ | ❌ — and your audio leaves your machine, paid per minute |
124
+
125
+ babelscribe does **not** replace those projects — it stands on whisper.cpp and simply removes the hard parts:
126
+ compiling for your GPU, converting media, picking the right device, avoiding the long-file repeat bug, and combining
127
+ a language-specific fine-tune with accurate timestamps.
128
+
129
+ ## FAQ
130
+ **How do I run Whisper on an AMD GPU on Windows?**
131
+ `pip install babelscribe`, then `babelscribe video.mp4`. It downloads a Vulkan build of whisper.cpp that runs on AMD Radeon
132
+ (and Intel Arc / NVIDIA) cards on Windows and Linux — no ROCm, no CUDA, no compiling.
133
+
134
+ **How do I make subtitles (SRT) from a video for free, offline?**
135
+ `babelscribe video.mp4 -f srt` writes `video.srt` next to the video. Nothing is uploaded; it runs on your own computer.
136
+
137
+ **What is the most accurate free transcription for Thai?**
138
+ `babelscribe video.mp4 -l th --accurate` — Pathumma Whisper (NECTEC) for the text plus Whisper turbo for timing:
139
+ CER 8.9% on Google FLEURS vs 15.9% for plain Whisper turbo. Thonburian Whisper is available too (`--text-model thai-thonburian`).
140
+
141
+ **Can Claude / ChatGPT Codex / Gemini transcribe a video on my computer?**
142
+ Yes — add babelscribe as an MCP server (see *Use it from an AI app*). Claude Desktop installs it with one click from
143
+ `babelscribe.mcpb`. The AI app can then find a file, transcribe it on your GPU, and proofread, translate or summarise the text.
144
+
145
+ **How fast is it?**
146
+ About 20x real time with Whisper large-v3-turbo on an AMD Radeon RX 9070 XT: a 19-minute talk in 48 seconds.
147
+
148
+ **Which languages are supported?**
149
+ All 99 Whisper languages, with automatic language detection. FLEURS error rates for 16 of them are in the benchmark table.
150
+
151
+ **Is it better than faster-whisper or WhisperX?**
152
+ Those are excellent on NVIDIA GPUs; on AMD / Intel GPUs they fall back to the CPU. babelscribe's niche is any GPU, zero setup,
153
+ and better Thai / Hindi through community fine-tunes. If you have an NVIDIA card and like Python, faster-whisper is a fine choice.
154
+
155
+ ## Languages
156
+ All 99 languages Whisper was trained on, auto-detected or forced with `-l`:
157
+ af am ar as az ba be bg bn bo br bs ca cs cy da de el en es et eu fa fi fo fr gl gu ha haw he hi hr ht hu hy id is it ja jw ka kk km kn ko la lb ln lo lt lv mg mi mk ml mn mr ms mt my ne nl nn no oc pa pl ps pt ro ru sa sd si sk sl sn so sq sr su sv sw ta te tg th tk tl tr tt uk ur uz vi yi yo yue zh
158
+
159
+ Accuracy follows Whisper's own training data: excellent for high-resource languages (English, Spanish, Japanese, …),
160
+ weaker for low-resource ones. That is what hybrid mode is for — a community fine-tune for one language can be plugged in
161
+ with one line in `babelscribe/models.py` (Thai and Hindi so far). PRs adding fine-tunes for other
162
+ languages are the most valuable contribution.
163
+
164
+ ## Limitations (honest)
165
+ - Tested end to end so far on an AMD Radeon RX 9070 XT (Windows, Vulkan). CUDA, Linux and macOS builds are produced by CI; reports from those machines are welcome.
166
+ - Hybrid mode runs two models, so it is slower (≈1 min per minute of audio with a large fine-tune on that GPU).
167
+ - Proper nouns can still be misspelled — check names before publishing subtitles.
168
+
169
+ ## Features
170
+ - **Any input** — mp4, mkv, mov, mp3, wav, m4a… (ffmpeg is bundled through `imageio-ffmpeg`).
171
+ - **Any language** — `-l auto` detects it; or pass `-l th`, `-l ja`, `-l es`…
172
+ - **Picks the right GPU** — prefers a discrete card over an integrated one; `babelscribe devices` lists them, `--device N` overrides.
173
+ - **Long files that don't loop** — runs whisper with `--max-context 0`, which stops the classic "same sentence repeated forever" hallucination on long recordings.
174
+ - **Hybrid mode for better spelling in your language** — community fine-tunes (e.g. Thai *Thonburian Whisper*) spell far better but often lose timestamps. `--text-model` takes the text from the fine-tune and the timing from `large-v3-turbo`, aligned character by character (works for languages without spaces), cut only at word boundaries, with the timing model filling any words the fine-tune skipped.
175
+ - **`--accurate`** — slower, fewest errors: large-v3 with beam search, or for Thai and Hindi the best community fine-tune (hybrid). Chosen per language from the FLEURS benchmark above.
176
+ - **Outputs** — `srt`, `vtt`, `txt`, `json` (segments with token timings).
177
+
178
+ ## Usage
179
+ ```bash
180
+ babelscribe talk.mp4 -f srt,vtt,txt,json # all formats
181
+ babelscribe podcast.mp3 -l en -m large-v3 # pick language and model
182
+ babelscribe talk.mp4 -l hi --accurate # slower, fewest errors (best model per language)
183
+ babelscribe vo.wav -l th --text-model thai-thonburian # hybrid: pick a Thai fine-tune yourself
184
+ babelscribe devices # GPUs whisper.cpp can see
185
+ babelscribe models # models and fine-tunes
186
+ babelscribe talk.mp4 --bin /path/to/whisper-cli # use your own whisper.cpp build
187
+ ```
188
+ From Python:
189
+ ```python
190
+ from babelscribe.api import transcribe_file
191
+ r = transcribe_file("talk.mp4", lang="auto", formats=["srt", "txt"]) # or accurate=True
192
+ print(r["lang"], r["device"], r["files"]); print(r["text"][:200])
193
+ ```
194
+ Models download on first use to `~/.babelscribe/models` (`BABELSCRIBE_MODELS` to change). Hybrid fine-tunes are converted on your
195
+ machine from their original Hugging Face repo — install `pip install "babelscribe[finetune]"` once; converted weights are never
196
+ redistributed, so each fine-tune keeps its own licence. Thai word boundaries: `pip install "babelscribe[thai]"`.
197
+
198
+ ## Add a language fine-tune
199
+ Add one entry to `FINETUNES` in `babelscribe/models.py` (Hugging Face repo, language code, whether it needs beam search) and open a PR.
200
+
201
+ ## Prebuilt binaries
202
+ `.github/workflows/build-binaries.yml` builds `whisper-cli` + `whisper-quantize` for every row of the table above and attaches
203
+ them to each `v*` release. Point `BABELSCRIBE_RELEASES` at another URL to self-host.
204
+
205
+ ## ภาษาไทย
206
+ ใช้ผ่าน Claude Desktop ได้โดยไม่ต้องพิมพ์คำสั่ง: โหลด `babelscribe.mcpb` จากหน้า Releases แล้วดับเบิลคลิก จากนั้นพิมพ์ในแชทว่า *"ทำซับไทยให้คลิปล่าสุดในโฟลเดอร์ดาวน์โหลด"*
207
+ ถอดเสียงจากไฟล์เสียงหรือวิดีโอได้ทุกภาษา บนการ์ดจอทุกยี่ห้อ (AMD / NVIDIA / Intel ผ่าน Vulkan, Apple ผ่าน Metal) หรือ CPU
208
+ ภาษาไทยแนะนำ `babelscribe ไฟล์.mp4 -l th --accurate` — ข้อความจาก Pathumma Whisper (NECTEC) ที่ผิดน้อยที่สุดใน FLEURS (CER 8.9% เทียบ turbo 15.9%) + เวลาจาก large-v3-turbo
209
+ หรือเลือก Thonburian Whisper เอง: `--text-model thai-thonburian`
210
+
211
+ ## Privacy Policy
212
+ babelscribe runs entirely on your own computer. Last updated 2026-10-06.
213
+
214
+ - **Data collection:** none. babelscribe has no telemetry, analytics, accounts or crash reporting, and never uploads your
215
+ audio, video, transcripts or file names anywhere.
216
+ - **What it processes and where:** the media file you choose is converted and transcribed locally; subtitles and text are
217
+ written to your disk (next to the file, or the folder you choose). Through MCP, the transcript text is returned to the AI
218
+ app that called the tool — what that app does with it is governed by that app's own privacy policy.
219
+ - **Network access (downloads only):** on first use it downloads the `whisper-cli` program from this project's GitHub
220
+ releases, speech models from Hugging Face (`huggingface.co/ggerganov/whisper.cpp`, and for `--accurate` Thai/Hindi the
221
+ fine-tune's own repository), and Python packages from PyPI when installed with pip/uv. These are plain downloads;
222
+ no personal data is sent. GitHub, Hugging Face and PyPI see a normal download request (IP address, user agent) under
223
+ their own privacy policies.
224
+ - **Storage and retention:** downloaded programs and models are cached in `~/.babelscribe` (or `BABELSCRIBE_HOME` /
225
+ `BABELSCRIBE_MODELS`) until you delete that folder. Outputs stay wherever they were written until you delete them.
226
+ babelscribe keeps no other data.
227
+ - **Third-party sharing:** none.
228
+ - **Contact:** open an issue at https://github.com/phonology024/babelscribe/issues
229
+
230
+ ## Credits & licence
231
+ MIT. Built on [whisper.cpp](https://github.com/ggml-org/whisper.cpp) (MIT) and OpenAI Whisper models (MIT).
232
+ Fine-tunes belong to their authors: [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) by NECTEC,
233
+ [Thonburian Whisper](https://huggingface.co/biodatlab/whisper-th-large-v3-combined) by biodatlab,
234
+ [whisper-hindi-large-v2](https://huggingface.co/vasista22/whisper-hindi-large-v2) by vasista22 (Speech Lab, IIT Madras).
@@ -1,2 +1,2 @@
1
1
  """babelscribe — any language, any GPU speech-to-text built on whisper.cpp."""
2
- __version__ = "0.3.1"
2
+ __version__ = "0.3.2"
@@ -1,136 +1,139 @@
1
- """babelscribe as an MCP server: any MCP client (Claude Desktop / Code, Codex, Antigravity, Gemini CLI, Cursor,
2
- VS Code, ...) can transcribe local audio/video on the user's own GPU.
3
-
4
- babelscribe mcp # stdio server; AI apps launch it themselves (see README "Use it from an AI app")
5
-
6
- Needs Python 3.10+ (the mcp SDK)."""
7
-
8
- import io
9
- import os
10
- import sys
11
- import time
12
- from pathlib import Path
13
-
14
- MEDIA = {".mp4", ".mkv", ".mov", ".avi", ".webm", ".m4v", ".mp3", ".wav", ".m4a", ".aac", ".flac", ".ogg", ".opus", ".wma"}
15
- TEXT_LIMIT = 30000 # characters of transcript returned to the model; the full text is always in the files
16
-
17
-
18
- def _guard_stdout():
19
- """stdout is the JSON-RPC channel. Keep a private handle to it for the protocol and point everything else
20
- (print, logging, stray library output) at stderr so it can never corrupt a message."""
21
- proto = io.TextIOWrapper(os.fdopen(os.dup(sys.stdout.fileno()), "wb"), encoding="utf-8", newline="\n",
22
- write_through=True)
23
- sys.stdout = sys.stderr
24
- return proto
25
-
26
-
27
- def build():
28
- import anyio
29
- from mcp.server.mcpserver import Context, MCPServer
30
-
31
- from . import __version__, api, backend, models
32
-
33
- srv = MCPServer("babelscribe", version=__version__, instructions=(
34
- "Local speech-to-text on the user's own GPU (AMD/NVIDIA/Intel/Apple) for 99 languages. Needs a file path on "
35
- "this computer: if the user only names or describes a file, call find_media first. Subtitles (.srt) and text "
36
- "(.txt) are written next to the media file unless output_dir is given. Use accurate=true when the user wants "
37
- "the fewest mistakes (slower); it is much better for Thai and Hindi. The first run downloads the model "
38
- "(~1.6 GB), so it can take a few minutes. After transcribing you can proofread names, translate, or "
39
- "summarise from the returned text."))
40
-
41
- @srv.tool()
42
- async def transcribe(file_path: str, language: str = "auto", accurate: bool = False, formats: str = "srt,txt",
43
- output_dir: str = "", ctx: Context | None = None) -> dict:
44
- """Transcribe a local audio or video file into subtitles / text.
45
-
46
- file_path: absolute path to the media file (mp4, mkv, mov, mp3, wav, m4a, ...).
47
- language: ISO code such as en, th, ja, es, hi — or "auto" to detect.
48
- accurate: slower, fewest errors (large-v3 with beam search, or the best fine-tune for Thai / Hindi).
49
- formats: comma list from srt, vtt, txt, json.
50
- output_dir: folder for the output files; empty = next to the media file.
51
- Returns the files written, detected language, device used, and the transcript text."""
52
- src = Path(file_path).expanduser()
53
- out = Path(output_dir).expanduser() / src.stem if output_dir else None
54
- if out:
55
- out.parent.mkdir(parents=True, exist_ok=True)
56
- fmts = [f.strip() for f in formats.split(",") if f.strip()]
57
- lines: list[str] = []
58
- done = anyio.Event()
59
-
60
- async def heartbeat(): # progress keeps clients from timing out on long files
61
- t0 = time.time()
62
- while not done.is_set():
63
- with anyio.move_on_after(5):
64
- await done.wait()
65
- if ctx and not done.is_set():
66
- await ctx.report_progress(time.time() - t0, None, lines[-1] if lines else "starting ...")
67
-
68
- result: dict = {}
69
- async with anyio.create_task_group() as tg:
70
- tg.start_soon(heartbeat)
71
- try:
72
- result = await anyio.to_thread.run_sync(lambda: api.transcribe_file(
73
- src, language, accurate=accurate, formats=fmts, out=out, log=lambda m: (lines.append(m), print(m))))
74
- finally:
75
- done.set()
76
- text = result.pop("text", "")
77
- result["text"] = text[:TEXT_LIMIT]
78
- if len(text) > TEXT_LIMIT:
79
- result["note"] = f"transcript truncated to {TEXT_LIMIT} characters; the full text is in the files listed"
80
- return result
81
-
82
- @srv.tool()
83
- def find_media(name_contains: str = "", folder: str = "", limit: int = 15) -> list[dict]:
84
- """Find audio/video files on this computer, newest first. Searches Downloads, Videos, Desktop, Music and
85
- Documents (two levels deep) unless folder is given. Use it when the user names a file without a full path."""
86
- home = Path.home()
87
- roots = [Path(folder).expanduser()] if folder else [home / d for d in ("Downloads", "Videos", "Desktop", "Music", "Documents", "Movies")]
88
- hits = []
89
- for r in roots:
90
- if not r.is_dir():
91
- continue
92
- for p in [*r.glob("*"), *r.glob("*/*"), *(r.glob("*/*/*") if folder else [])]:
93
- if p.suffix.lower() in MEDIA and name_contains.lower() in p.name.lower():
94
- try:
95
- st = p.stat()
96
- except OSError:
97
- continue
98
- hits.append((st.st_mtime, p, st.st_size))
99
- hits.sort(reverse=True)
100
- return [{"path": str(p), "size_mb": round(sz / 1e6, 1), "modified": time.strftime("%Y-%m-%d %H:%M", time.localtime(t))}
101
- for t, p, sz in hits[:limit]]
102
-
103
- @srv.tool()
104
- def list_devices() -> dict:
105
- """GPUs whisper.cpp can use on this computer and which one babelscribe picks automatically."""
106
- _, _, found = api.setup()
107
- return {"devices": found, "auto_pick": backend.pick_device(found)}
108
-
109
- @srv.tool()
110
- def list_languages_and_models() -> dict:
111
- """Models available, and which model --accurate uses per language."""
112
- return {"general": models.GENERAL, "fine_tunes": {k: v["note"] for k, v in models.FINETUNES.items()},
113
- "accurate_per_language": {**models.ACCURATE, "*": "large-v3 beam 5"}}
114
-
115
- return srv
116
-
117
-
118
- def main() -> None:
119
- try:
120
- import anyio
121
- from mcp.server.stdio import stdio_server
122
- except ImportError:
123
- raise SystemExit('the MCP server needs Python 3.10+ (the mcp SDK)')
124
- proto = _guard_stdout()
125
- srv = build()
126
-
127
- async def run():
128
- async with stdio_server(stdout=anyio.wrap_file(proto)) as (r, w):
129
- low = srv._lowlevel_server
130
- await low.run(r, w, low.create_initialization_options())
131
-
132
- anyio.run(run)
133
-
134
-
135
- if __name__ == "__main__":
136
- main()
1
+ """babelscribe as an MCP server: any MCP client (Claude Desktop / Code, Codex, Antigravity, Gemini CLI, Cursor,
2
+ VS Code, ...) can transcribe local audio/video on the user's own GPU.
3
+
4
+ babelscribe mcp # stdio server; AI apps launch it themselves (see README "Use it from an AI app")
5
+
6
+ Needs Python 3.10+ (the mcp SDK)."""
7
+
8
+ import io
9
+ import os
10
+ import sys
11
+ import time
12
+ from pathlib import Path
13
+
14
+ MEDIA = {".mp4", ".mkv", ".mov", ".avi", ".webm", ".m4v", ".mp3", ".wav", ".m4a", ".aac", ".flac", ".ogg", ".opus", ".wma"}
15
+ TEXT_LIMIT = 30000 # characters of transcript returned to the model; the full text is always in the files
16
+
17
+
18
+ def _guard_stdout():
19
+ """stdout is the JSON-RPC channel. Keep a private handle to it for the protocol and point everything else
20
+ (print, logging, stray library output) at stderr so it can never corrupt a message."""
21
+ proto = io.TextIOWrapper(os.fdopen(os.dup(sys.stdout.fileno()), "wb"), encoding="utf-8", newline="\n",
22
+ write_through=True)
23
+ sys.stdout = sys.stderr
24
+ return proto
25
+
26
+
27
+ def build():
28
+ import anyio
29
+ from mcp.server.mcpserver import Context, MCPServer
30
+ from mcp.types import ToolAnnotations
31
+
32
+ from . import __version__, api, backend, models
33
+
34
+ srv = MCPServer("babelscribe", version=__version__, instructions=(
35
+ "Local speech-to-text on the user's own GPU (AMD/NVIDIA/Intel/Apple) for 99 languages. Needs a file path on "
36
+ "this computer: if the user only names or describes a file, call find_media first. Subtitles (.srt) and text "
37
+ "(.txt) are written next to the media file unless output_dir is given. Use accurate=true when the user wants "
38
+ "the fewest mistakes (slower); it is much better for Thai and Hindi. The first run downloads the model "
39
+ "(~1.6 GB), so it can take a few minutes. After transcribing you can proofread names, translate, or "
40
+ "summarise from the returned text."))
41
+
42
+ # transcribe writes new .srt/.txt files (re-running rewrites its own output); first use downloads whisper-cli and the model
43
+ @srv.tool(title="Transcribe audio/video to subtitles", annotations=ToolAnnotations(
44
+ read_only_hint=False, destructive_hint=False, idempotent_hint=True, open_world_hint=True))
45
+ async def transcribe(file_path: str, language: str = "auto", accurate: bool = False, formats: str = "srt,txt",
46
+ output_dir: str = "", ctx: Context | None = None) -> dict:
47
+ """Transcribe a local audio or video file into subtitles / text.
48
+
49
+ file_path: absolute path to the media file (mp4, mkv, mov, mp3, wav, m4a, ...).
50
+ language: ISO code such as en, th, ja, es, hi — or "auto" to detect.
51
+ accurate: slower, fewest errors (large-v3 with beam search, or the best fine-tune for Thai / Hindi).
52
+ formats: comma list from srt, vtt, txt, json.
53
+ output_dir: folder for the output files; empty = next to the media file.
54
+ Returns the files written, detected language, device used, and the transcript text."""
55
+ src = Path(file_path).expanduser()
56
+ out = Path(output_dir).expanduser() / src.stem if output_dir else None
57
+ if out:
58
+ out.parent.mkdir(parents=True, exist_ok=True)
59
+ fmts = [f.strip() for f in formats.split(",") if f.strip()]
60
+ lines: list[str] = []
61
+ done = anyio.Event()
62
+
63
+ async def heartbeat(): # progress keeps clients from timing out on long files
64
+ t0 = time.time()
65
+ while not done.is_set():
66
+ with anyio.move_on_after(5):
67
+ await done.wait()
68
+ if ctx and not done.is_set():
69
+ await ctx.report_progress(time.time() - t0, None, lines[-1] if lines else "starting ...")
70
+
71
+ result: dict = {}
72
+ async with anyio.create_task_group() as tg:
73
+ tg.start_soon(heartbeat)
74
+ try:
75
+ result = await anyio.to_thread.run_sync(lambda: api.transcribe_file(
76
+ src, language, accurate=accurate, formats=fmts, out=out, log=lambda m: (lines.append(m), print(m))))
77
+ finally:
78
+ done.set()
79
+ text = result.pop("text", "")
80
+ result["text"] = text[:TEXT_LIMIT]
81
+ if len(text) > TEXT_LIMIT:
82
+ result["note"] = f"transcript truncated to {TEXT_LIMIT} characters; the full text is in the files listed"
83
+ return result
84
+
85
+ @srv.tool(title="Find audio/video files", annotations=ToolAnnotations(read_only_hint=True, open_world_hint=False))
86
+ def find_media(name_contains: str = "", folder: str = "", limit: int = 15) -> list[dict]:
87
+ """Find audio/video files on this computer, newest first. Searches Downloads, Videos, Desktop, Music and
88
+ Documents (two levels deep) unless folder is given. Use it when the user names a file without a full path."""
89
+ home = Path.home()
90
+ roots = [Path(folder).expanduser()] if folder else [home / d for d in ("Downloads", "Videos", "Desktop", "Music", "Documents", "Movies")]
91
+ hits = []
92
+ for r in roots:
93
+ if not r.is_dir():
94
+ continue
95
+ for p in [*r.glob("*"), *r.glob("*/*"), *(r.glob("*/*/*") if folder else [])]:
96
+ if p.suffix.lower() in MEDIA and name_contains.lower() in p.name.lower():
97
+ try:
98
+ st = p.stat()
99
+ except OSError:
100
+ continue
101
+ hits.append((st.st_mtime, p, st.st_size))
102
+ hits.sort(reverse=True)
103
+ return [{"path": str(p), "size_mb": round(sz / 1e6, 1), "modified": time.strftime("%Y-%m-%d %H:%M", time.localtime(t))}
104
+ for t, p, sz in hits[:limit]]
105
+
106
+ @srv.tool(title="List GPUs", annotations=ToolAnnotations(read_only_hint=True, open_world_hint=True))
107
+ def list_devices() -> dict:
108
+ """GPUs whisper.cpp can use on this computer and which one babelscribe picks automatically."""
109
+ _, _, found = api.setup()
110
+ return {"devices": found, "auto_pick": backend.pick_device(found)}
111
+
112
+ @srv.tool(title="List languages and models", annotations=ToolAnnotations(read_only_hint=True, open_world_hint=False))
113
+ def list_languages_and_models() -> dict:
114
+ """Models available, and which model --accurate uses per language."""
115
+ return {"general": models.GENERAL, "fine_tunes": {k: v["note"] for k, v in models.FINETUNES.items()},
116
+ "accurate_per_language": {**models.ACCURATE, "*": "large-v3 beam 5"}}
117
+
118
+ return srv
119
+
120
+
121
+ def main() -> None:
122
+ try:
123
+ import anyio
124
+ from mcp.server.stdio import stdio_server
125
+ except ImportError:
126
+ raise SystemExit('the MCP server needs Python 3.10+ (the mcp SDK)')
127
+ proto = _guard_stdout()
128
+ srv = build()
129
+
130
+ async def run():
131
+ async with stdio_server(stdout=anyio.wrap_file(proto)) as (r, w):
132
+ low = srv._lowlevel_server
133
+ await low.run(r, w, low.create_initialization_options())
134
+
135
+ anyio.run(run)
136
+
137
+
138
+ if __name__ == "__main__":
139
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: babelscribe
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Transcribe any audio/video in 99 languages on any GPU (AMD, NVIDIA, Intel via Vulkan; NVIDIA via CUDA; Apple via Metal) or CPU — whisper.cpp with batteries included.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/phonology024/babelscribe
@@ -251,6 +251,25 @@ them to each `v*` release. Point `BABELSCRIBE_RELEASES` at another URL to self-h
251
251
  ภาษาไทยแนะนำ `babelscribe ไฟล์.mp4 -l th --accurate` — ข้อความจาก Pathumma Whisper (NECTEC) ที่ผิดน้อยที่สุดใน FLEURS (CER 8.9% เทียบ turbo 15.9%) + เวลาจาก large-v3-turbo
252
252
  หรือเลือก Thonburian Whisper เอง: `--text-model thai-thonburian`
253
253
 
254
+ ## Privacy Policy
255
+ babelscribe runs entirely on your own computer. Last updated 2026-10-06.
256
+
257
+ - **Data collection:** none. babelscribe has no telemetry, analytics, accounts or crash reporting, and never uploads your
258
+ audio, video, transcripts or file names anywhere.
259
+ - **What it processes and where:** the media file you choose is converted and transcribed locally; subtitles and text are
260
+ written to your disk (next to the file, or the folder you choose). Through MCP, the transcript text is returned to the AI
261
+ app that called the tool — what that app does with it is governed by that app's own privacy policy.
262
+ - **Network access (downloads only):** on first use it downloads the `whisper-cli` program from this project's GitHub
263
+ releases, speech models from Hugging Face (`huggingface.co/ggerganov/whisper.cpp`, and for `--accurate` Thai/Hindi the
264
+ fine-tune's own repository), and Python packages from PyPI when installed with pip/uv. These are plain downloads;
265
+ no personal data is sent. GitHub, Hugging Face and PyPI see a normal download request (IP address, user agent) under
266
+ their own privacy policies.
267
+ - **Storage and retention:** downloaded programs and models are cached in `~/.babelscribe` (or `BABELSCRIBE_HOME` /
268
+ `BABELSCRIBE_MODELS`) until you delete that folder. Outputs stay wherever they were written until you delete them.
269
+ babelscribe keeps no other data.
270
+ - **Third-party sharing:** none.
271
+ - **Contact:** open an issue at https://github.com/phonology024/babelscribe/issues
272
+
254
273
  ## Credits & licence
255
274
  MIT. Built on [whisper.cpp](https://github.com/ggml-org/whisper.cpp) (MIT) and OpenAI Whisper models (MIT).
256
275
  Fine-tunes belong to their authors: [Pathumma Whisper](https://huggingface.co/nectec/Pathumma-whisper-th-large-v3) by NECTEC,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "babelscribe"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "Transcribe any audio/video in 99 languages on any GPU (AMD, NVIDIA, Intel via Vulkan; NVIDIA via CUDA; Apple via Metal) or CPU — whisper.cpp with batteries included."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes