What polish should do
Drop filler, fix caps and punctuation, turn “number one…” into real lists, keep final intent after course-corrections — paste-ready prose.
R&D
After speech-to-text, dictation is still messy: ums, spoken lists, “wait, I mean…”. We’re training a tiny on-device polish model that cleans that text for paste — without sending audio or transcripts to a cloud LLM, and without answering questions you only meant to type.
The job
Product pages talk about free local ASR. This page is the gap: how we teach a small model to format and correct spoken text — and stay silent when the user is only dictating a question.
Drop filler, fix caps and punctuation, turn “number one…” into real lists, keep final intent after course-corrections — paste-ready prose.
“Do you think that’s a good idea?” must stay a question — not “Yes, I think…”. Chat priors kill dictation tools.
Timeline
Not a launch deck — a lab log. Small models, real failures, then a base model and disciplined data.
Tiny LFM-class models with LoRA course-correction. Fast footprint, weak Flow-like formatting, easy to over-index as “the” default.
Lesson: useful experiment, not the product default.
LoRA on a chat-style MiniCPM checkpoint (~1.5k–1.8k synthetic pairs). Strong on simple “Number one is X” lists. On questions, it still answered like an assistant.
Lesson: LoRA on a chat model does not reliably kill answer-leak.
Switched to a pretrain-only base (not instruct/chat), full-weight SFT, and 500 carefully built train pairs — no legacy MiniCPM data mix. Holdout kept leak-free and large enough to trust.
Lesson: prefer base over chat when the job is rewrite, not reply.
Synthetic pairs are built in two temperatures: messy dictation seeds at high creativity, then perfect clean labels at low temperature. Mixing both in one generation blurs diversity and correctness.
Pass 1 — seeds
Diverse messy raw dictations only.
Pass 2 — labels
Boring, correct clean gold only.
On a stratified 96-example slice of a 500 holdout, pass rate moved 62.5% → 85.4%, answer-leak 3.1% → 0%, mean latency ~1.5s → ~0.6s.
Verdict: the model learned. Remaining gaps = bullets and numbered vs checklist style.
Extra two-pass data focused on bullets, strict numbered lists, checklists, mixed formats, and light cleanup that never drafts assistant text. Continue full SFT from the fused Phase-2 weights. Full 500 holdout: 94.6% pass, 0% answer-leak, ~0.6 s mean.
Shipping defaults stay careful — this track is R&D toward open polish.
Live dictations like “the first one is apple, orange…” still stayed prose after Phase 3.
Fix via more training on spoken list intent and prose contrast — not keyword rules.
Continue SFT → qwen35-08b-polish-enum. Product path: MLX polish, bare train prompt,
paste after polish, weights bundled in FormatTest.
If a list form fails live, improve data + retrain — don’t hard-code triggers.
Results
Numbers from the full 500-example holdout after base SFT + targeted weak-spot practice (2026-07). Not loss curves — pass rate, answer-leak, and latency. (Earlier 96-sample check: 85.4% after first SFT only.)
59.2% → 94.6%
4.8% → 0%
~1.5s → ~0.6s
Untrained Qwen3.5-0.8B Base vs full SFT on 500 two-pass pairs. Same prompt contract, temperature 0 for product-style eval.
| Model | Pass rate | Answered questions? | Latency (mean) |
|---|---|---|---|
| Base (no polish train) | 62.5% | Sometimes (3.1%) | ~1.5 s |
| After 500-pair SFT | 85.4% | 0% on sample | ~0.6 s |
| Skill | Before | After |
|---|---|---|
| Keep questions as questions | 64% | 100% |
| Bullets | 42% | 97% |
| Checklists | 44% | 96% |
| Mixed list + prose | 36% | 92% |
| Numbered steps | 31% | 84% |
| Course-correction | 96% | 100% |
| Light cleanup | 84% | 92% |
| Preserve clean prose | 87% | 97% |
Full 500 after Phase 3 (targeted). Phase 4 adds general enumeration training for spoken list intent that still failed live (“first one is…”) — not keyword heuristics.
Principles
Engineering rules we publish so future us doesn’t “optimize” into a chatbot again.
Prefer base / pretrain weights for polish SFT. Instruct priors want to be helpful — we need a rewriter.
LoRA on chat was not enough. Full-weight SFT (or high-capacity adapters) when answer-leak is the failure mode.
Wild inputs at high T; boring correct gold at low T. Never one sample that has to be both creative and perfect.
Hundreds of held-out dictations, including “Do you think…?” traps. Measure pass rate + leak + latency — not loss alone.
Spoken enumeration should become structure because the model learned it — not because product code matched “first one is.”
Status
This is not the whole shipping story — it’s the polish gap product pages skip. Free local ASR first; open polish that doesn’t answer your questions, next.
Experimental · numbers from 2026-07 holdout runs · MIT open source