OpenAI dropped a new model on the Hub this week: Privacy Filter, an open-source PII detector that labels text across eight categories in a single forward pass over a 128k context. That’s a big deal because most PII tools either chunk your text (and lose context) or only handle a few categories. This one does it all at once, and it’s Apache 2.0 licensed.
I spent a few hours building with it, and I came away impressed—but not for the reasons you’d expect. The model itself is solid, but the real star here is how easy it is to wire up real apps around it. I landed on three prototypes, and each one shows a different slice of what this stack can do.
The Model at a Glance
Privacy Filter is a 1.5B-parameter model with only 50M active parameters (mixture-of-experts architecture). It covers: private_person, private_address, private_email, private_phone, private_url, private_date, account_number, and secret. Full benchmark numbers are in the official release blog, but the headline is state-of-the-art on PII-Masking-300k.
The 128k context window is the killer feature here. No chunking, no stitching, no weird offset bugs. You dump a whole document in, you get clean spans out.
App 1: Document Privacy Explorer
Try it at ysharma/OPF-Document-PII-Explorer.
The idea is simple: drop in a PDF or DOCX, get the full document back with every PII span highlighted in place, color-coded by category. Sidebar filters let you toggle categories on and off without re-running the model. A summary dashboard shows counts per category up top.
What makes this work is that the whole file goes through in one pass. No chunking means the span offsets line up directly with the rendered text. BIOES decoding keeps boundaries clean even through long ambiguous runs.
I built the frontend as a single HTML file with Gradio’s Server (gr.Server). The backend is just one endpoint:
@server.api(name="analyze_document")
def analyze_document(file: FileData) -> dict:
text = extract_text(file["path"])
source_text, spans = run_privacy_filter(text)
return {
"text": source_text,
"spans": spans,
"stats": compute_stats(source_text, spans),
}
The @server.api decorator is the magic. It plugs the handler into Gradio’s queue, so concurrent uploads are serialized, ZeroGPU composes correctly, and the same endpoint works from both the browser and gradio_client. No duplicated code.
App 2: Image Anonymizer
Try it at ysharma/OPF-Image-Anonymizer.
This one is more ambitious. Upload a screenshot—a Slack thread, a receipt, a Stripe dashboard—and get it back with black bars over names, emails, and account numbers. You can toggle bars on and off, drag them to reposition, or draw your own for anything the model missed. Then export the result.
The pipeline: Tesseract runs OCR and returns per-word bounding boxes. The backend reconstructs the full text with a char-offset-to-box map, runs Privacy Filter once over the whole text, then looks up detected spans against the word map and joins them into pixel rectangles per line.
I could have used gr.ImageEditor, but the workflow I wanted—per-bar category metadata, toggle all bars in a category at once, client-side PNG export at natural resolution—was cleaner on a custom frontend. gr.Server hands back pixel rectangles from one queued endpoint and lets the canvas own everything else.
@server.api(name="anonymize_screenshot")
def anonymize_screenshot(image: FileData) -> dict:
img = Image.open(image["path"]).convert("RGB")
full_text, char_to_box = ocr_image(img)
spans = run_privacy_filter(full_text)
boxes = spans_to_pixel_boxes(spans, char_to_box)
return {
"image_data_url": pil_to_base64(img),
"width": img.width,
"height": img.height,
"boxes": boxes,
}
The frontend calls it with client.predict(“/anonymize_screenshot”, { image: handle_file(file) })—same pattern as the document explorer. Toggles, drags, new-bar drawing, and PNG export all happen client-side. No server round-trips after the initial inference.
App 3: SmartRedact Paste
This one is the most interesting to me because it solves a real problem I’ve had: you need to share sensitive text with someone, but you don’t want them to see the PII. Paste the text, get a public URL that serves the redacted version, and keep a private reveal link for yourself.
The backend stores the original text and the PII spans. The public endpoint renders the redacted version. The private endpoint renders the full text. No authentication, no database—just two URLs and a model call.
The architecture is the same as the other two apps: one queued endpoint for analysis, one for rendering. The frontend is a single HTML file with a paste area and two copyable links.
What I Actually Learned
The model is good. Not perfect—it misses some edge cases and occasionally flags a common word as a person name—but for a first release, it’s impressive. The 128k context window is the real differentiator.
But the bigger takeaway for me is how gr.Server changes the game for building these kinds of apps. You get:
- Custom HTML/JS frontends without fighting Gradio’s component system
- One consistent backend pattern across wildly different UIs
- Free queueing, ZeroGPU allocation, and gradio_client compatibility
- No duplicated code between browser and programmatic access
I’ve built PII tools before, and they always ended up as janky prototypes that fell apart under real use. These three apps are genuinely usable. I’m already thinking about what else I can build with this stack.
Try them yourself. The model is on the Hub, the code is open source, and the whole thing takes about an hour to understand. That’s rare in this space.
Comments (0)
Login Log in to comment.
Be the first to comment!