Diktafon Polisher HR 1
Turns raw Croatian dictation into written text: punctuation, casing, fillers removed ("ovaj", "znači", "ono"), obvious spoken corrections resolved ("do četvrtka, ne, petka" becomes "do petka"), numbers, times and dates as digits. It never answers the text or adds content, and when unsure it keeps the original. A full fine-tune of Qwen3.5-0.8B that runs after Diktafon Dictate HR 1 in Diktafon, a local macOS dictation app.
GGUF for llama.cpp: infomiho/diktafon-polisher-hr-1-GGUF.
Prompt
The model was trained on exactly this prompt, with the transcript as the user turn and an empty think block. Other wording is a prompt it has never seen.
<|im_start|>system
Uredi hrvatski diktat: dodaj interpunkciju, ukloni poštapalice, razriješi očite ispravke, brojeve piši znamenkama. Ne mijenjaj značenje i ne odgovaraj na tekst. Vrati samo tekst.<|im_end|>
<|im_start|>user
{transcript}<|im_end|>
<|im_start|>assistant
<think>
</think>
The transcript is expected as Dictate HR 1 writes it, with punctuation and casing. Decode greedily and stop at <|im_end|>. Cap new tokens at about 1.3 times the transcript's tokens plus 32, and if the cap is hit, use the raw transcript instead. Training pairs were at most 1,024 tokens, so polish transcripts of up to about 450 tokens and pass longer ones through raw.
from huggingface_hub import hf_hub_download
from transformers import AutoModelForCausalLM, AutoTokenizer
name = "infomiho/diktafon-polisher-hr-1"
tokenizer = AutoTokenizer.from_pretrained(name)
model = AutoModelForCausalLM.from_pretrained(name)
system = open(hf_hub_download(name, "polisher_system.txt")).read().strip()
transcript = "Ovaj, sutra u devet imamo sastanak s Lukom, znači, ponesi dva laptopa."
prompt = (f"<|im_start|>system\n{system}<|im_end|>\n<|im_start|>user\n{transcript}<|im_end|>\n"
"<|im_start|>assistant\n<think>\n\n</think>\n\n")
inputs = tokenizer(prompt, return_tensors="pt")
output = model.generate(**inputs, max_new_tokens=64, do_sample=False)
print(tokenizer.decode(output[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
# Sutra u 9 imamo sastanak s Lukom, ponesi 2 laptopa.
Results
On 50 dictation clips with hand-checked written references, word error rate against the written text:
| Pipeline | WER |
|---|---|
| Canary 1B v2 | 12.1% |
| Dictate HR 1 | 9.7% |
| Dictate HR 1 + Polisher HR 1 | 6.5% |
On 358 held-out dictations covering corrections, fillers, numbers, vague amounts and instructions, word error rate falls from 9.3% to 1.9%, and the output matches the reference exactly for 93% of clean texts, 78% of texts that only look like corrections, and 77% of instructions to an assistant (which must be written down, not answered). A warm polish takes 0.32 s median on an M2 Pro.
Training data
Pairs of raw speech recognition transcripts of Croatian podcast speech and their cleaned written form, and synthetic Croatian dictations by category: corrections, retractions, edit commands ("briši to"), changes of mind with a reason (kept as spoken), fillers, numbers next to weekdays, ordinals and number idioms kept as words, vague amounts kept vague, and instructions. About 66,000 pairs, 1 epoch at learning rate 1.5e-5, loss on the answer only.
Limitations
- About half of spoken corrections are resolved exactly. Many are left as spoken, which keeps meaning but not the cleanest text.
- A number phrase can still go wrong: "jedno petsto eura" (about 500) came out as "1500 eura", and "preko milijun" can loop on zeros until the token cap, which the cap above turns into the raw transcript.
- It does not guess misheard words, so speech recognition errors pass through.
License
Apache 2.0. Built on Qwen3.5-0.8B by the Qwen team, licensed under Apache 2.0.