Text Generation
Transformers
GGUF
MLX
Japanese
asr-error-correction
japanese
whisper
phonetics
constrained-decoding
on-device
text2text-generation
Instructions to use NagaYu/mondegreen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use NagaYu/mondegreen with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="NagaYu/mondegreen")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("NagaYu/mondegreen", device_map="auto") - MLX
How to use NagaYu/mondegreen with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # if on a CUDA device, also pip install mlx[cuda] # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("NagaYu/mondegreen") prompt = "Once upon a time in" text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- vLLM
How to use NagaYu/mondegreen with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "NagaYu/mondegreen" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NagaYu/mondegreen", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/NagaYu/mondegreen
- SGLang
How to use NagaYu/mondegreen with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "NagaYu/mondegreen" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NagaYu/mondegreen", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "NagaYu/mondegreen" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NagaYu/mondegreen", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - MLX LM
How to use NagaYu/mondegreen with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Generate some text mlx_lm.generate --model "NagaYu/mondegreen" --prompt "Once upon a time"
- Docker Model Runner
How to use NagaYu/mondegreen with Docker Model Runner:
docker model run hf.co/NagaYu/mondegreen
- Atomic Chat
| license: apache-2.0 | |
| language: | |
| - ja | |
| library_name: transformers | |
| pipeline_tag: text2text-generation | |
| base_model: Qwen/Qwen2.5-0.5B | |
| tags: | |
| - asr-error-correction | |
| - japanese | |
| - whisper | |
| - phonetics | |
| - constrained-decoding | |
| - on-device | |
| - gguf | |
| - mlx | |
| # Mondegreen โ `v0.1.0` | |
| **็จ่ช้ใใใ้กใใงใฏใชใๅถ็ดใซใใใ** | |
| *A private glossary, compiled into a hard phonetic constraint.* | |
| Whisper does not know your colleagues' names, your product names or your team's | |
| jargon โ and 10,000 of them do not fit in a 244-token prompt. Mondegreen corrects | |
| them **afterwards, locally**, as a span replacement that is structurally unable to | |
| leave your glossary. | |
| - Code: https://github.com/NagaYu/mondegreen | |
| - Space: https://huggingface.co/spaces/NagaYu/mondegreen | |
| - Dataset: https://huggingface.co/datasets/NagaYu/mondegreen-asr-errors | |
| ## What is in this repo | |
| - `gate.json โ the calibrated conservative gate (3 KB, ships with the package)` | |
| - `lora/ โ LoRA adapter for the candidate re-ranker (Qwen2.5-0.5B base)` | |
| ## Read this before assuming what the LM does | |
| The **hard constraint is not learned and not in these weights.** The legal | |
| replacement set for a span is computed by `mondegreen.index.PhoneticIndex` as a | |
| finite list, under bounds evaluated before any model runs: | |
| | bound | what it stops | | |
| | --- | --- | | |
| | normalised phonetic distance โค ฯ (0.28) | unrelated words | | |
| | absolute distance โค 0.25 + 0.20ยทโmora | long terms reached via many cheap edits | | |
| | mora-count difference โค 34% | invented syllables | | |
| | common dictionary words need near-exact homophony | ใ็จผๅ็ใโใๅ ่ค็ใ | | |
| | containment guard | ใๆฐ่คใใใโใๆฐ่คใ (deleting an honorific) | | |
| The LoRA adapter **only re-ranks candidates already inside that set**. It cannot | |
| add to it, cannot introduce a term that is not in your glossary, and cannot | |
| rewrite grammar. On synthetic glossaries only ~1% of spans have more than one | |
| legal candidate, so most of the time it is not consulted at all โ which is | |
| precisely why 4-bit quantisation is safe here, and is asserted by | |
| `tests/test_quantization.py` (removing the LM entirely costs < 2 recall points). | |
| `gate.json` is the calibrated conservative gate โ a logistic regression over 18 | |
| interpretable span features (AUC 0.985, ECE 0.053, | |
| threshold 0.82). It is 3 KB of JSON and it is the | |
| component whose job is to say *no*. | |
| ## Results | |
| 400 held-out sentences, 10,000-term glossary, evaluation glossary strictly | |
| disjoint from training by surface **and** by reading: | |
| | condition | CER | WER | term recall | **damage rate** | | |
| | --- | ---: | ---: | ---: | ---: | | |
| | (A) raw Whisper | 0.2842 | 0.2541 | 25.3% | 0.00000 | | |
| | (B) Whisper `initial_prompt` | 0.2796 | 0.2509 | 27.2% | 0.00009 | | |
| | (C) cloud LLM post-processing | 0.0893 | 0.0944 | 83.0% | 0.00657 | | |
| | **(D) Mondegreen** | 0.1105 | 0.1217 | 66.3% | 0.00009 | | |
| | (E) Mondegreen, quantised | 0.1105 | 0.1217 | 66.3% | 0.00009 | | |
| **(C) wins on term recall (83.0% vs 66.3%) and does 73ร the damage** (0.00657 vs | |
| 0.00009), needs the transcript to leave the machine, and is therefore unusable on | |
| the confidential audio that motivates this project. That trade is the finding, not | |
| a footnote. | |
| | | | | |
| | --- | --- | | |
| | throughput | **464 characters/second** (10,000-term glossary) | | |
| | 1 hour of transcription | **45 seconds** | | |
| | peak memory | 196 MB | | |
| | machine | Apple M2, 16.0 GB | | |
| | network | **none** | | |
| > **Provenance.** These numbers are `simulated`: condition (D) is always the real | |
| > system, but the error generator and baselines (B)/(C) are explicit models whose | |
| > parameters are printed in the results file. They are **not** measured Whisper | |
| > numbers. See `benchmarks/README.md` in the repo for how to replace them with | |
| > measurements. | |
| ## Use | |
| ```bash | |
| pip install git+https://github.com/NagaYu/mondegreen | |
| ``` | |
| ```python | |
| from mondegreen import ConstrainedCorrector, load_glossary | |
| corrector = ConstrainedCorrector(load_glossary("terms.csv")) | |
| print(corrector.correct("้ฒ่คใใใไธกๆฐ่ชคใ่จๆญฃใฎ่ฉฑใใใพใใใ").text) | |
| # ๆฐ่คใใใ้ๅญ่ชคใ่จๆญฃใฎ่ฉฑใใใพใใใ | |
| ``` | |
| With the quantised re-ranker: | |
| ```python | |
| from mondegreen.runtime import build_reranker | |
| corrector = ConstrainedCorrector( | |
| load_glossary("terms.csv"), | |
| lm=build_reranker("mondegreen-Q4_K_M.gguf"), | |
| ) | |
| ``` | |
| CLI, with the evidence for every edit: | |
| ```bash | |
| mondegreen fix transcript.txt --glossary terms.csv | |
| mondegreen explain transcript.txt --glossary terms.csv | |
| ``` | |
| ## Training data | |
| Synthetic. Glossaries are generated by `mondegreen.harvest.GlossaryBuilder`; | |
| carrier sentences by `SentenceFactory`; errors by the phonetic corruption model in | |
| `mondegreen.simulate`, which perturbs the *reading* using the same confusion | |
| classes the distance function discounts and re-renders it as a homophone kanji | |
| spelling. **No real audio, no real person's name, and no LLM grading anywhere.** | |
| ## Limitations | |
| - Japanese only. The mora table, the confusion costs and the POS rules are all | |
| Japanese-specific. | |
| - Without `fugashi`/`pyopenjtalk` the bundled 4,030-kanji fallback table is used. | |
| It has no part-of-speech information, so the common-word protection cannot fire | |
| and the damage rate rises. Install `mondegreen[g2p]`. | |
| - The n-gram candidate accelerator is not exact (99.67% recall vs exhaustive at | |
| 10,000 terms). Misses can only cause a *missed* correction, never an illegal | |
| one โ the bound is re-verified on every scored candidate. | |
| - Evaluation is on synthetic glossaries and simulated ASR errors. | |
| ## โ ๏ธ Intended use | |
| A glossary can contain personal names. **Use this only on data under your own | |
| control.** Do not run it over other people's meeting records, or with a glossary | |
| of names you have no relationship to. Mondegreen handles text only, never audio, | |
| and makes no network calls. | |
| ## Citation | |
| ```bibtex | |
| @software{mondegreen, | |
| title = {Mondegreen: private glossaries as hard phonetic constraints for local ASR correction}, | |
| author = {NagaYu}, | |
| year = {2026}, | |
| url = {https://github.com/NagaYu/mondegreen}, | |
| license = {Apache-2.0} | |
| } | |
| ``` | |