--- license: other license_name: per-model-licenses license_link: https://huggingface.co/ekacare/document-pii-redactor#license-and-attribution tags: [pii, redaction, document-ai] --- # document-pii-redactor model weights **Try it live:** [medai.eka.care/pii-redactor](https://medai.eka.care/pii-redactor) (faster), or the [Hugging Face Space](https://huggingface.co/spaces/ekacare/document-pii-redactor) — upload a document image or paste text and see detection + redaction run in your browser. Background and design notes are in the [launch blog](https://info.eka.care/services/releasing-parrotlet-open-models-open-weights-for-medical-document-intelligence). Most PII redactors stop at plain text. These models power [document-pii-redactor](https://github.com/eka-care/document-pii-redactor), which also redacts **document images** and is light enough to deploy on **CPU**. They are trained to understand **Indian names, documents, and contexts**, and the text model works across **Indian languages**. The main contribution is the **PII token classifier** — OCR is just the pluggable input stage in front of it. It defaults to lightweight **Tesseract**, which keeps memory low and works well for PDFs and good-quality images; for more difficult or blurred images, **Bring-your-own OCR** lets a model like [**Nemotron OCR**](https://huggingface.co/nvidia/nemotron-ocr-v2) (or Textract, Google Vision, etc) plug straight in for better results ([example notebook](https://github.com/eka-care/document-pii-redactor/blob/main/examples/byo_ocr_nemotron.ipynb)). Single repo holding the models used by the document-pii-redactor GitHub repo (https://github.com/eka-care/document-pii-redactor), organized by modality. You can use the document-pii-redactor repo directly to use these models — it has the library, a Docker image, and a FastAPI server. - `image/layoutlmv3/` — a text-in-image classifier for **text PII in images** (47 categories), run on Tesseract OCR words. - `image/yolo/best.pt` — a detector for **visual entities** (signature, seal/stamp, QR/barcode, face photo, fingerprint, logo). - `text/minilm/` — a lightweight multilingual classifier for **PII in plain text** (no image, no OCR). ## Install ```bash pip install "document-pii-redactor[visual]" # full pipeline, used by the examples below (AGPL-3.0 — see License below) pip install document-pii-redactor # text pipeline + built-in OCR only, no visual entities (permissive licenses) ``` `ImagePIIRedactor` detects **visual entities** by default — PII that is an image region rather than readable text: signatures, seals/stamps, QR codes/barcodes, face photos, fingerprints, and logos. That detector needs the `[visual]` extra, so the image examples below assume it — or pass `detect_visual=False` to detect only text PII on the core install. System dependency: **Tesseract OCR** — used by the **image** modality's built-in OCR step. Not needed for the text-only modality, nor if you bring your own OCR (`detect(..., words=..., boxes=...)`). ```bash # Debian/Ubuntu sudo apt-get install -y tesseract-ocr # macOS brew install tesseract ``` ## Usage **`detect()` is the core primitive** — it finds every PII entity with its location, category, and confidence, and runs the models exactly once. The transforms (redact / anonymize / de-identify) take its result as a required argument: detect once, feed the result to any transform. ```python from document_pii_redactor import ImagePIIRedactor, TextPIIRedactor image_redactor = ImagePIIRedactor("ekacare/document-pii-redactor") entities = image_redactor.detect("page.jpg") # built-in Tesseract OCR # each entity: kind ("text"/"visual"), category, bbox (pixels), text, score # …or bring your own OCR — pass words + pixel boxes, Tesseract is skipped # and your exact boxes come back on the detected entities: entities = image_redactor.detect("page.jpg", words=["John", "Doe"], boxes=[[100, 20, 140, 40], [145, 20, 180, 40]]) text_redactor = TextPIIRedactor("ekacare/document-pii-redactor") text = "Mr. John Doe, 45 yrs, DOB 12-03-1979, Indiranagar, Bangalore. Contact: +91 98765 43210." spans = text_redactor.detect(text) # char-offset spans ``` **Redact** — destroy: ```python image_redactor.redact("page.jpg", entities, mode="blur").save("redacted.png") # or "solid" / "pixelate" text_redactor.redact(text, spans) # '[REDACTED], [REDACTED] yrs, DOB [REDACTED], [REDACTED], [REDACTED]. Contact: [REDACTED].' ``` **Anonymize** — generalize, one-way, no mapping kept. Ages become 10-year buckets, dates keep only the year, fine geography collapses to `[LOCATION]` (state and country survive), everything else becomes an unnumbered token; faces/signatures are filled solid: ```python image_redactor.anonymize("page.jpg", entities).save("anonymized.png") text_redactor.anonymize(text, spans) # '[PERSON], 40–49 yrs, DOB 1979, [LOCATION], [LOCATION]. Contact: [PHONE].' ``` **De-identify** — pseudonymize. Same value → same pseudonym throughout the document (rendered in place in images; faces/signatures become neutral placeholders), and the entity→pseudonym mapping comes back for authorized re-linking — yours to store securely, never persisted by the library. `strategy="hash"` gives globally deterministic tokens that stay stable across documents with no mapping to thread (`secret=` salts the hash so guessable values can't be dictionary-reversed): ```python deid = image_redactor.deidentify("page.jpg", entities) # .image + .mapping deid.image.save("deidentified.png") text_redactor.deidentify(text, spans).text # 'Person_1, Age_1 yrs, DOB Date_1, City_1, City_2. Contact: Phone_1.' text_redactor.deidentify(text, spans, strategy="hash").text # 'Person_539681, Age_6c8349 yrs, DOB Date_7f19c4, City_d12704, City_60c7d5. Contact: Phone_d57003.' ``` Good to know: - `categories=[...]` on `detect()` limits which of the 53 PII categories are found (default: all); `detect_visual=False` on `ImagePIIRedactor` skips the visual-entity detector entirely. - Sequential pseudonyms are scoped to the returned `mapping` — pass `mapping=result.mapping` on the next page of the same record to keep numbering consistent. Hash tokens need no threading. - Anonymization is best-effort removal/generalization of detected identifiers — not a k-anonymity guarantee or a compliance determination. See the [document-pii-redactor GitHub repo](https://github.com/eka-care/document-pii-redactor) for runnable notebook walkthroughs — [`quickstart.ipynb`](https://github.com/eka-care/document-pii-redactor/blob/main/examples/quickstart.ipynb) and [`byo_ocr_nemotron.ipynb`](https://github.com/eka-care/document-pii-redactor/blob/main/examples/byo_ocr_nemotron.ipynb) — the full API reference, the category taxonomy, and the Docker/FastAPI deployment setup (the same setup behind the demo Space above). ## License and attribution The weights are licensed **per model**, following each base model's license (a fine-tune is a derivative of its base — the base license flows through): | weights | fine-tuned from | license | |---|---|---| | `text/minilm/` | Multilingual MiniLM (MIT) | **CC-BY-4.0** — free use incl. commercial; credit Eka Care with a link back | | `image/layoutlmv3/` | [microsoft/layoutlmv3-base](https://huggingface.co/microsoft/layoutlmv3-base) (CC-BY-NC-SA-4.0) | **CC-BY-NC-SA-4.0** — **non-commercial use only**, ShareAlike | | `image/yolo/best.pt` | YOLO11m ([Ultralytics](https://github.com/ultralytics/ultralytics), AGPL-3.0) | **AGPL-3.0** | Practical summary: the **plain-text pipeline (`TextPIIRedactor`) has a fully permissive lineage** and may be used commercially with attribution. The image pipeline currently inherits its bases' restrictions — no commercial use of the LayoutLMv3 fine-tune, and AGPL obligations for the visual detector (the `ultralytics` runtime it needs is also AGPL-3.0 and is an optional `[visual]` extra of the pip package). The library code is Apache-2.0 at https://github.com/eka-care/document-pii-redactor. If you use the models or the library, please cite: ```bibtex @software{document_pii_redactor, author = {{Eka Care}}, title = {document-pii-redactor: detect, redact, de-identify, or anonymize PII in document images and plain text}, year = {2026}, url = {https://github.com/eka-care/document-pii-redactor}, note = {Model weights: https://huggingface.co/ekacare/document-pii-redactor} } ```