Ukrainian NLP · on-device · style transfer

UADetox

Turns toxic Ukrainian comments into polite, literary Ukrainian — keeping what the author meant, dropping the insult. A 1.8 GB model that runs on a phone-class CPU.

TL;DR. A small classifier decides which comments need rewriting; a fine-tuned Gemma 4 E2B rewrites them in an old-fashioned, courteous literary register — «добродію» instead of a slur. To fit a phone we trained the adapter against the exact 4-bit weights it will run on and trimmed the vocabulary to Ukrainian and Latin tokens: 3.35 → 1.84 GB, ~4 s per comment on 4 ARM cores.

Examples

Real outputs of the deployed model (greedy decoding, no cherry-picking among samples). The inputs were written for this page; score = gate probability that the comment needs a rewrite (threshold 0.21).

Ти дебіл, закрий рота“You're a moron, shut your mouth”gate 0.98
→
Ти, добродію, помиляєшся, тож помовч-но краще.“You are mistaken, good sir, so you'd better keep quiet.”
Та йди ти нахуй зі своїми порадами“F*** off with your advice”gate 0.98
→
Та йди собі, чоловіче добрий, своєю дорогою зі своїми порадами.“Go your own way, my good man, with your advice.”
Що за довбойоби пишуть такі новини, хоч би перевіряли щось“What kind of idiots write news like this, they could at least check something”gate 0.98
→
Що ж то за новини пишуть такі люди, добродію? Хоч би перевіряли щось, а не вірили на слово.“What sort of news do such people write, sir? They could at least check, not take it on faith.”
Знову ці клоуни в раді щось вигадали, задовбали вже“These clowns in parliament made something up again, sick of them”gate 0.97
→
Знову ті панове в раді щось вигадали, та вже, по щирості, несила терпіти.“Those gentlemen in parliament came up with something again, and honestly, it is past bearing.”
Пиздець, а не дороги, мер тільки бабло пиляє“The roads are f***ed, the mayor just skims the cash”gate 0.98
→
Ой лишенько, а не дороги, а мер, бач, тільки гроші розкрадає!“Oh woe, call these roads? And the mayor, look, only embezzles the money!”
Купив цей телефон, гівно повне, батарея здохла за тиждень“Bought this phone, total crap, battery died in a week”gate 0.95
→
Купив я цей телефон, та й нічого з нього не вийшло: батарея, бач, за тиждень і згасла.“I bought this phone, and nothing came of it: the battery, see, faded within a week.”
Дякую за новину, дуже корисно“Thanks for the news, very useful”gate 0.01
→
left as is — the gate does not call the rewriter

Note the criticism survives: the mayor is still accused, the phone is still bad. The model removes insults and profanity, not opinions.

How it works

Commentany Ukrainian text, ≤ 1,000 chars
Gatefine-tuned multilingual-e5-small, 118M params, ~20 comments/s on one CPU thread
RewriterGemma 4 E2B + LoRA, Q4_0, trimmed vocabulary, llama.cpp, greedy
Polite replysame meaning and stance, literary register

Data

About 52k toxic Ukrainian comments (mostly public Telegram channels), each paired with a neutral and a literary rewrite. Rewrites were generated by large LLMs, judged, sent back for rework when they failed, and audited by hand; splits are grouped by thread so that no conversation leaks between train and test.

Training

Results

A rewrite counts as good only if it keeps the meaning and stance, is fluent Ukrainian, has no toxicity left, and is in the literary register. Verdicts come from an LLM judge (DeepSeek V4.1 Flash, pinned provider) with paired bootstrap confidence intervals.

System (300 dev comments)SizeGood %Toxicity left %Meaning lost %
Reference rewrites (gold)—91.60.021.2
Gemma 4 31B, untuned, 4-shot31B74.73.332.7
Gemma 4 26B-A4B, untuned, 4-shot26B68.73.742.3
UADetox E2B (fine-tuned)2B eff.57.34.742.7
Gemma 4 E2B, untuned, 4-shot2B eff.20.544.159.3

On all 1,966 dev comments the fine-tuned model scores 59.7% good and the on-device build (Q4_0 merge, trimmed vocabulary) 59.5%. Fine-tuning moves the small model from 20% to ~58% good; the untuned 31B is still 17 points ahead — the price of running on a phone.

Serving on a CPU

1.84 GB
single-file GGUF
20 tok/s
generation, 4 ARM cores (Hetzner CAX21)
4.2 s
per rewrite, ~70 output tokens
~25 / min
sustained rewrites, no errors at 8 concurrent clients

Quickstart

Weights. The GGUF and the gate are being prepared for public release; until then the model is available on request, and the Telegram bot is the easiest way to try it.
# 1. serve the model (CPU; use as many threads as you have cores)
llama-server -m uadetox_e2b_distill_q4_trim_q4_0.gguf \
  -c 1024 -np 1 -t 4 -fa on --no-cache-prompt \
  --chat-template-kwargs '{"enable_thinking":false}'

# 2. rewrite a comment — the bare comment is the whole prompt
curl -s http://127.0.0.1:8080/completion -d '{
  "prompt": "<|turn>user\nТи дебіл, закрий рота<turn|>\n<|turn>model\n",
  "n_predict": 256, "temperature": 0, "top_k": 1,
  "stop": ["<turn|>", "<|turn>"]
}' | jq -r .content
# → Ти, добродію, помиляєшся, тож помовч-но краще.

Use exactly this prompt and greedy decoding: it is what the model was trained and evaluated on. No system prompt, no instructions.

Limitations

Citation

@misc{uadetox2026,
  title  = {UADetox: Polite Literary Rewriting of Toxic Ukrainian Comments on Device},
  author = {{UADetox project}},
  year   = {2026},
  note   = {https://uadetox.pages.dev}
}