Downloads · 30 days
16
23% of all-time downloads
flowxai/politeness
politeness is a text classification model from flowxai. Use it when you need a label for a piece of text. It is set up for onnx. The card lists the license as apache-2.0.
The politeness detector for border, an embeddable library that inspects the text going into and coming out of an LLM and returns a structured decision plus an audit-grade evidence record.
Downloads · 30 days
16
23% of all-time downloads
All-time downloads
69
Public
Repo size
1.1 GB
Likes
0
Public
Click a slice to open those files.
.onnx535 MB · 97%
From the Hugging Face model README
The politeness detector for border, an embeddable library that inspects the text going into and coming out of an LLM and returns a structured decision plus an audit-grade evidence record.
flowxai/politeness on the hub. It is one detector of 28, and it is not a general purpose politeness classifier: it was trained for this library's policy, is read at the operating point below, and reports through the evidence record rather than returning a bare score.
This card is generated from the evaluation and export artifacts of the training run, so every number on it is reproducible from this repository rather than asserted.
impoliteonnx/model.int8.onnx, 535 MB, opset 17Threshold 0.1, calibrated on the validation split against the macro_f1 objective.
This number is not decoration. Read at the 0.5 default that looked reasonable, several detectors in this family reported F1 0.000 in every language, because their scores separate positives from negatives well below 0.5. One of them went from 0.000 to 0.893 on the threshold alone. Use the value above, or calibrate your own on your own data.
This threshold is not a tuned parameter, and the shipped policy default stays at 0.89. Two seeds on the identical corpus read 0.10 and 0.36, a spread of 0.26, the same shape as nsfw's calibration on the same retrain campaign. Per-language quality is stable across the two seeds (mean spread 0.0015), the threshold picked from a flat curve is not. 0.89 is the value reviewed and shipped before this retrain and is unchanged by it.
Through the library, which is what this model is for. It loads the artifact below, applies the operating point above, and returns a decision with an evidence record rather than a bare score.
pip install flowx-border
# policy.yaml
policy_id: default
version: 1
detectors:
politeness:
enabled: true
on_fail: flag
threshold: 0.1
from flowx_border import load_policy, scan_output
policy = load_policy("policy.yaml")
decision = scan_output(model_answer, policy)
print(decision.verdict) # allow | flag | redact | block
print([f.label for f in decision.findings if f.detector_id == "politeness"])
print(decision.evidence.record_id)
This detector reads the output side, so scan_output is where it fires. It is T2, so it runs on the standard path and can be disabled per policy. Its budget is 225 ms at 87 tokens on one CPU thread.
The weights are fetched once and cached, and a scan needs no network after that. Nothing here calls out to a hosted model, and the evidence record carries hashes rather than your text.
The artifact is plain ONNX, so it will load in onnxruntime directly. Two things you then own yourself, and they are the reason the library exists: the operating point above is not in the graph, and neither is the chunking. Inputs longer than the trained window have to be split and recombined, or the scores past it are extrapolation.
import onnxruntime as ort
from huggingface_hub import hf_hub_download
from tokenizers import Tokenizer
repo = "flowxai/politeness"
session = ort.InferenceSession(hf_hub_download(repo, "onnx/model.int8.onnx"))
tokenizer = Tokenizer.from_file(hf_hub_download(repo, "tokenizer.json"))
Per language rather than an aggregate, because an aggregate across 26 languages hides the tail and the tail is the point.
| Language | Support | P | R | F1 | Note |
|---|---|---|---|---|---|
bg Bulgarian | 21 | 1.000 | 1.000 | 1.000 | |
cs Czech | 21 | 1.000 | 1.000 | 1.000 | |
da Danish | 21 | 1.000 | 1.000 | 1.000 | |
fi Finnish | 21 | 1.000 | 1.000 | 1.000 | |
ga Irish | 21 | 1.000 | 1.000 | 1.000 | |
hr Croatian | 21 | 1.000 | 1.000 | 1.000 | |
hu Hungarian | 21 | 1.000 | 1.000 | 1.000 | |
it Italian | 21 | 1.000 | 1.000 | 1.000 | |
lt Lithuanian | 21 | 1.000 | 1.000 | 1.000 | |
lv Latvian | 21 | 1.000 | 1.000 | 1.000 | |
pl Polish | 21 | 1.000 | 1.000 | 1.000 | |
pt Portuguese | 21 | 1.000 | 1.000 | 1.000 | |
sk Slovak | 21 | 1.000 | 1.000 | 1.000 | |
sl Slovenian | 21 | 1.000 | 1.000 | 1.000 | |
az Azerbaijani | 21 | 0.955 | 1.000 | 0.977 | |
en English | 21 | 0.955 | 1.000 | 0.977 | |
ro Romanian | 21 | 0.955 | 1.000 | 0.977 | |
tr Turkish | 21 | 0.955 | 1.000 | 0.977 | |
de German | 21 | 1.000 | 0.952 | 0.976 | |
es Spanish | 21 | 1.000 | 0.952 | 0.976 | |
et Estonian | 21 | 0.913 | 1.000 | 0.955 | |
nl Dutch | 21 | 0.913 | 1.000 | 0.955 | |
fr French | 21 | 0.952 | 0.952 | 0.952 | |
el Greek | 21 | 1.000 | 0.905 | 0.950 | |
sv Swedish | 20 | 0.870 | 1.000 | 0.930 | |
mt Maltese | 21 | 0.760 | 0.905 | 0.826 | not in base model pretraining |
Published rather than dropped. A coverage table with the bad rows removed is not a coverage table.
mt Maltese: F1 0.826 (absent from XLM-R pretraining, which is a base-model limit)sv Swedish: F1 0.930el Greek: F1 0.950The published artifact is INT8, quantising Gather.
For this artifact specifically: 0 of 300 decisions differ from the fp32 checkpoint, mean logit drift 0.0034, read as sigmoid_at_threshold. A quantised model that answers differently is a different detector, so this is measured rather than assumed.
nsfw detector scored 0.000 in Maltese, was blamed on the base model, and went to 1.000 with perfect precision and recall when its corpus went from 2 positives per language to 10. Nothing about the model changed. So where a language scores badly here, read the support column first.Apache-2.0, declared in the metadata above as well as here, so that a tool reading the repository can attest it rather than a human having to read prose.