Views
No views yet
piiguard 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/piiguard on the hub. It is one detector of 28, and it is not a general purpose piiguard 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.O, B-PERSON, I-PERSON, B-EMAIL, I-EMAIL, B-PHONE, I-PHONE, B-NATIONAL_ID, I-NATIONAL_ID, B-IBAN, I-IBAN, B-CARD, I-CARD, B-DATE, I-DATE, B-LOCATION, I-LOCATIONonnx/model.fp16.onnx, 555 MB, opset 17pip install flowx-border1# policy.yaml
2policy_id: default
3version: 1
4
5detectors:
6 piiguard:
7 enabled: true
8 on_fail: flag1from flowx_border import load_policy, scan_input, scan_output
2
3policy = load_policy("policy.yaml")
4
5decision = scan_input(user_text, policy)
6decision = scan_output(model_answer, policy)
7
8print(decision.verdict) # allow | flag | redact | block
9print([f.label for f in decision.findings if f.detector_id == "piiguard"])
10print(decision.evidence.record_id)scan_input and scan_output is where it fires. It is T2, so it runs on the standard path and can be disabled per policy.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.1import onnxruntime as ort
2from huggingface_hub import hf_hub_download
3from tokenizers import Tokenizer
4
5repo = "flowxai/piiguard"
6session = ort.InferenceSession(hf_hub_download(repo, "onnx/model.int8.onnx"))
7tokenizer = Tokenizer.from_file(hf_hub_download(repo, "tokenizer.json"))| Language | Support | P | R | F1 | Note |
|---|---|---|---|---|---|
az Azerbaijani | 164 | 1.000 | 1.000 | 1.000 | |
bg Bulgarian | 180 | 1.000 | 1.000 | 1.000 | |
da Danish | 124 | 1.000 | 1.000 | 1.000 | |
de German | 212 | 1.000 | 1.000 | 1.000 | |
el Greek | 144 | 1.000 | 1.000 | 1.000 | |
en English | 180 | 1.000 | 1.000 | 1.000 | |
es Spanish | 180 | 1.000 | 1.000 | 1.000 | |
et Estonian | 188 | 1.000 | 1.000 | 1.000 | |
fi Finnish | 164 | 1.000 | 1.000 | 1.000 | |
hr Croatian | 152 | 1.000 | 1.000 | 1.000 | |
hu Hungarian | 224 | 1.000 | 1.000 | 1.000 | |
lt Lithuanian | 148 | 1.000 | 1.000 | 1.000 | |
lv Latvian | 156 | 1.000 | 1.000 | 1.000 | |
mt Maltese | 164 | 1.000 | 1.000 | 1.000 | not in base model pretraining |
nl Dutch | 160 | 1.000 | 1.000 | 1.000 | |
pl Polish | 180 | 1.000 | 1.000 | 1.000 | |
pt Portuguese | 172 | 1.000 | 1.000 | 1.000 | |
ro Romanian | 192 | 1.000 | 1.000 | 1.000 | |
sk Slovak | 188 | 1.000 | 1.000 | 1.000 | |
sl Slovenian | 152 | 1.000 | 1.000 | 1.000 | |
sv Swedish | 132 | 1.000 | 1.000 | 1.000 | |
tr Turkish | 172 | 0.994 | 0.994 | 0.994 | |
it Italian | 172 | 0.988 | 0.988 | 0.988 | |
cs Czech | 164 | 0.976 | 1.000 | 0.988 | |
ga Irish | 160 | 0.976 | 1.000 | 0.988 | |
fr French | 148 | 0.987 | 0.987 | 0.987 |
fr French: F1 0.987ga Irish: F1 0.988cs Czech: F1 0.988character spans. 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.