Text Generation
GGUF
English
dictation
transcript-cleanup
asr-post-processing
asr-error-correction
speech-to-text
post-asr-correction
llama.cpp
qwen3.5
local-llm
cpu-inference
Eval Results (legacy)
conversational
Instructions to use SpeakoFlow/speakoflow-mini with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use SpeakoFlow/speakoflow-mini with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf SpeakoFlow/speakoflow-mini:Q4_K_M # Run inference directly in the terminal: llama cli -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf SpeakoFlow/speakoflow-mini:Q4_K_M # Run inference directly in the terminal: llama cli -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf SpeakoFlow/speakoflow-mini:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf SpeakoFlow/speakoflow-mini:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Use Docker
docker model run hf.co/SpeakoFlow/speakoflow-mini:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use SpeakoFlow/speakoflow-mini with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "SpeakoFlow/speakoflow-mini" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "SpeakoFlow/speakoflow-mini", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/SpeakoFlow/speakoflow-mini:Q4_K_M
- Ollama
How to use SpeakoFlow/speakoflow-mini with Ollama:
ollama run hf.co/SpeakoFlow/speakoflow-mini:Q4_K_M
- Unsloth Desktop
- Pi
How to use SpeakoFlow/speakoflow-mini with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "SpeakoFlow/speakoflow-mini:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use SpeakoFlow/speakoflow-mini with Docker Model Runner:
docker model run hf.co/SpeakoFlow/speakoflow-mini:Q4_K_M
- Lemonade
How to use SpeakoFlow/speakoflow-mini with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull SpeakoFlow/speakoflow-mini:Q4_K_M
Run and chat with the model
lemonade run user.speakoflow-mini-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use SpeakoFlow/speakoflow-mini with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default SpeakoFlow/speakoflow-mini:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use SpeakoFlow/speakoflow-mini with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf SpeakoFlow/speakoflow-mini:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "SpeakoFlow/speakoflow-mini:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Restructure: two-stage architecture, published category taxonomy, scoring tiers
Browse files
README.md
CHANGED
|
@@ -27,7 +27,7 @@ model-index:
|
|
| 27 |
name: Dictation cleanup
|
| 28 |
dataset:
|
| 29 |
type: dictation-cleanup-eval
|
| 30 |
-
name: SpeakoFlow dictation cleanup evaluation (held out
|
| 31 |
split: test
|
| 32 |
metrics:
|
| 33 |
- type: exact_match
|
|
@@ -48,29 +48,33 @@ model-index:
|
|
| 48 |
|
| 49 |
# SpeakoFlow Mini 0.8B, GGUF
|
| 50 |
|
| 51 |
-
Dictation cleanup for
|
| 52 |
-
|
| 53 |
|
| 54 |
-
|
| 55 |
[`Qwen/Qwen3.5-0.8B`](https://huggingface.co/Qwen/Qwen3.5-0.8B) with LoRA rank 16, merged, then
|
| 56 |
-
quantised. English
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
| 60 |
|
| 61 |
[](https://speakoflow.com)
|
|
|
|
| 62 |
[](https://www.apache.org/licenses/LICENSE-2.0)
|
| 63 |
-
[](https://huggingface.co/Qwen/Qwen3.5-0.8B)
|
| 64 |
|
| 65 |
-
##
|
| 66 |
|
| 67 |
-
|
| 68 |
-
*"the deposit is three hundred dollars, um, and the meeting is at nine thirty"* and you get
|
| 69 |
-
*"The deposit is $300 and the meeting is at 9:30"* before any language model runs.
|
| 70 |
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
| you dictate | it returns |
|
| 76 |
|---|---|
|
|
@@ -79,14 +83,46 @@ model is for:
|
|
| 79 |
| Thanks for the update. New paragraph. I'll review it tonight. | Thanks for the update.<br><br>I'll review it tonight. |
|
| 80 |
| Thanks for the update. I'll review it tonight. | Thanks for the update. I'll review it tonight. |
|
| 81 |
|
| 82 |
-
The fourth row is the
|
| 83 |
|
| 84 |
-
That is
|
| 85 |
-
|
| 86 |
paragraph becomes bullets, a word becomes a smoother synonym. Each edit is defensible on its own
|
| 87 |
and each one is wrong, because the speaker said the other thing and now has to undo the
|
| 88 |
improvement.
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
## Run it
|
| 91 |
|
| 92 |
```bash
|
|
@@ -105,10 +141,14 @@ LM Studio: search `speakoflow` in-app, or `lms get SpeakoFlow/speakoflow-mini-0.
|
|
| 105 |
Send the transcript as the user message with nothing added. No instructions, no delimiters, no
|
| 106 |
examples.
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
### The system prompt is part of the model
|
| 109 |
|
| 110 |
-
It was fine-tuned on this exact string and every number below was produced with it.
|
| 111 |
-
something different and you are running a configuration nobody has measured.
|
| 112 |
|
| 113 |
```text
|
| 114 |
You clean up SpeakoFlow dictation. Return only the cleaned transcript text.
|
|
@@ -130,29 +170,9 @@ Rules:
|
|
| 130 |
- Do not add or remove blank lines at the start or end.
|
| 131 |
```
|
| 132 |
|
| 133 |
-
##
|
| 134 |
-
|
| 135 |
-
Do not cap `max_tokens`. A truncated long transcript counts as lost content and manufactures a
|
| 136 |
-
failure that did not happen.
|
| 137 |
-
|
| 138 |
-
Disable thinking. Reasoning text landing in a field that is supposed to be byte-identical fails
|
| 139 |
-
every no-op case for reasons that have nothing to do with cleanup. At its defaults this model
|
| 140 |
-
emits zero reasoning characters. The untuned base at the same file size reasons until the context
|
| 141 |
-
runs out and returns nothing.
|
| 142 |
-
|
| 143 |
-
## How it was measured
|
| 144 |
|
| 145 |
-
|
| 146 |
-
evaluation set, used as a check on that work rather than as a substitute for it.
|
| 147 |
-
|
| 148 |
-
**The evaluation set is not published and will not be.** It is built from real dictation,
|
| 149 |
-
including the author's own correspondence, so it contains personal information that has no
|
| 150 |
-
business being on the internet. The examples in this card are written for illustration and are
|
| 151 |
-
not drawn from it.
|
| 152 |
-
|
| 153 |
-
Three things you can hold this to. Scoring is exact string match at temperature 0, so a pass
|
| 154 |
-
means the output matched the reference character for character with no partial credit. The rates
|
| 155 |
-
are:
|
| 156 |
|
| 157 |
| | overall | restraint | edit accuracy | content damage |
|
| 158 |
|---|---|---|---|---|
|
|
@@ -165,65 +185,67 @@ are:
|
|
| 165 |
| S1-mini (shipped cleanup model) | 15.3% | 22.1% | 8.5% | 55.3% |
|
| 166 |
| Sotto 350M (shipped cleanup model) | 11.7% | 16.2% | 7.3% | 60.7% |
|
| 167 |
|
| 168 |
-
- **Restraint**
|
| 169 |
-
- **Edit accuracy**
|
| 170 |
-
- **Overall**
|
| 171 |
-
- **Content damage**
|
| 172 |
better.
|
| 173 |
|
| 174 |
-
Overall is
|
| 175 |
transcripts that need an edit and transcripts that do not. Plain accuracy would score a program
|
| 176 |
that changes nothing at 45.3%, which reads like it half works. The mean scores that same
|
| 177 |
do-nothing strategy at exactly 50.0%, so anything under 50 is worse than leaving the transcript
|
| 178 |
-
alone. Four of the seven systems
|
| 179 |
-
the restraint column
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
-
**
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
|
|
|
|
|
|
| 188 |
|
| 189 |
## Fine-tuning bought the skill and cost no restraint
|
| 190 |
|
| 191 |
-
Against the untuned `Qwen/Qwen3.5-0.8B` at the same file size,
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
[+16.3, +30.3].
|
| 195 |
|
| 196 |
The usual expectation is that teaching a model to edit costs restraint. Here it cost nothing
|
| 197 |
measurable.
|
| 198 |
|
| 199 |
## Against a frontier model: a tie, except on long transcripts
|
| 200 |
|
| 201 |
-
Overall the gap is +5.8 points, 95% CI [-1.5, +12.9].
|
| 202 |
-
tie, and calling it anything else would not survive scrutiny.
|
| 203 |
|
| 204 |
-
|
| 205 |
-
|
| 206 |
|
| 207 |
## Speed
|
| 208 |
|
| 209 |
-
|
| 210 |
|
| 211 |
| | median latency | p95 | decode |
|
| 212 |
|---|---|---|---|
|
| 213 |
| CPU | 2,509 ms | 14,821 ms | 54 tok/s |
|
| 214 |
| CUDA, `--n-gpu-layers 99` | 311 ms | 1,909 ms | 342 tok/s |
|
| 215 |
|
| 216 |
-
8.1x on median latency at the same restraint and
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
against CUDA is not: 1.3% of outputs differ, because the two kernels do not produce bit-identical
|
| 221 |
-
logits and a near-tie can resolve the other way.
|
| 222 |
-
|
| 223 |
-
## What each quantisation costs
|
| 224 |
|
| 225 |
-
|
| 226 |
-
here was run through the same evaluation, so you do not have to guess.
|
| 227 |
|
| 228 |
| file | size | overall | restraint | edit accuracy | outputs differing from Q8_0 |
|
| 229 |
|---|---|---|---|---|---|
|
|
@@ -233,75 +255,49 @@ here was run through the same evaluation, so you do not have to guess.
|
|
| 233 |
| Q5_K_M | 593 MB | 70.0% | 91.2% | 48.8% | 2.0% |
|
| 234 |
| Q4_K_M | 542 MB | 69.4% | 91.2% | 47.6% | 7.3% |
|
| 235 |
|
| 236 |
-
|
| 237 |
-
identical.
|
| 238 |
-
|
| 239 |
-
**Take Q8_0 unless you have a reason not to.** It is the build every other number on this page
|
| 240 |
-
describes, and the app downloads it by default.
|
| 241 |
-
|
| 242 |
-
**This evaluation cannot tell Q4_K_M and Q8_0 apart.** The 1.3 point gap is one case on each
|
| 243 |
-
axis, and the 95% intervals overlap almost entirely: restraint [83.9%, 96.8%] against
|
| 244 |
-
[82.1%, 95.9%], edit accuracy [38.3%, 59.4%] against [37.1%, 58.2%]. Read that row as a null
|
| 245 |
-
result, not as a measured cost. What is real, because it is a count and not an estimate, is that
|
| 246 |
-
7.3% of outputs changed. Q4_K_M demonstrably changes what this model says. It does not
|
| 247 |
-
demonstrably change how often it is right.
|
| 248 |
-
|
| 249 |
-
In daily use I have noticed Q4_K_M come back slightly worse often enough to prefer Q8_0. That is
|
| 250 |
-
an anecdote and it stays labelled as one, but it points the same way as the changed outputs.
|
| 251 |
|
| 252 |
-
**
|
| 253 |
-
value is that you can quantise it yourself.
|
| 254 |
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
**Most of the scoring rewards copying.** Returning an already-correct transcript unchanged means
|
| 263 |
-
emitting the token that is already in context, and the logit margin on a copy is large.
|
| 264 |
-
Quantisation noise has to clear a wide gap to flip one. An evaluation weighted toward
|
| 265 |
-
already-correct text is therefore less sensitive to quantisation than one that generates freely,
|
| 266 |
-
and nothing here measures the compounding you would see over hundreds of generated tokens. This
|
| 267 |
-
table is evidence about dictation cleanup, not about 4-bit quantisation in general.
|
| 268 |
-
|
| 269 |
-
**The remaining difficulty is not the kind quantisation makes worse.** Edit accuracy is 48.8%, so
|
| 270 |
-
the model misses more than half the changes it is asked to make. The task is not easy. It is hard
|
| 271 |
-
in a way that depends on knowing which change the speaker wanted, and that knowledge either
|
| 272 |
-
survives the weight noise or it does not.
|
| 273 |
|
| 274 |
## Limitations
|
| 275 |
|
| 276 |
-
**
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
|
| 281 |
-
**It
|
| 282 |
-
|
| 283 |
|
| 284 |
**It is not a rewriter.** Register, tone and verbosity are out of scope by design. Changing how
|
| 285 |
formally someone speaks means replacing words they said.
|
| 286 |
|
| 287 |
-
**
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
|
| 292 |
-
**
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
|
| 297 |
-
**
|
| 298 |
-
|
|
|
|
| 299 |
|
| 300 |
-
**
|
| 301 |
-
|
| 302 |
|
| 303 |
-
**10.7% of transcripts lose a word the speaker said.** That is the number to beat
|
| 304 |
-
small.
|
| 305 |
|
| 306 |
## Provenance
|
| 307 |
|
|
@@ -309,7 +305,7 @@ small.
|
|
| 309 |
- Method: LoRA, rank 16, merged before quantisation
|
| 310 |
- Reference build: Q8_0, 833,591,776 bytes
|
| 311 |
- SHA-256: `696769bb6911f51bc231b112926e934cf7bfc760e6cdfa24212907bc5ad41fc9`
|
| 312 |
-
-
|
| 313 |
|
| 314 |
## Citation
|
| 315 |
|
|
|
|
| 27 |
name: Dictation cleanup
|
| 28 |
dataset:
|
| 29 |
type: dictation-cleanup-eval
|
| 30 |
+
name: SpeakoFlow dictation cleanup evaluation (held out)
|
| 31 |
split: test
|
| 32 |
metrics:
|
| 33 |
- type: exact_match
|
|
|
|
| 48 |
|
| 49 |
# SpeakoFlow Mini 0.8B, GGUF
|
| 50 |
|
| 51 |
+
Dictation cleanup for transcribed speech. It applies the correction the speaker actually made,
|
| 52 |
+
and returns everything else byte for byte.
|
| 53 |
|
| 54 |
+
833 MB at Q8_0, 2,509 ms median on a desktop CPU. Fine-tuned from
|
| 55 |
[`Qwen/Qwen3.5-0.8B`](https://huggingface.co/Qwen/Qwen3.5-0.8B) with LoRA rank 16, merged, then
|
| 56 |
+
quantised. English. Not a chat model, not a rewriter.
|
| 57 |
|
| 58 |
+
Ships in [SpeakoFlow](https://speakoflow.com), a free offline voice assistant for Windows, macOS
|
| 59 |
+
and Linux.
|
| 60 |
|
| 61 |
[](https://speakoflow.com)
|
| 62 |
+
[](https://github.com/AbhishekBarali/dictation-cleanup-rules)
|
| 63 |
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
| 64 |
|
| 65 |
+
## Two stages, and this model is the second one
|
| 66 |
|
| 67 |
+
Cleanup splits cleanly into work a rule can do and work it cannot.
|
|
|
|
|
|
|
| 68 |
|
| 69 |
+
**Stage one is deterministic.** Filler words, repeated words, spacing, punctuation,
|
| 70 |
+
capitalisation, numbers, dates, currency and known jargon substitutions are pattern work, and
|
| 71 |
+
pattern work belongs in code, where it is fast, free and auditable. That layer is published on
|
| 72 |
+
its own as [dictation-cleanup-rules](https://github.com/AbhishekBarali/dictation-cleanup-rules):
|
| 73 |
+
MIT, Python and TypeScript, with a spec, pattern tables and a conformance suite. Use it with or
|
| 74 |
+
without this model.
|
| 75 |
+
|
| 76 |
+
**Stage two is this model.** It handles what a rule cannot decide, which is anything requiring a
|
| 77 |
+
judgement about what the speaker meant. Four examples:
|
| 78 |
|
| 79 |
| you dictate | it returns |
|
| 80 |
|---|---|
|
|
|
|
| 83 |
| Thanks for the update. New paragraph. I'll review it tonight. | Thanks for the update.<br><br>I'll review it tonight. |
|
| 84 |
| Thanks for the update. I'll review it tonight. | Thanks for the update. I'll review it tonight. |
|
| 85 |
|
| 86 |
+
The fourth row is the point. Nothing was wrong, so nothing changed, down to the byte.
|
| 87 |
|
| 88 |
+
That is where general-purpose models fail. Handed text that is already correct, a capable model
|
| 89 |
+
finds something to improve. A comma becomes a full stop, a sentence becomes a heading, a
|
| 90 |
paragraph becomes bullets, a word becomes a smoother synonym. Each edit is defensible on its own
|
| 91 |
and each one is wrong, because the speaker said the other thing and now has to undo the
|
| 92 |
improvement.
|
| 93 |
|
| 94 |
+
## What it was trained and evaluated on
|
| 95 |
+
|
| 96 |
+
Fifteen categories, each one a decision a rule cannot make. The examples below are written for
|
| 97 |
+
this card.
|
| 98 |
+
|
| 99 |
+
| category | what it covers | example |
|
| 100 |
+
|---|---|---|
|
| 101 |
+
| `no_op` | already correct, so return it unchanged | input comes back byte for byte |
|
| 102 |
+
| `retraction` | the speaker corrects themselves mid-sentence | "Thursday, no, Friday" becomes "Friday" |
|
| 103 |
+
| `spoken_command` | an editing or layout instruction said out loud | "new paragraph" becomes a paragraph break |
|
| 104 |
+
| `spoken_symbol` | a symbol named instead of typed | "sam at example dot com" becomes `sam@example.com` |
|
| 105 |
+
| `format_intent` | structure described in speech | "bullet one, call the vendor, bullet two, send the invoice" becomes a list |
|
| 106 |
+
| `speaker_grammar` | the speaker's own slip, not a transcription error | "they was ready" becomes "they were ready" |
|
| 107 |
+
| `wrong_word_right_transcription` | transcribed correctly, still the wrong word | "in the mourning" becomes "in the morning" |
|
| 108 |
+
| `disfluency_artifact` | stumbles the recogniser preserved | "the the deadline" becomes "the deadline" |
|
| 109 |
+
| `clarification` | the speaker restates a name or number more precisely | the later, more precise form wins |
|
| 110 |
+
| `dictated_question` | a question inside the text | transcribed, never answered |
|
| 111 |
+
| `instruction_as_text` | an instruction inside the text | transcribed, never obeyed |
|
| 112 |
+
| `language_preserved` | dictation in another language | kept in that language, never translated |
|
| 113 |
+
| `truncated_input` | the transcript stops mid-thought | left stopped, nothing invented to finish it |
|
| 114 |
+
| `empty_or_noise` | nothing usable came through | returns nothing, with no commentary about it |
|
| 115 |
+
| `hallucination_loop` | the recogniser repeats a phrase it never heard twice | the artefact goes, a repetition the speaker really made stays |
|
| 116 |
+
|
| 117 |
+
Cases are drawn from two sources, labelled per case: transcripts captured from real dictation,
|
| 118 |
+
and cases written by hand to cover a category that real use had not yet produced. Each case is
|
| 119 |
+
also labelled by length band and by where in the transcript the defect sits, so results can be
|
| 120 |
+
broken out by both.
|
| 121 |
+
|
| 122 |
+
**The evaluation set itself is held privately.** It is built from real dictation by the author and
|
| 123 |
+
by people using the app, so it contains personal correspondence that is not ours to publish. The
|
| 124 |
+
categories above, the specification and the scoring code are what make the numbers checkable.
|
| 125 |
+
|
| 126 |
## Run it
|
| 127 |
|
| 128 |
```bash
|
|
|
|
| 141 |
Send the transcript as the user message with nothing added. No instructions, no delimiters, no
|
| 142 |
examples.
|
| 143 |
|
| 144 |
+
Two settings are not optional. Do not cap `max_tokens`: a truncated long transcript counts as
|
| 145 |
+
lost content. Disable thinking: reasoning text landing in a field that is meant to be
|
| 146 |
+
byte-identical fails every no-op case for reasons that have nothing to do with cleanup. At its
|
| 147 |
+
defaults this model emits zero reasoning characters.
|
| 148 |
+
|
| 149 |
### The system prompt is part of the model
|
| 150 |
|
| 151 |
+
It was fine-tuned on this exact string and every number below was produced with it.
|
|
|
|
| 152 |
|
| 153 |
```text
|
| 154 |
You clean up SpeakoFlow dictation. Return only the cleaned transcript text.
|
|
|
|
| 170 |
- Do not add or remove blank lines at the start or end.
|
| 171 |
```
|
| 172 |
|
| 173 |
+
## Results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
+
Held-out evaluation, temperature 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
| | overall | restraint | edit accuracy | content damage |
|
| 178 |
|---|---|---|---|---|
|
|
|
|
| 185 |
| S1-mini (shipped cleanup model) | 15.3% | 22.1% | 8.5% | 55.3% |
|
| 186 |
| Sotto 350M (shipped cleanup model) | 11.7% | 16.2% | 7.3% | 60.7% |
|
| 187 |
|
| 188 |
+
- **Restraint**: of the transcripts that were already correct, the share returned byte for byte.
|
| 189 |
+
- **Edit accuracy**: of the transcripts needing a change, the share that came back exactly right.
|
| 190 |
+
- **Overall**: the unweighted mean of the two.
|
| 191 |
+
- **Content damage**: the share of all transcripts that lost a word the speaker said. Lower is
|
| 192 |
better.
|
| 193 |
|
| 194 |
+
Overall is a mean rather than plain accuracy because the set is close to evenly split between
|
| 195 |
transcripts that need an edit and transcripts that do not. Plain accuracy would score a program
|
| 196 |
that changes nothing at 45.3%, which reads like it half works. The mean scores that same
|
| 197 |
do-nothing strategy at exactly 50.0%, so anything under 50 is worse than leaving the transcript
|
| 198 |
+
alone. Four of the seven systems here are under it, and two of those look safe if you read only
|
| 199 |
+
the restraint column.
|
| 200 |
+
|
| 201 |
+
### How scoring works
|
| 202 |
+
|
| 203 |
+
Three tiers, in the order they run.
|
| 204 |
+
|
| 205 |
+
**Human-authored references.** Every expected output is written by hand against a written
|
| 206 |
+
specification that predates the cases. There is one annotator, so no inter-annotator agreement
|
| 207 |
+
figure is available.
|
| 208 |
|
| 209 |
+
**Deterministic scoring.** Exact string match. A pass means the output matched the reference
|
| 210 |
+
character for character, with no partial credit. Every rate on this page comes from this tier. A
|
| 211 |
+
deterministic difference classifier runs alongside it to group the failures by cause.
|
| 212 |
+
|
| 213 |
+
**Model-based adjudication, evaluated and not adopted.** A tier using frontier models to judge
|
| 214 |
+
disputed outputs was built and run. Four models from four vendors adjudicated the same cases and
|
| 215 |
+
agreed on too few of them to be usable, which meant the choice of judge moved the result more
|
| 216 |
+
than the answers did. The tier was dropped rather than tuned. No judge score is published.
|
| 217 |
|
| 218 |
## Fine-tuning bought the skill and cost no restraint
|
| 219 |
|
| 220 |
+
Against the untuned `Qwen/Qwen3.5-0.8B` at the same file size, quantisation, prompt and hardware,
|
| 221 |
+
edit accuracy goes from 4.9% to 48.8%. Restraint goes from 89.7% to 92.6%, a difference of a
|
| 222 |
+
single case that this set cannot resolve. Overall gain is +23.4 points, 95% CI [+16.3, +30.3].
|
|
|
|
| 223 |
|
| 224 |
The usual expectation is that teaching a model to edit costs restraint. Here it cost nothing
|
| 225 |
measurable.
|
| 226 |
|
| 227 |
## Against a frontier model: a tie, except on long transcripts
|
| 228 |
|
| 229 |
+
Overall the gap is +5.8 points, 95% CI [-1.5, +12.9]. The interval contains zero, so it is a tie.
|
|
|
|
| 230 |
|
| 231 |
+
Length is what separates them. On passages of 500 words and up the gap is +20.9 points, 95% CI
|
| 232 |
+
[+7.0, +35.6]. Long passages are what people dictate.
|
| 233 |
|
| 234 |
## Speed
|
| 235 |
|
| 236 |
+
Ryzen 7 7700X, 8 threads, reasoning off:
|
| 237 |
|
| 238 |
| | median latency | p95 | decode |
|
| 239 |
|---|---|---|---|
|
| 240 |
| CPU | 2,509 ms | 14,821 ms | 54 tok/s |
|
| 241 |
| CUDA, `--n-gpu-layers 99` | 311 ms | 1,909 ms | 342 tok/s |
|
| 242 |
|
| 243 |
+
8.1x on median latency at the same restraint and edit accuracy. Every published rate is the CPU
|
| 244 |
+
rate. Determinism is within-backend: three CPU runs are byte-identical to each other, while CPU
|
| 245 |
+
against CUDA differs on 1.3% of outputs because the two kernels do not produce bit-identical
|
| 246 |
+
logits.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
|
| 248 |
+
## Which file to download
|
|
|
|
| 249 |
|
| 250 |
| file | size | overall | restraint | edit accuracy | outputs differing from Q8_0 |
|
| 251 |
|---|---|---|---|---|---|
|
|
|
|
| 255 |
| Q5_K_M | 593 MB | 70.0% | 91.2% | 48.8% | 2.0% |
|
| 256 |
| Q4_K_M | 542 MB | 69.4% | 91.2% | 47.6% | 7.3% |
|
| 257 |
|
| 258 |
+
Every file was run through the same evaluation, so the ladder states its own cost. One pass each,
|
| 259 |
+
all on one GPU with every setting held identical.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
| 261 |
+
**Take Q8_0.** It is the build the rest of this page describes and the one the app downloads.
|
|
|
|
| 262 |
|
| 263 |
+
The spread across the ladder is smaller than this evaluation can resolve. Q4_K_M is 1.3 points
|
| 264 |
+
behind on overall, which is one case on each axis, and the 95% intervals overlap almost entirely.
|
| 265 |
+
What is a count rather than an estimate is that 7.3% of its outputs differ from Q8_0. So Q4_K_M
|
| 266 |
+
demonstrably changes what the model says without demonstrably changing how often it is right, and
|
| 267 |
+
in daily use I prefer Q8_0. BF16 is here as the source for anyone who wants to quantise it
|
| 268 |
+
themselves, not as an upgrade: it is 724 MB larger and scores the same.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
|
| 270 |
## Limitations
|
| 271 |
|
| 272 |
+
**Deterministic fixes are out of scope on purpose.** Filler removal, punctuation, capitalisation
|
| 273 |
+
and number formatting are not trained into this model, because
|
| 274 |
+
[the rules layer](https://github.com/AbhishekBarali/dictation-cleanup-rules) already does them and
|
| 275 |
+
a rule is faster and auditable. Run the two together.
|
| 276 |
|
| 277 |
+
**It works on text.** If the transcription heard the wrong word and nothing in the sentence gives
|
| 278 |
+
that away, this model cannot recover it.
|
| 279 |
|
| 280 |
**It is not a rewriter.** Register, tone and verbosity are out of scope by design. Changing how
|
| 281 |
formally someone speaks means replacing words they said.
|
| 282 |
|
| 283 |
+
**English.** The specification, the training data and every number here are English. The only
|
| 284 |
+
non-English behaviour taught or scored is leaving it alone, under an absolute rule never to
|
| 285 |
+
translate. The base tokenizer covers languages this work does not, so the model will produce
|
| 286 |
+
output for non-English input that nothing here evaluates.
|
| 287 |
|
| 288 |
+
**It was trained on the specification it is scored against.** Competitors get that convention
|
| 289 |
+
described in a prompt; this model was trained on it. The correct reading is that training on a
|
| 290 |
+
written specification beats prompting for it, not that this model is better at English than a
|
| 291 |
+
frontier model.
|
| 292 |
|
| 293 |
+
**The evaluation and the model share an author.** An internal audit found a number of scored cases
|
| 294 |
+
defective or disputed. With those removed, the hosted frontier model's edit accuracy comes out
|
| 295 |
+
*above* this model's, 55.9% against 54.4%. That is published because it is true.
|
| 296 |
|
| 297 |
+
**Gaps under about six points are not resolvable** by this set, including the one against GPT-5.6
|
| 298 |
+
Luna.
|
| 299 |
|
| 300 |
+
**10.7% of transcripts lose a word the speaker said.** That is the number to beat.
|
|
|
|
| 301 |
|
| 302 |
## Provenance
|
| 303 |
|
|
|
|
| 305 |
- Method: LoRA, rank 16, merged before quantisation
|
| 306 |
- Reference build: Q8_0, 833,591,776 bytes
|
| 307 |
- SHA-256: `696769bb6911f51bc231b112926e934cf7bfc760e6cdfa24212907bc5ad41fc9`
|
| 308 |
+
- Other quantisations come from the same checkpoint with an importance matrix
|
| 309 |
|
| 310 |
## Citation
|
| 311 |
|