S1-mini-GGUF by Superwhisper

S1-mini banner

Website Discord v1

GGUF builds of superwhisper/s1-mini, release v1, for llama.cpp, Ollama, LM Studio, and anything else built on llama.cpp. You can use it in your own dictation app too, just check the license first.

S1-mini is a 0.6B-parameter text normalizer for speech-to-text output. It takes a raw ASR transcript and rewrites it as clean written text: fillers removed, false starts and self-corrections resolved to the value the speaker landed on, punctuation and capitalization applied, and spoken numbers, dates, times, currency and email addresses rendered in written form.

At Q4_K_M it is a 462 MiB file that runs comfortably on a laptop CPU, and on a held-out set of 7,519 English cases it reaches 94.8% token accuracy.

The model covers English only. It is not a chat model and will not follow general instructions; it does one job, and you steer it with a control line at the top of the input. Full documentation lives in the BF16 repository.

Files

File Type Size Notes
s1-mini-q4_k_m.gguf Q4_K_M 462 MB Recommended. The build the published accuracy was measured on.
s1-mini-f16.gguf F16 1.4 GB Unquantized conversion, the intermediate the Q4_K_M is produced from.

Both files share the same skeleton: architecture qwen3, 311 tensors, 28 blocks, a 40,960-token context window, and an embedded chat template. The Q4_K_M build keeps the most quantization-sensitive tensors at Q6_K (29 of 311) and the bulk at Q4_K, while normalization parameters stay F32 in both builds.

The Hub sidebar reports 0.8B parameters for this repo. Qwen3-0.6B sets tie_word_embeddings, but ships lm_head.weight as a materialized copy of the input embedding, so the 155.6M-parameter embedding is counted twice: 751.6M tensor elements against 596.0M unique parameters. Both builds carry that layout through unchanged, and Qwen/Qwen3-0.6B reports 0.8B on the Hub for the same reason. The 0.6B above counts unique parameters.

Input format

Every request needs the system prompt and a control line, exactly as shown.

System prompt:

You are a text normalizer for speech-to-text transcripts. The input begins with a control line specifying the styling, structure, and context settings; clean the transcript to match those settings and output only the cleaned text.

The user message is a control line, then a newline, then the transcript:

[Styling: <value>] [Structure: <value>] [Context: <value>]
<raw transcript>
Axis Values What it does
Styling casual, semi-casual, semi-formal, formal Sets the register: how much capitalization, apostrophe and contraction cleanup to apply.
Structure prose, lists Whether the model may break enumerable content into a bulleted list. It needs at least three items, and anything that isn't really a list stays as prose.
Context general, email Destination conventions. email turns on greeting-line and sign-off-block layout.

The three axes are independent and every combination was trained.

The system prompt and the control line are part of the input format the model was trained on. Skip either one, change the system prompt's wording, or send values outside the trained sets, and the model can hallucinate or produce garbled output. Always send both, exactly as shown.

Filler-only or noise-only input correctly yields an empty string, so treat an empty result as valid rather than as a failure.

Styling

The register decides how much of the speaker's voice survives into the written text. casual writes everything lowercase with apostrophes stripped and colloquialisms kept. semi-casual keeps the speaker's phrasing but capitalizes I and its contractions. semi-formal is standard written English with contractions kept and colloquialisms smoothed (gonna becomes going to), a good default. formal also expands contractions (I am, cannot).

Here is the same input under all four registers:

Input: hmm im gonna be late theres a cute dog outside i cant just walk past him

Styling Output
casual hmm im gonna be late. theres a cute dog outside. i cant just walk past him
semi-casual hmm, I'm gonna be late. there's a cute dog outside. I can't just walk past him
semi-formal I'm going to be late. There's a cute dog outside. I can't just walk past him.
formal I am going to be late. There is a cute dog outside. I cannot just walk past him.

Filled pauses like um and uh are removed in every register.

Structure

prose keeps everything in sentences and paragraphs. lists permits the model to break enumerable content into Markdown bullets, and it is deliberately conservative about it: it wants at least three items, and content that is not clearly an enumeration stays as prose. Here is the same input under both values:

Input: so for the trip we need to pack sunscreen and then also a first aid kit and um chargers for everything

Structure: prose

So for the trip, we need to pack sunscreen and then also a first aid kit and chargers for everything.

Structure: lists

So for the trip, we need to pack:
- Sunscreen
- A first aid kit
- Chargers for everything

Context

general produces flowing text, while email reshapes the transcript into email layout, with a greeting line, the body and a sign-off block separated by blank lines. Here is the same input under both values:

Input: hey sarah just wanted to follow up on the proposal can you send the numbers by end of week thanks john

Context: general

Hey Sarah, just wanted to follow up on the proposal. Can you send the numbers by end of week? Thanks, John.

Context: email

Hey Sarah,

Just wanted to follow up on the proposal. Can you send the numbers by end of week?

Thanks,
John

Two settings that matter

Turn thinking off via the template. The embedded chat template is Qwen3's, which defaults to thinking mode. S1-mini was trained with thinking off, so the assistant turn must start with an empty <think> block, or you will get no usable output. In llama.cpp that means --jinja together with --chat-template-kwargs '{"enable_thinking":false}'. Don't substitute --reasoning-budget 0: it suppresses the think block a different way, and the output degrades (fillers survive into the result).

Use greedy decoding. Normalization is deterministic and sampling only adds variance, so always pass --temp 0 explicitly. Do not rely on the file's defaults: these builds carry general.sampling.temp = 0.6, top_p = 0.95 and top_k = 20 in their metadata, inherited from Qwen3-0.6B rather than from S1-mini, which is trained for greedy decoding. Runtimes differ in whether they honor those keys, and llama.cpp's own default is temperature 0.8, so set it on every request.

llama.cpp

llama-server -hf superwhisper/s1-mini-GGUF:Q4_K_M --jinja --chat-template-kwargs '{"enable_thinking":false}' --temp 0

(Use -m s1-mini-q4_k_m.gguf instead of -hf if you already have the file.)

curl -s http://localhost:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
  "messages": [
    {"role": "system", "content": "You are a text normalizer for speech-to-text transcripts. The input begins with a control line specifying the styling, structure, and context settings; clean the transcript to match those settings and output only the cleaned text."},
    {"role": "user", "content": "[Styling: semi-formal] [Structure: prose] [Context: general]\nso um i need to like send the the report by uh friday no wait make that thursday"}
  ],
  "temperature": 0
}' | jq -r '.choices[0].message.content'
# I need to send the report by Thursday.

Single shot from the command line:

llama-cli -m s1-mini-q4_k_m.gguf --jinja --chat-template-kwargs '{"enable_thinking":false}' --temp 0 -st \
  -sys "You are a text normalizer for speech-to-text transcripts. The input begins with a control line specifying the styling, structure, and context settings; clean the transcript to match those settings and output only the cleaned text." \
  -p "[Styling: semi-formal] [Structure: prose] [Context: general]
so um i need to like send the the report by uh friday no wait make that thursday"
# I need to send the report by Thursday.

If you use the raw /completion endpoint, you need to match the training prefix exactly. The assistant turn opens with an empty think block:

<|im_start|>system
{system prompt}<|im_end|>
<|im_start|>user
{control line}
{transcript}<|im_end|>
<|im_start|>assistant
<think>

</think>

Written out, the assistant prefix is <|im_start|>assistant\n<think>\n\n</think>\n\n, with two newlines inside the think block and two more after it.

Ollama

Hard-code the non-thinking prompt format in the Modelfile rather than relying on a thinking toggle:

FROM ./s1-mini-q4_k_m.gguf

SYSTEM """You are a text normalizer for speech-to-text transcripts. The input begins with a control line specifying the styling, structure, and context settings; clean the transcript to match those settings and output only the cleaned text."""

TEMPLATE """<|im_start|>system
{{ .System }}<|im_end|>
<|im_start|>user
{{ .Prompt }}<|im_end|>
<|im_start|>assistant
<think>

</think>

"""

PARAMETER temperature 0
PARAMETER num_ctx 4096
ollama create s1-mini -f Modelfile
ollama run s1-mini "[Styling: semi-formal] [Structure: prose] [Context: general]
so um i need to like send the the report by uh friday no wait make that thursday"

LM Studio

Load s1-mini-q4_k_m.gguf, set temperature to 0, and disable the thinking/reasoning toggle. If you see <think> tags or get empty output, the template's thinking branch is still active, and the assistant turn needs to begin with the empty think block shown above.

Evaluation

The published number, 94.8% token accuracy on a held-out English test set of 7,519 cases, was measured with greedy decoding on the s1-mini-q4_k_m.gguf build in this repo.

Using S1-mini in your own app

S1-mini is Apache 2.0 plus a naming clause, the same base license it inherits from Qwen3-0.6B, so these builds can be embedded in open-source and commercial software alike: dictation apps, meeting-notes tools, live captioning, voice-driven editors, or any pipeline that has to turn raw ASR output into text a person will read. At 462 MB the Q4_K_M build is small enough to ship on-device.

It is a post-processing stage rather than a standalone system:

audio ──▶ ASR (Whisper, Parakeet, …) ──▶ S1-mini ──▶ clean text

Nothing about the model is Superwhisper-specific. The two things to get right in any integration are the input format documented above and the thinking flag; nearly every integration bug traces back to one of those.

Read the LICENSE before you ship. Apache 2.0 is permissive but not obligation-free: you must retain the license text and attribution notices, and state significant changes if you redistribute a modified version. It also carries one additional term: the model must keep its name, "S1-mini" by "Superwhisper", with that exact capitalization, wherever it's used. If you are bundling S1-mini into a commercial dictation app or redistributing the weights yourself, confirm the terms cover your case rather than assuming they do.

License

S1-mini is released under Apache 2.0, which it inherits from Qwen3-0.6B, plus one additional term: wherever it's used, it must keep its name, "S1-mini" by "Superwhisper", with that exact capitalization. See LICENSE.

Citation

@misc{s1mini2026,
  title  = {S1-mini: a small text normalizer for speech-to-text output},
  author = {Superwhisper},
  year   = {2026},
  url    = {https://huggingface.co/superwhisper/s1-mini}
}

Built on Qwen3:

@misc{qwen3technicalreport,
  title         = {Qwen3 Technical Report},
  author        = {Qwen Team},
  year          = {2025},
  eprint        = {2505.09388},
  archivePrefix = {arXiv},
  primaryClass  = {cs.CL},
  url           = {https://arxiv.org/abs/2505.09388}
}
Downloads last month
286
GGUF
Model size
0.8B params
Architecture
qwen3
Hardware compatibility
Log In to add your hardware

4-bit

16-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for superwhisper/s1-mini-GGUF

Finetuned
Qwen/Qwen3-0.6B
Quantized
(5)
this model

Paper for superwhisper/s1-mini-GGUF