UADetox gate: which Ukrainian comments need a rewrite

A small binary classifier that decides whether a Ukrainian comment is rude or toxic enough to be sent to the rewriter Housto4/uadetox-e2b. It is intfloat/multilingual-e5-small (118M parameters) fully fine-tuned as a sequence classifier. It takes about 11 ms per comment on 4 CPU threads.

Project page: uadetox.pages.dev. Live demo (gate + rewriter): Housto4/uadetox.

Output: P(needs rewrite) = softmax(logits)[1]. Input: the comment text only, truncated to 128 tokens.

Files

file what
model.safetensors, config.json, tokenizer.json, tokenizer_config.json the model for transformers (fp16 weights)
model.onnx the same model exported to ONNX (fp32, opset 17; inputs input_ids, attention_mask; output logits). Scores match the PyTorch model to within 2e-6.
gate_config.json thresholds and evaluation metrics

Thresholds

threshold use locked test: recall false-positive rate precision comments flagged
0.208 operating point (used in production) 59.9% 3.9% 0.91 25.8%
0.127 95% recall on the in-domain dev set 65.8% 6.3% 0.87 29.6%

Choose a lower threshold if missing a rude comment costs more than an unnecessary rewrite.

Evaluation

set n labels PR-AUC other
held-out channels (whole channels never seen in training) 55,503 training-style labels 0.896 recall 86.5% at 5% false positives
locked policy test (natural mix of the held-out channels, 39% need a rewrite) 2,000 a written rewrite policy, applied by an LLM labeller 0.861 see thresholds above

Share of comments that need a rewrite and are caught, locked test, by type of toxicity (threshold 0.208): profanity 90%, identity attack 76%, insult 74%, threat 52%, implicit 26%.

At threshold 0.127 (6% false positives), by hard case: comments with a swear word 100%, attacks without a swear word 57%, mocking or sarcasm only 17%, mild comments 33%.

Training data

227,552 Telegram comments from 74 public Ukrainian channels, two epochs, learning rate 5e-5.

  • Label 1: comments from the UADetox dataset and other scraped comments that an LLM judged toxic under the written policy.
  • Label 0: comments the LLM judged not toxic, including hard negatives that contain a flagged word or scored high on an automatic toxicity score, plus a large sample of unscreened comments from the same channels (most comments are not toxic, so they serve as weak negatives).

Candidates for LLM labelling were pre-filtered by an automatic toxicity score and keyword matches. Whole channels were held out for testing, and comments overlapping the UADetox validation and test splits were removed.

Usage

transformers

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

repo = "Housto4/uadetox-gate"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForSequenceClassification.from_pretrained(repo, dtype=torch.float32).eval()

comments = ["ะขะฐ ะนะดะธ ั‚ะธ ะทั– ัะฒะพั—ะผะธ ะฟะพั€ะฐะดะฐะผะธ, ะดัƒั€ะฝัŽ", "ะ”ัะบัƒัŽ ะทะฐ ะฝะพะฒะธะฝะธ!"]
enc = tok(comments, truncation=True, max_length=128, padding=True, return_tensors="pt")
with torch.no_grad():
    p = torch.softmax(model(**enc).logits, -1)[:, 1]
needs_rewrite = (p >= 0.208).tolist()

onnxruntime

import numpy as np, onnxruntime as ort
from huggingface_hub import hf_hub_download
from tokenizers import Tokenizer

repo = "Housto4/uadetox-gate"
sess = ort.InferenceSession(hf_hub_download(repo, "model.onnx"))
tok = Tokenizer.from_file(hf_hub_download(repo, "tokenizer.json"))
tok.enable_truncation(128); tok.enable_padding(pad_id=1, pad_token="<pad>")

enc = tok.encode_batch(["ะขะฐ ะนะดะธ ั‚ะธ ะทั– ัะฒะพั—ะผะธ ะฟะพั€ะฐะดะฐะผะธ, ะดัƒั€ะฝัŽ", "ะ”ัะบัƒัŽ ะทะฐ ะฝะพะฒะธะฝะธ!"])
feed = {"input_ids": np.array([e.ids for e in enc], dtype=np.int64),
        "attention_mask": np.array([e.attention_mask for e in enc], dtype=np.int64)}
logits = sess.run(None, feed)[0]
p = np.exp(logits) / np.exp(logits).sum(-1, keepdims=True)
needs_rewrite = p[:, 1] >= 0.208

Limitations

  • It catches swearing almost always, but mocking, sarcasm and insults without swear words much less often (17% and 57% at 6% false positives). Its training labels marked many such comments as clean.
  • Mild rudeness is often let through (about a third caught).
  • Trained on Telegram comments about news and politics; other platforms and topics are less tested.
  • Labels come from an LLM following a written policy, not from human annotators; agreement with a small human-labelled gold set is moderate (ฮบ โ‰ˆ 0.4).
  • It is a routing filter for a rewriter, not a moderation decision. Do not use it alone to block or punish users.

License

MIT, as the base model.

Citation

@misc{uadetox_gate_2026,
  title  = {UADetox gate: a Ukrainian rewrite-needed classifier},
  author = {Housto4},
  year   = {2026},
  howpublished = {\url{https://huggingface.co/Housto4/uadetox-gate}}
}
Downloads last month
23
Safetensors
Model size
0.1B params
Tensor type
F16
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for Housto4/uadetox-gate

Quantized
(308)
this model

Space using Housto4/uadetox-gate 1

Collection including Housto4/uadetox-gate

Evaluation results

  • PR-AUC on Locked policy-labelled test (2,000 comments from held-out Telegram channels)
    self-reported
    0.861
  • Recall at threshold 0.208 on Locked policy-labelled test (2,000 comments from held-out Telegram channels)
    self-reported
    0.599
  • Precision at threshold 0.208 on Locked policy-labelled test (2,000 comments from held-out Telegram channels)
    self-reported
    0.907