{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-04-27-how-to-build-scalable-web-apps-with-openai-s-privacy-filter/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "OpenAI released Privacy Filter on the Hub this week: an open-source personally-identifiable information (PII) detector that labels text across eight categories in a single forward pass over a 128k context. [Model card](https://huggingface.co/openai/privacy-filter). We spent a few hours building with it and landed on three apps that each reveals a different slice of what it can do.\n\n- [**Document Privacy Explorer**](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer): drop in a PDF or DOCX, read the document back with every PII span highlighted in place.\n- [**Image Anonymizer**](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer): upload an image, get it back with redacted black bars over names, emails, and account numbers. The image is also editable on a canvas so you can make your own annotations before downloading.\n- [**SmartRedact Paste**](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste): paste sensitive text, share a public URL that serves the redacted version, keep a private reveal link for yourself.\n\nAll three are built on [gradio.Server](https://huggingface.co/blog/introducing-gradio-server), which lets you pair custom HTML/JS frontends with Gradio's queueing, ZeroGPU allocation, and `gradio_client` SDK. In all these apps, **`gradio.Server`** plays the same backend role, and that consistency is exactly what makes it really powerful.\n\n## The model\n\nPrivacy Filter is a 1.5B-parameter model with 50M active parameters, permissively licensed under Apache 2.0. PII categories are `private_person`, `private_address`, `private_email`, `private_phone`, `private_url`, `private_date`, `account_number`, `secret`. Context is 128,000 tokens. Achieves state-of-the-art performance on the [PII-Masking-300k benchmark](https://huggingface.co/datasets/ai4privacy/pii-masking-300k). Full numbers and methodology are in the [official release blog](https://openai.com/index/introducing-openai-privacy-filter/).\n\n## 1. Document Privacy Explorer\n\nTry it at [ysharma/OPF-Document-PII-Explorer](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer).\n\n**User problem.** You want to read a PII-heavy document (a contract, a resume, an exported chat log) with every detected span highlighted by category, a filter in the sidebar, and a summary dashboard up top. The reading experience should feel like a normal document, not a form.\n\n**What Privacy Filter does here.** The whole file goes through in a single 128k-context forward pass, so there's no chunking, no stitching, and span offsets line up directly with the rendered text. BIOES decoding keeps span boundaries clean through long ambiguous runs.\n\n**What `gr.Server` does here.** You could wire this up in Blocks with `gr.HighlightedText` and a sidebar, and it would work. The reading experience we wanted (serif body, category filters that toggle CSS classes client-side instead of re-running the model, a summary dashboard that doesn't force a page re-render) was easier to hand-author than to compose. `gr.Server` lets us serve the reader view as a single HTML file and expose the model behind one queued endpoint:\n\n```python\nimport gradio as gr\nfrom fastapi.responses import HTMLResponse\nfrom gradio.data_classes import FileData\n\nserver = gr.Server()\n\n@server.get(\"/\", response_class=HTMLResponse)\nasync def homepage():\n    return FRONTEND_HTML                           # reader view; see app.py\n\n@server.api(name=\"analyze_document\")\ndef analyze_document(file: FileData) -> dict:\n    text = extract_text(file[\"path\"])              # PyMuPDF / python-docx\n    source_text, spans = run_privacy_filter(text)  # single 128k pass\n    return {\n        \"text\":  source_text,\n        \"spans\": spans,                            # [{start, end, label}, ...]\n        \"stats\": compute_stats(source_text, spans),\n    }\n```\n\nNote the decorator: `@server.api(name=\"analyze_document\")`, not a plain `@server.post`. That's the piece that plugs the handler into Gradio's queue, so concurrent uploads are serialized, `@spaces.GPU` composes correctly on ZeroGPU, and the same endpoint is reachable from both the browser and `gradio_client` with no duplicated code. The browser calls it with the Gradio JS client:\n\n```html\n<script type=\"module\">\nimport { Client, handle_file } from \"https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js\";\nconst client = await Client.connect(window.location.origin);\n\nasync function uploadFile(file) {\n  const result = await client.predict(\"/analyze_document\", { file: handle_file(file) });\n  renderResults(result.data[0]);                   // { text, spans, stats }\n}\n</script>\n```\n\n## 2. Image Anonymizer\n\nTry it at [ysharma/OPF-Image-Anonymizer](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer).\n\n**User problem.** You want to share an image or any screenshot (a Slack thread, a receipt, a Stripe dashboard) with black bars over the PII. You want to toggle bars on and off, drag them to reposition, or draw one by hand for anything the model missed, then export the result.\n\n**What Privacy Filter does here.** Tesseract runs OCR and returns per-word bounding boxes. The backend reconstructs the full text with a char-offset to box map, then runs Privacy Filter once over the whole text. Detected character spans are looked up against the word map and joined into pixel rectangles per line.\n\n**What `gr.Server` does here.** `gr.ImageEditor` supports layered annotation and is a reasonable starting point for image redaction. The workflow we wanted (per-bar category metadata, toggle all bars in a category at once, client-side PNG export at natural resolution with no server round-trip) was cleaner to build on a custom `<canvas>` frontend. `gr.Server` hands back pixel rectangles from one queued endpoint and lets the canvas own everything else:\n\n```python\n@server.api(name=\"anonymize_screenshot\")\ndef anonymize_screenshot(image: FileData) -> dict:\n    img = Image.open(image[\"path\"]).convert(\"RGB\")\n    full_text, char_to_box = ocr_image(img)        # per-word boxes + char map\n    spans = run_privacy_filter(full_text)\n    boxes = spans_to_pixel_boxes(spans, char_to_box)\n    return {\n        \"image_data_url\": pil_to_base64(img),\n        \"width\":  img.width,\n        \"height\": img.height,\n        \"boxes\":  boxes,                           # [{x, y, w, h, label, text}, ...]\n    }\n```\n\nThe frontend invokes it with `client.predict(\"/anonymize_screenshot\", { image: handle_file(file) })`, the same pattern as above. Toggles, drags, new-bar drawing, and PNG export all happen in the browser; edits never round-trip to the server.\n\n## 3. SmartRedact Paste\n\nTry it at [ysharma/OPF-SmartRedact-Paste](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste).\n\n**User problem.** You want a pastebin that redacts before sharing. You paste a log line, an email, a support ticket. You get two URLs back. The public one serves the redacted version with `<PRIVATE_PERSON>`, `<PRIVATE_EMAIL>`, `<ACCOUNT_NUMBER>` placeholders, following the redaction convention from the [official blog examples](https://openai.com/index/introducing-openai-privacy-filter/#:~:text=coherent%20masking%20boundaries.-,Example%20input%20text,-Subject%3A%20Q2%20Planning). The private one is gated by a token you keep and shows the original with spans highlighted.\n\n**What Privacy Filter does here.** Swap each detected span with a `<CATEGORY>` placeholder on the stored paste. That's the entire redaction step. Multilingual text (Spanish, French, Chinese, Hindi, and others in the model-card examples) routes through the same call with no change.\n\n**What `gr.Server` does here.** This app needs two distinct GET routes for the same paste ID, one public and one token-gated, and the URL shape matters because the reveal URL is the thing you keep. `gr.Server` works here because it's a FastAPI app underneath — which is also why `@server.api` and plain `@server.get` can sit side by side in the same process. Note: this can also be built with `gr.Blocks()` by [mounting custom routes with FastAPI](https://www.gradio.app/docs/gradio/mount_gradio_app) :\n\n```python\n# Model call → queued endpoint. Hit from the browser via\n# client.predict(\"/create_paste\", { text, ttl }).\n@server.api(name=\"create_paste\")\ndef create_paste(text: str, ttl: str = \"never\") -> dict:\n    source_text, spans = run_privacy_filter(text)\n    redacted = redact(source_text, spans)          # <CATEGORY> placeholders\n    pid, reveal_token = secrets.token_urlsafe(6), secrets.token_urlsafe(22)\n    PASTES[pid] = Paste(pid, reveal_token, source_text, redacted, spans,\n                        expires_at=_ttl(ttl))      # see app.py\n    return {\n        \"view_path\":   f\"/view/{pid}\",\n        \"reveal_path\": f\"/view/{pid}?token={reveal_token}\",\n    }\n\n# View page → plain FastAPI GET. No model, no queue needed, and we\n# actually want the bespoke URL shape `/view/{pid}?token=...` that a\n# queued endpoint couldn't give us.\n@server.get(\"/view/{pid}\", response_class=HTMLResponse)\nasync def view_paste(pid: str, token: str | None = None):\n    p = _store_get(pid)                            # see app.py for store\n    if p is None:\n        return HTMLResponse(_not_found(), status_code=404)\n    revealed = bool(token) and secrets.compare_digest(token, p.reveal_token)\n    return HTMLResponse(_render_view(p, revealed))\n```\n\nA daemon thread evicts expired pastes every 30 seconds. The whole service, including storage, is about 200 lines of application code because everything lives in one process.\n\n## What `gradio.Server` provides\n\nThe split across all three apps is the same — anything that touches the model goes through `@server.api`, everything else stays on plain FastAPI routes:\n\n| App                       | Queued compute (`@server.api`)                            | Plain FastAPI routes                                                                                             |\n| ------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |\n| Document Privacy Explorer | `analyze_document` — extract, detect, stats               | `GET /` serves the custom reader view                                                                            |\n| Image Anonymizer          | `anonymize_screenshot` — OCR, detect, spans → pixel boxes | `GET /` + `GET /examples/*` serve the canvas UI and preloaded examples                                           |\n| SmartRedact Paste         | `create_paste` — detect, redact, mint IDs                 | `GET /` compose page, `GET /view/{pid}?token=...` public + token-gated views, `GET /api/paste/{pid}` JSON lookup |\n\n`@server.api` gives you Gradio's queue (serialized requests, correct `@spaces.GPU` composition on ZeroGPU, progress events) and it's what the browser hits through [`@gradio/client`](https://www.gradio.app/guides/getting-started-with-the-js-client). The same endpoint is also what `gradio_client` users hit from Python — one function, two SDKs, no duplicated code. Plain `@server.get`/`@server.post` are reserved for the static surfaces: HTML pages, file lookups, cheap dict reads. That's the rule of thumb from the [gradio.Server intro post](https://huggingface.co/blog/introducing-gradio-server), and it's what makes these three apps feel consistent even though their UIs are very different.\n\n## Try them\n\n- [Document Privacy Explorer](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer)\n- [Image Anonymizer](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer)\n- [SmartRedact Paste](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste)\n\nDrop in a resume, a screenshot of a Slack thread, a log line with a token in it. The fun part is seeing what Privacy Filter catches (and occasionally misses) on text you actually care about.\n\n## Recommended reading\n\n- OpenAI's release post: [Introducing OpenAI Privacy Filter](https://openai.com/index/introducing-openai-privacy-filter/)\n- Model card: [openai/privacy-filter on Hugging Face](https://huggingface.co/openai/privacy-filter)\n- [Redaction examples and taxonomy on Model card](https://cdn.openai.com/pdf/c66281ed-b638-456a-8ce1-97e9f5264a90/OpenAI-Privacy-Filter-Model-Card.pdf)\n",
  "authors": [],
  "captured_at": "2026-10-19T01:26:53.998049939+00:00",
  "category": "ai",
  "content_html": "<p>OpenAI released Privacy Filter on the Hub this week: an open-source personally-identifiable information (PII) detector that labels text across eight categories in a single forward pass over a 128k context. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/openai/privacy-filter\">Model card</a>. We spent a few hours building with it and landed on three apps that each reveals a different slice of what it can do.</p>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer\"><strong>Document Privacy Explorer</strong></a>: drop in a PDF or DOCX, read the document back with every PII span highlighted in place.</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer\"><strong>Image Anonymizer</strong></a>: upload an image, get it back with redacted black bars over names, emails, and account numbers. The image is also editable on a canvas so you can make your own annotations before downloading.</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste\"><strong>SmartRedact Paste</strong></a>: paste sensitive text, share a public URL that serves the redacted version, keep a private reveal link for yourself.</li>\n</ul>\n<p>All three are built on <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/introducing-gradio-server\">gradio.Server</a>, which lets you pair custom HTML/JS frontends with Gradio's queueing, ZeroGPU allocation, and <code>gradio_client</code> SDK. In all these apps, <strong><code>gradio.Server</code></strong> plays the same backend role, and that consistency is exactly what makes it really powerful.</p>\n<h2>The model</h2>\n<p>Privacy Filter is a 1.5B-parameter model with 50M active parameters, permissively licensed under Apache 2.0. PII categories are <code>private_person</code>, <code>private_address</code>, <code>private_email</code>, <code>private_phone</code>, <code>private_url</code>, <code>private_date</code>, <code>account_number</code>, <code>secret</code>. Context is 128,000 tokens. Achieves state-of-the-art performance on the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/datasets/ai4privacy/pii-masking-300k\">PII-Masking-300k benchmark</a>. Full numbers and methodology are in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://openai.com/index/introducing-openai-privacy-filter/\">official release blog</a>.</p>\n<h2>1. Document Privacy Explorer</h2>\n<p>Try it at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer\">ysharma/OPF-Document-PII-Explorer</a>.</p>\n<p><strong>User problem.</strong> You want to read a PII-heavy document (a contract, a resume, an exported chat log) with every detected span highlighted by category, a filter in the sidebar, and a summary dashboard up top. The reading experience should feel like a normal document, not a form.</p>\n<p><strong>What Privacy Filter does here.</strong> The whole file goes through in a single 128k-context forward pass, so there's no chunking, no stitching, and span offsets line up directly with the rendered text. BIOES decoding keeps span boundaries clean through long ambiguous runs.</p>\n<p><strong>What <code>gr.Server</code> does here.</strong> You could wire this up in Blocks with <code>gr.HighlightedText</code> and a sidebar, and it would work. The reading experience we wanted (serif body, category filters that toggle CSS classes client-side instead of re-running the model, a summary dashboard that doesn't force a page re-render) was easier to hand-author than to compose. <code>gr.Server</code> lets us serve the reader view as a single HTML file and expose the model behind one queued endpoint:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gradio</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">fastapi</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">responses</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">HTMLResponse</span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">gradio</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">data_classes</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">FileData</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">gr</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Server</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"></span></span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-function syntax-python\">get</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-annotation syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">response_class</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">HTMLResponse</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-modifier syntax-async syntax-python\">async</span> <span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">homepage</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-other syntax-constant syntax-python\">FRONTEND_HTML</span></span>                           <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> reader view; see app.py\n</span>\n<span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"></span></span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-function syntax-python\">api</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-annotation syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">name</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">analyze_document<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">analyze_document</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">file</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">FileData</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"> </span><span class=\"syntax-meta syntax-function syntax-annotation syntax-return syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-return syntax-python\">-&gt;</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">dict</span></span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">text</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">extract_text</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">path<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>              <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> PyMuPDF / python-docx\n</span>    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">run_privacy_filter</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">text</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> single 128k pass\n</span>    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">text<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span>  <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">spans<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [{start, end, label}, ...]\n</span>        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">stats<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">compute_stats</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n    <span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span>\n</span></span></code></pre>\n<p>Note the decorator: <code>@server.api(name=&quot;analyze_document&quot;)</code>, not a plain <code>@server.post</code>. That's the piece that plugs the handler into Gradio's queue, so concurrent uploads are serialized, <code>@spaces.GPU</code> composes correctly on ZeroGPU, and the same endpoint is reachable from both the browser and <code>gradio_client</code> with no duplicated code. The browser calls it with the Gradio JS client:</p>\n<pre><code class=\"language-html\"><span class=\"code-snippet\" data-language=\"HTML\"><span class=\"syntax-text syntax-html syntax-basic\"><span class=\"syntax-meta syntax-tag syntax-script syntax-begin syntax-html\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-html\">&lt;</span><span class=\"syntax-entity syntax-name syntax-tag syntax-script syntax-html\">script</span></span><span class=\"syntax-meta syntax-tag syntax-script syntax-begin syntax-html\"> <span class=\"syntax-meta syntax-attribute-with-value syntax-html\"><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-html\">type</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-html\">=</span></span><span class=\"syntax-meta syntax-attribute-with-value syntax-html\"><span class=\"syntax-string syntax-quoted syntax-double syntax-html\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-html\">&quot;</span>module<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-html\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-tag syntax-script syntax-begin syntax-html\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-html\">&gt;</span></span>\n<span class=\"syntax-source syntax-js syntax-embedded syntax-html\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">Client</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">handle_file</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">client</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">Client</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">connect</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">window</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">location</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">origin</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">async</span> <span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span> <span class=\"syntax-entity syntax-name syntax-function syntax-js\">uploadFile</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">file</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">result</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">client</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">predict</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>/analyze_document<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">file</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">handle_file</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">file</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n  <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">renderResults</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">result</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">data</span><span class=\"syntax-meta syntax-brackets syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-constant syntax-numeric syntax-js\">0</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>                   <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> { text, spans, stats }\n</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n</span></span><span class=\"syntax-meta syntax-tag syntax-script syntax-end syntax-html\"><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-begin syntax-html\">&lt;/</span><span class=\"syntax-entity syntax-name syntax-tag syntax-script syntax-html\">script</span><span class=\"syntax-punctuation syntax-definition syntax-tag syntax-end syntax-html\">&gt;</span></span>\n</span></span></code></pre>\n<h2>2. Image Anonymizer</h2>\n<p>Try it at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer\">ysharma/OPF-Image-Anonymizer</a>.</p>\n<p><strong>User problem.</strong> You want to share an image or any screenshot (a Slack thread, a receipt, a Stripe dashboard) with black bars over the PII. You want to toggle bars on and off, drag them to reposition, or draw one by hand for anything the model missed, then export the result.</p>\n<p><strong>What Privacy Filter does here.</strong> Tesseract runs OCR and returns per-word bounding boxes. The backend reconstructs the full text with a char-offset to box map, then runs Privacy Filter once over the whole text. Detected character spans are looked up against the word map and joined into pixel rectangles per line.</p>\n<p><strong>What <code>gr.Server</code> does here.</strong> <code>gr.ImageEditor</code> supports layered annotation and is a reasonable starting point for image redaction. The workflow we wanted (per-bar category metadata, toggle all bars in a category at once, client-side PNG export at natural resolution with no server round-trip) was cleaner to build on a custom <code>&lt;canvas&gt;</code> frontend. <code>gr.Server</code> hands back pixel rectangles from one queued endpoint and lets the canvas own everything else:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"></span></span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-function syntax-python\">api</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-annotation syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">name</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">anonymize_screenshot<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">anonymize_screenshot</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">image</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">FileData</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"> </span><span class=\"syntax-meta syntax-function syntax-annotation syntax-return syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-return syntax-python\">-&gt;</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">dict</span></span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">img</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">Image</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">open</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">image</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">path<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">convert</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">RGB<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">full_text</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">char_to_box</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">ocr_image</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">img</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>        <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> per-word boxes + char map\n</span>    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">run_privacy_filter</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">full_text</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">boxes</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">spans_to_pixel_boxes</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">char_to_box</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">image_data_url<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">pil_to_base64</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">img</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">width<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span>  <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">img</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">width</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">height<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">img</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">height</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">boxes<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span>  <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">boxes</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>                           <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [{x, y, w, h, label, text}, ...]\n</span>    <span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span>\n</span></span></code></pre>\n<p>The frontend invokes it with <code>client.predict(&quot;/anonymize_screenshot&quot;, { image: handle_file(file) })</code>, the same pattern as above. Toggles, drags, new-bar drawing, and PNG export all happen in the browser; edits never round-trip to the server.</p>\n<h2>3. SmartRedact Paste</h2>\n<p>Try it at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste\">ysharma/OPF-SmartRedact-Paste</a>.</p>\n<p><strong>User problem.</strong> You want a pastebin that redacts before sharing. You paste a log line, an email, a support ticket. You get two URLs back. The public one serves the redacted version with <code>&lt;PRIVATE_PERSON&gt;</code>, <code>&lt;PRIVATE_EMAIL&gt;</code>, <code>&lt;ACCOUNT_NUMBER&gt;</code> placeholders, following the redaction convention from the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://openai.com/index/introducing-openai-privacy-filter/#:~:text=coherent%20masking%20boundaries.-,Example%20input%20text,-Subject%3A%20Q2%20Planning\">official blog examples</a>. The private one is gated by a token you keep and shows the original with spans highlighted.</p>\n<p><strong>What Privacy Filter does here.</strong> Swap each detected span with a <code>&lt;CATEGORY&gt;</code> placeholder on the stored paste. That's the entire redaction step. Multilingual text (Spanish, French, Chinese, Hindi, and others in the model-card examples) routes through the same call with no change.</p>\n<p><strong>What <code>gr.Server</code> does here.</strong> This app needs two distinct GET routes for the same paste ID, one public and one token-gated, and the URL shape matters because the reveal URL is the thing you keep. <code>gr.Server</code> works here because it's a FastAPI app underneath — which is also why <code>@server.api</code> and plain <code>@server.get</code> can sit side by side in the same process. Note: this can also be built with <code>gr.Blocks()</code> by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.gradio.app/docs/gradio/mount_gradio_app\">mounting custom routes with FastAPI</a> :</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Model call → queued endpoint. Hit from the browser via\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> client.predict(&quot;/create_paste&quot;, { text, ttl }).\n</span><span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"></span></span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-function syntax-python\">api</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-annotation syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">name</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">create_paste<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">create_paste</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">text</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">str</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-parameters syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">ttl</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">str</span></span> </span><span class=\"syntax-meta syntax-function syntax-parameters syntax-default-value syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">never<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"> </span><span class=\"syntax-meta syntax-function syntax-annotation syntax-return syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-return syntax-python\">-&gt;</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">dict</span></span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">run_privacy_filter</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">text</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">redacted</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">redact</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>          <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> &lt;CATEGORY&gt; placeholders\n</span>    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reveal_token</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">secrets</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">token_urlsafe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">6</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>, <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">secrets</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">token_urlsafe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">22</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-other syntax-constant syntax-python\">PASTES</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Paste</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reveal_token</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">source_text</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">redacted</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">spans</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n                        <span class=\"syntax-variable syntax-parameter syntax-python\">expires_at</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">_ttl</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ttl</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>      <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> see app.py\n</span>    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">view_path<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span>   <span class=\"syntax-storage syntax-type syntax-string syntax-python\">f</span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/view/</span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">reveal_path<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-storage syntax-type syntax-string syntax-python\">f</span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/view/</span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">?token=</span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">reveal_token</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n    <span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> View page → plain FastAPI GET. No model, no queue needed, and we\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> actually want the bespoke URL shape `/view/{pid}?token=...` that a\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> queued endpoint couldn&#39;t give us.\n</span><span class=\"syntax-meta syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-annotation syntax-python\">@</span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"></span></span><span class=\"syntax-meta syntax-annotation syntax-function syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">server</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-annotation syntax-function syntax-python\">get</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-annotation syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/view/<span class=\"syntax-constant syntax-other syntax-placeholder syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-placeholder syntax-begin syntax-python\">{</span>pid<span class=\"syntax-punctuation syntax-definition syntax-placeholder syntax-end syntax-python\">}</span></span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">response_class</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">HTMLResponse</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-modifier syntax-async syntax-python\">async</span> <span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">view_paste</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">pid</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">str</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-parameters syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">token</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-annotation syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-annotation syntax-parameter syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">str</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">|</span> <span class=\"syntax-constant syntax-language syntax-python\">None</span> </span><span class=\"syntax-meta syntax-function syntax-parameters syntax-default-value syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-constant syntax-language syntax-python\">None</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">_store_get</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">pid</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> see app.py for store\n</span>    <span class=\"syntax-meta syntax-statement syntax-if syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-conditional syntax-python\">if</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-python\">is</span> <span class=\"syntax-constant syntax-language syntax-python\">None</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-conditional syntax-python\">:</span></span>\n        <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">HTMLResponse</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">_not_found</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">status_code</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">404</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">revealed</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">bool</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">token</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-python\">and</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">secrets</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">compare_digest</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">token</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">reveal_token</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">HTMLResponse</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">_render_view</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">p</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">revealed</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>A daemon thread evicts expired pastes every 30 seconds. The whole service, including storage, is about 200 lines of application code because everything lives in one process.</p>\n<h2>What <code>gradio.Server</code> provides</h2>\n<p>The split across all three apps is the same — anything that touches the model goes through <code>@server.api</code>, everything else stays on plain FastAPI routes:</p>\n<table>\n<thead>\n<tr>\n<th>App</th>\n<th>Queued compute (<code>@server.api</code>)</th>\n<th>Plain FastAPI routes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Document Privacy Explorer</td>\n<td><code>analyze_document</code> — extract, detect, stats</td>\n<td><code>GET /</code> serves the custom reader view</td>\n</tr>\n<tr>\n<td>Image Anonymizer</td>\n<td><code>anonymize_screenshot</code> — OCR, detect, spans → pixel boxes</td>\n<td><code>GET /</code> + <code>GET /examples/*</code> serve the canvas UI and preloaded examples</td>\n</tr>\n<tr>\n<td>SmartRedact Paste</td>\n<td><code>create_paste</code> — detect, redact, mint IDs</td>\n<td><code>GET /</code> compose page, <code>GET /view/{pid}?token=...</code> public + token-gated views, <code>GET /api/paste/{pid}</code> JSON lookup</td>\n</tr>\n</tbody>\n</table>\n<p><code>@server.api</code> gives you Gradio's queue (serialized requests, correct <code>@spaces.GPU</code> composition on ZeroGPU, progress events) and it's what the browser hits through <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.gradio.app/guides/getting-started-with-the-js-client\"><code>@gradio/client</code></a>. The same endpoint is also what <code>gradio_client</code> users hit from Python — one function, two SDKs, no duplicated code. Plain <code>@server.get</code>/<code>@server.post</code> are reserved for the static surfaces: HTML pages, file lookups, cheap dict reads. That's the rule of thumb from the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/introducing-gradio-server\">gradio.Server intro post</a>, and it's what makes these three apps feel consistent even though their UIs are very different.</p>\n<h2>Try them</h2>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer\">Document Privacy Explorer</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer\">Image Anonymizer</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste\">SmartRedact Paste</a></li>\n</ul>\n<p>Drop in a resume, a screenshot of a Slack thread, a log line with a token in it. The fun part is seeing what Privacy Filter catches (and occasionally misses) on text you actually care about.</p>\n<h2>Recommended reading</h2>\n<ul>\n<li>OpenAI's release post: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://openai.com/index/introducing-openai-privacy-filter/\">Introducing OpenAI Privacy Filter</a></li>\n<li>Model card: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/openai/privacy-filter\">openai/privacy-filter on Hugging Face</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cdn.openai.com/pdf/c66281ed-b638-456a-8ce1-97e9f5264a90/OpenAI-Privacy-Filter-Model-Card.pdf\">Redaction examples and taxonomy on Model card</a></li>\n</ul>\n",
  "content_markdown": "OpenAI released Privacy Filter on the Hub this week: an open-source personally-identifiable information (PII) detector that labels text across eight categories in a single forward pass over a 128k context. [Model card](https://huggingface.co/openai/privacy-filter). We spent a few hours building with it and landed on three apps that each reveals a different slice of what it can do.\n\n- [**Document Privacy Explorer**](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer): drop in a PDF or DOCX, read the document back with every PII span highlighted in place.\n- [**Image Anonymizer**](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer): upload an image, get it back with redacted black bars over names, emails, and account numbers. The image is also editable on a canvas so you can make your own annotations before downloading.\n- [**SmartRedact Paste**](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste): paste sensitive text, share a public URL that serves the redacted version, keep a private reveal link for yourself.\n\nAll three are built on [gradio.Server](https://huggingface.co/blog/introducing-gradio-server), which lets you pair custom HTML/JS frontends with Gradio's queueing, ZeroGPU allocation, and `gradio_client` SDK. In all these apps, **`gradio.Server`** plays the same backend role, and that consistency is exactly what makes it really powerful.\n\n## The model\n\nPrivacy Filter is a 1.5B-parameter model with 50M active parameters, permissively licensed under Apache 2.0. PII categories are `private_person`, `private_address`, `private_email`, `private_phone`, `private_url`, `private_date`, `account_number`, `secret`. Context is 128,000 tokens. Achieves state-of-the-art performance on the [PII-Masking-300k benchmark](https://huggingface.co/datasets/ai4privacy/pii-masking-300k). Full numbers and methodology are in the [official release blog](https://openai.com/index/introducing-openai-privacy-filter/).\n\n## 1. Document Privacy Explorer\n\nTry it at [ysharma/OPF-Document-PII-Explorer](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer).\n\n**User problem.** You want to read a PII-heavy document (a contract, a resume, an exported chat log) with every detected span highlighted by category, a filter in the sidebar, and a summary dashboard up top. The reading experience should feel like a normal document, not a form.\n\n**What Privacy Filter does here.** The whole file goes through in a single 128k-context forward pass, so there's no chunking, no stitching, and span offsets line up directly with the rendered text. BIOES decoding keeps span boundaries clean through long ambiguous runs.\n\n**What `gr.Server` does here.** You could wire this up in Blocks with `gr.HighlightedText` and a sidebar, and it would work. The reading experience we wanted (serif body, category filters that toggle CSS classes client-side instead of re-running the model, a summary dashboard that doesn't force a page re-render) was easier to hand-author than to compose. `gr.Server` lets us serve the reader view as a single HTML file and expose the model behind one queued endpoint:\n\n```python\nimport gradio as gr\nfrom fastapi.responses import HTMLResponse\nfrom gradio.data_classes import FileData\n\nserver = gr.Server()\n\n@server.get(\"/\", response_class=HTMLResponse)\nasync def homepage():\n    return FRONTEND_HTML                           # reader view; see app.py\n\n@server.api(name=\"analyze_document\")\ndef analyze_document(file: FileData) -> dict:\n    text = extract_text(file[\"path\"])              # PyMuPDF / python-docx\n    source_text, spans = run_privacy_filter(text)  # single 128k pass\n    return {\n        \"text\":  source_text,\n        \"spans\": spans,                            # [{start, end, label}, ...]\n        \"stats\": compute_stats(source_text, spans),\n    }\n```\n\nNote the decorator: `@server.api(name=\"analyze_document\")`, not a plain `@server.post`. That's the piece that plugs the handler into Gradio's queue, so concurrent uploads are serialized, `@spaces.GPU` composes correctly on ZeroGPU, and the same endpoint is reachable from both the browser and `gradio_client` with no duplicated code. The browser calls it with the Gradio JS client:\n\n```html\n<script type=\"module\">\nimport { Client, handle_file } from \"https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js\";\nconst client = await Client.connect(window.location.origin);\n\nasync function uploadFile(file) {\n  const result = await client.predict(\"/analyze_document\", { file: handle_file(file) });\n  renderResults(result.data[0]);                   // { text, spans, stats }\n}\n</script>\n```\n\n## 2. Image Anonymizer\n\nTry it at [ysharma/OPF-Image-Anonymizer](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer).\n\n**User problem.** You want to share an image or any screenshot (a Slack thread, a receipt, a Stripe dashboard) with black bars over the PII. You want to toggle bars on and off, drag them to reposition, or draw one by hand for anything the model missed, then export the result.\n\n**What Privacy Filter does here.** Tesseract runs OCR and returns per-word bounding boxes. The backend reconstructs the full text with a char-offset to box map, then runs Privacy Filter once over the whole text. Detected character spans are looked up against the word map and joined into pixel rectangles per line.\n\n**What `gr.Server` does here.** `gr.ImageEditor` supports layered annotation and is a reasonable starting point for image redaction. The workflow we wanted (per-bar category metadata, toggle all bars in a category at once, client-side PNG export at natural resolution with no server round-trip) was cleaner to build on a custom `<canvas>` frontend. `gr.Server` hands back pixel rectangles from one queued endpoint and lets the canvas own everything else:\n\n```python\n@server.api(name=\"anonymize_screenshot\")\ndef anonymize_screenshot(image: FileData) -> dict:\n    img = Image.open(image[\"path\"]).convert(\"RGB\")\n    full_text, char_to_box = ocr_image(img)        # per-word boxes + char map\n    spans = run_privacy_filter(full_text)\n    boxes = spans_to_pixel_boxes(spans, char_to_box)\n    return {\n        \"image_data_url\": pil_to_base64(img),\n        \"width\":  img.width,\n        \"height\": img.height,\n        \"boxes\":  boxes,                           # [{x, y, w, h, label, text}, ...]\n    }\n```\n\nThe frontend invokes it with `client.predict(\"/anonymize_screenshot\", { image: handle_file(file) })`, the same pattern as above. Toggles, drags, new-bar drawing, and PNG export all happen in the browser; edits never round-trip to the server.\n\n## 3. SmartRedact Paste\n\nTry it at [ysharma/OPF-SmartRedact-Paste](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste).\n\n**User problem.** You want a pastebin that redacts before sharing. You paste a log line, an email, a support ticket. You get two URLs back. The public one serves the redacted version with `<PRIVATE_PERSON>`, `<PRIVATE_EMAIL>`, `<ACCOUNT_NUMBER>` placeholders, following the redaction convention from the [official blog examples](https://openai.com/index/introducing-openai-privacy-filter/#:~:text=coherent%20masking%20boundaries.-,Example%20input%20text,-Subject%3A%20Q2%20Planning). The private one is gated by a token you keep and shows the original with spans highlighted.\n\n**What Privacy Filter does here.** Swap each detected span with a `<CATEGORY>` placeholder on the stored paste. That's the entire redaction step. Multilingual text (Spanish, French, Chinese, Hindi, and others in the model-card examples) routes through the same call with no change.\n\n**What `gr.Server` does here.** This app needs two distinct GET routes for the same paste ID, one public and one token-gated, and the URL shape matters because the reveal URL is the thing you keep. `gr.Server` works here because it's a FastAPI app underneath — which is also why `@server.api` and plain `@server.get` can sit side by side in the same process. Note: this can also be built with `gr.Blocks()` by [mounting custom routes with FastAPI](https://www.gradio.app/docs/gradio/mount_gradio_app) :\n\n```python\n# Model call → queued endpoint. Hit from the browser via\n# client.predict(\"/create_paste\", { text, ttl }).\n@server.api(name=\"create_paste\")\ndef create_paste(text: str, ttl: str = \"never\") -> dict:\n    source_text, spans = run_privacy_filter(text)\n    redacted = redact(source_text, spans)          # <CATEGORY> placeholders\n    pid, reveal_token = secrets.token_urlsafe(6), secrets.token_urlsafe(22)\n    PASTES[pid] = Paste(pid, reveal_token, source_text, redacted, spans,\n                        expires_at=_ttl(ttl))      # see app.py\n    return {\n        \"view_path\":   f\"/view/{pid}\",\n        \"reveal_path\": f\"/view/{pid}?token={reveal_token}\",\n    }\n\n# View page → plain FastAPI GET. No model, no queue needed, and we\n# actually want the bespoke URL shape `/view/{pid}?token=...` that a\n# queued endpoint couldn't give us.\n@server.get(\"/view/{pid}\", response_class=HTMLResponse)\nasync def view_paste(pid: str, token: str | None = None):\n    p = _store_get(pid)                            # see app.py for store\n    if p is None:\n        return HTMLResponse(_not_found(), status_code=404)\n    revealed = bool(token) and secrets.compare_digest(token, p.reveal_token)\n    return HTMLResponse(_render_view(p, revealed))\n```\n\nA daemon thread evicts expired pastes every 30 seconds. The whole service, including storage, is about 200 lines of application code because everything lives in one process.\n\n## What `gradio.Server` provides\n\nThe split across all three apps is the same — anything that touches the model goes through `@server.api`, everything else stays on plain FastAPI routes:\n\n| App                       | Queued compute (`@server.api`)                            | Plain FastAPI routes                                                                                             |\n| ------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |\n| Document Privacy Explorer | `analyze_document` — extract, detect, stats               | `GET /` serves the custom reader view                                                                            |\n| Image Anonymizer          | `anonymize_screenshot` — OCR, detect, spans → pixel boxes | `GET /` + `GET /examples/*` serve the canvas UI and preloaded examples                                           |\n| SmartRedact Paste         | `create_paste` — detect, redact, mint IDs                 | `GET /` compose page, `GET /view/{pid}?token=...` public + token-gated views, `GET /api/paste/{pid}` JSON lookup |\n\n`@server.api` gives you Gradio's queue (serialized requests, correct `@spaces.GPU` composition on ZeroGPU, progress events) and it's what the browser hits through [`@gradio/client`](https://www.gradio.app/guides/getting-started-with-the-js-client). The same endpoint is also what `gradio_client` users hit from Python — one function, two SDKs, no duplicated code. Plain `@server.get`/`@server.post` are reserved for the static surfaces: HTML pages, file lookups, cheap dict reads. That's the rule of thumb from the [gradio.Server intro post](https://huggingface.co/blog/introducing-gradio-server), and it's what makes these three apps feel consistent even though their UIs are very different.\n\n## Try them\n\n- [Document Privacy Explorer](https://huggingface.co/spaces/ysharma/OPF-Document-PII-Explorer)\n- [Image Anonymizer](https://huggingface.co/spaces/ysharma/OPF-Image-Anonymizer)\n- [SmartRedact Paste](https://huggingface.co/spaces/ysharma/OPF-SmartRedact-Paste)\n\nDrop in a resume, a screenshot of a Slack thread, a log line with a token in it. The fun part is seeing what Privacy Filter catches (and occasionally misses) on text you actually care about.\n\n## Recommended reading\n\n- OpenAI's release post: [Introducing OpenAI Privacy Filter](https://openai.com/index/introducing-openai-privacy-filter/)\n- Model card: [openai/privacy-filter on Hugging Face](https://huggingface.co/openai/privacy-filter)\n- [Redaction examples and taxonomy on Model card](https://cdn.openai.com/pdf/c66281ed-b638-456a-8ce1-97e9f5264a90/OpenAI-Privacy-Filter-Model-Card.pdf)\n",
  "dateCreated": "2026-10-19T01:26:53.998049939+00:00",
  "date_created": "2026-04-27T00:00:00+00:00",
  "date_modified": "2026-04-27T00:00:00+00:00",
  "date_published": "2026-04-27T00:00:00+00:00",
  "description": "OpenAI released Privacy Filter on the Hub this week: an open-source personally-identifiable information (PII) detector that labels text across eight categories in a single forward pass over a 128k context. Model card. We spent a few hours…",
  "external_url": "https://huggingface.co/blog/openai-privacy-filter-web-apps",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/huggingface-co/2026/04/2026-04-27-how-to-build-scalable-web-apps-with-openai-s-privacy-filter.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/huggingface-co/2026/04/2026-04-27-how-to-build-scalable-web-apps-with-openai-s-privacy-filter.md"
  },
  "id": "urn:aggr:item:c21e95a187f2e39bc516a976abbecc1947075ff9",
  "isBasedOn": {
    "@id": "https://huggingface.co/blog/openai-privacy-filter-web-apps"
  },
  "mainEntity": {
    "@id": "https://huggingface.co/blog/openai-privacy-filter-web-apps",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-04-27-how-to-build-scalable-web-apps-with-openai-s-privacy-filter/#webpage"
    },
    "dateModified": "2026-04-27T00:00:00+00:00",
    "datePublished": "2026-04-27T00:00:00+00:00",
    "headline": "How to build scalable web apps with OpenAI's Privacy Filter",
    "image": {
      "@type": "ImageObject",
      "caption": null,
      "height": 90,
      "url": "https://huggingface.co/blog/assets/openai-privacy-filter-web-apps/thumbnail.png",
      "width": 160
    },
    "timeRequired": "PT7M",
    "url": "https://huggingface.co/blog/openai-privacy-filter-web-apps",
    "wordCount": 1425
  },
  "name": "Archived snapshot: How to build scalable web apps with OpenAI's Privacy Filter",
  "preview": {
    "alt": null,
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://huggingface.co/blog/assets/openai-privacy-filter-web-apps/thumbnail.png",
    "width": 160
  },
  "reading_minutes": 7,
  "replicated_at": null,
  "source": "huggingface-co",
  "source_name": "Hugging Face - Blog",
  "summary": null,
  "tags": [],
  "temporalCoverage": "2026-10-19T01:26:53.998049939+00:00",
  "title": "How to build scalable web apps with OpenAI's Privacy Filter",
  "url": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-04-27-how-to-build-scalable-web-apps-with-openai-s-privacy-filter/",
  "word_count": 1425
}