rabwa-mask

rabwa-mask is a small, CPU-only model that finds personal data in Arabic (Gulf / Saudi dialect) and English text.

It ships with a reversible redaction helper. The typical flow:

  1. Mask: names, phone numbers, IDs, IBANs and home addresses become placeholders such as [PERSON_1].
  2. Send the masked text to any external LLM API.
  3. Restore: the real values go back into the reply on your side.

The raw text never leaves your server.

in   : Please call Sara Al-Harbi on 0551234567 or write to sara.h@example.com
out  : Please call [PERSON_1] on [PHONE_1] or write to [EMAIL_1]
reply: Sure, we will call [PERSON_1] today.   ->   Sure, we will call Sara Al-Harbi today.

The same works for Arabic script, mixed Arabic/English text and Arabic-Indic digits.

Why this model

Teams that pass customer notes, chat messages or support tickets to a hosted LLM leak personal data in free text. Regexes catch phone numbers and e-mails, but not names.

Arabic names are especially hard to catch:

  • Structure: they have 2 to 4 parts, with bin / bint, the article al-, and kunyas such as Abu Fahd / Umm Khalid.
  • Glued prepositions: one-letter prepositions and conjunctions attach directly to the name.
  • Names that are also words: many names are ordinary words too, like Jameel, Kareem, Amal and Noor.
  • Places named after people: streets, banks and hospitals carry people's names.

General multilingual NER models and small chat LLMs miss too many of these. rabwa-mask was fine-tuned for exactly this job, and it runs in a few milliseconds on a CPU.

Use cases

  • Safe LLM calls. Mask CRM notes, tickets or chat messages before sending them to a hosted LLM, then restore the names in the answer.
  • Customer-service and sales assistants. Let an internal assistant answer questions about customers while the model provider only ever sees codes.
  • Log and analytics scrubbing. Remove personal data from application logs, call notes or survey answers before storing or sharing them.
  • Dataset anonymisation. Clean Arabic / English text corpora before using them for training, evaluation or research.
  • Document review. Find and highlight personal data in contracts, forms or e-mails before they are shared outside the team.
  • Compliance. Support data-minimisation duties under privacy laws such as Saudi PDPL or GDPR. It is one technical control, not a legal guarantee.
  • Privacy "try it" pages. Show staff exactly what an external model would receive. The helper returns the masked text, the detected values and the restored text.

What it detects

Label What Found by
PERSON full or partial names, kunyas, English spellings model
ADDRESS a person's home address (district, street, building), Saudi national short address model + rule
PHONE Saudi mobiles and landlines in any format: 05..., +966..., 00966..., spaces, dashes, Arabic-Indic digits rules
EMAIL e-mail addresses rules
NID Saudi national ID (10 digits, starts with 1) rules
IQAMA Saudi residence permit (10 digits, starts with 2) rules
IBAN Saudi IBAN (SA + 22 digits, spaced or not) rules
PLATE Saudi car plates, Arabic or Latin letters rules
  • Who owns which label: the model also tags the fixed formats. Regexes are exact there, so the helper lets the rules own them and takes only names and addresses from the model.
  • Tag scheme: BIO tags: O, then B- and I- for each of the eight labels.

Quick start (Python, ONNX, CPU)

git clone https://huggingface.co/mad-nasher/rabwa-mask && cd rabwa-mask
pip install -r requirements.txt     # onnxruntime, tokenizers, numpy
python pii_redact.py "Please call Sara Al-Harbi on +966 55 123 4567, her IBAN is SA44 2000 0001 2345 6789 1234"
from pii_redact import Redactor

r = Redactor(threads=1)                    # load once, reuse
masked, mapping = r.redact(user_text)      # send `masked` to the LLM
answer = r.restore(llm_reply, mapping)     # real values back; unknown placeholders raise
  • One mapping per request. Pass the same mapping to redact() for every field of one request. Keep it in memory only and drop it afterwards.
  • Same value, same placeholder. A value that appears twice gets one placeholder, and every occurrence in the text is masked.
  • Fail closed. If the model can't be loaded or raises, don't send the text.

Using it with transformers

The full-precision weights (model.safetensors) work with the standard token-classification pipeline. Use this route for further fine-tuning or for GPU batch jobs:

from transformers import pipeline

ner = pipeline(
    "token-classification",
    model="mad-nasher/rabwa-mask",
    aggregation_strategy="simple",
)
for ent in ner(text):
    print(ent["entity_group"], ent["start"], ent["end"], round(ent["score"], 3))

The pipeline returns the model's raw spans. Masking, placeholders and the regex rules live in pii_redact.py; reuse its RULES if you need the exact phone / ID / IBAN behaviour.

Using it from Node.js

The ONNX file runs with onnxruntime-node and a plain BERT WordPiece tokenizer (tokenizer.json, no lower-casing).

  • Model inputs: input_ids, attention_mask, token_type_ids.
  • Model output: one logit per label for each token; take the arg-max.
  • Windows: split long text into windows of about 300 characters (128 tokens).

Results

These numbers come from a held-out synthetic test set of 780 Gulf-Arabic / English sentences:

  • What the sentences are: CRM-style notes, assistant questions and WhatsApp-style messages, built from random combinations of common names.
  • Sentences with no personal data: 179.
  • Hard negatives: 545 company, bank, place, street and project names, plus words that are also names.
  • Unseen material: the test sentence templates, and a quarter of the names, were never seen in training.

"Fully masked" means every letter of the entity is covered. Masking half a name counts as a leak.

Fully masked Precision Recall
names (PERSON, 537) 97.2% 0.93 0.98
addresses (ADDRESS, 110) 99.1% 0.74 0.99
phone / e-mail / ID / iqama / IBAN / plate (326) 100% 1.00 1.00
all personal data 98.4%
hard negatives wrongly masked 10 of 545 (1.8%)
  • Adding a name list helps. Combined with a list of common first and family names, and a short list of your own brand and product names that must never be masked, name masking reached 99.4% in our tests (99.6% for all personal data).
  • The data is synthetic. Real text will be messier. Test the model on your own data before relying on it.

Speed and size

Measured on Redactor.detect, Apple M3 CPU; a server CPU will differ.

1 thread 4 threads
short message (~55 chars) ~12 ms ~5 ms
1,500 characters ~330 ms ~105 ms
  • ONNX model: 105 MB (int8, per-channel; same accuracy as fp32).
  • Memory: a process running it needs about 250 MB of RAM.

Compared with alternatives

Same test set. Each alternative was combined with the same regex rules and name list.

Model Names fully masked Short-request time (1 thread) Size
rabwa-mask 99.4% ~12 ms 105 MB
CAMeLBERT-NER, off the shelf 82% similar 414 MB
GLiNER multi v2.1, zero-shot 92% ~36 ms 1.1 GB
Qwen2.5-3B-Instruct, prompted 87% ~4 s 1.9 GB

Known limits

  • One-word names that are also common words can be missed when they appear alone, for example a greeting that ends with the name Amal.
  • Some places named after people get masked too, such as streets named after princes or a hospital named after a doctor. Over-masking is the safe direction.
  • Only Saudi formats are covered by the phone, ID, IBAN and plate rules. Add your own rules for other countries.
  • Text is read in windows of about 300 characters (128 tokens), so long documents take longer.
  • Not a legal guarantee. Use it as one layer of a privacy design. Keep logging off for raw text, keep mappings in memory only, and fail closed.

Files

File
onnx/model.int8pc.onnx int8 ONNX model used by pii_redact.py (CPU)
model.safetensors full-precision PyTorch weights (transformers, fine-tuning)
config.json model config and label map
tokenizer.json, tokenizer_config.json, special_tokens_map.json, vocab.txt BERT WordPiece tokenizer, no lower-casing
pii_redact.py detection + reversible redaction helper
requirements.txt Python dependencies for the helper
SHA256SUMS checksums of the model files
LICENSE, NOTICE Apache 2.0 licence and attribution

Training

  • Base model: fine-tuned from CAMeL-Lab/bert-base-arabic-camelbert-mix-ner.
  • Data: 1,600 synthetic sentences.
  • Settings: 6 epochs, learning rate 5e-5, on Apple MPS (about one minute).
  • Stability: three training seeds gave the same accuracy within 0.3 points.
  • Export: ONNX, then quantised to int8 per channel.

No real personal data was used. Every name in the training and test data is a random combination of common given and family names.

License

Apache License 2.0, the same as the base model. See LICENSE and NOTICE.

Citation

@misc{rabwa_mask_2026,
  title  = {rabwa-mask: reversible PII redaction for Gulf Arabic and English text},
  author = {Nasher},
  year   = {2026},
  url    = {https://huggingface.co/mad-nasher/rabwa-mask}
}

Please also cite the CAMeLBERT base model:

@inproceedings{inoue-etal-2021-interplay,
  title     = {The Interplay of Variant, Size, and Task Type in Arabic Pre-trained Language Models},
  author    = {Inoue, Go and Alhafni, Bashar and Baimukan, Nurpeiis and Bouamor, Houda and Habash, Nizar},
  booktitle = {Proceedings of the Sixth Arabic Natural Language Processing Workshop},
  year      = {2021}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for mad-nasher/rabwa-mask

Quantized
(1)
this model