English | Deutsch
Small FastAPI sidecar around openai/privacy-filter that exposes two endpoints for use from n8n (or any other HTTP client):
POST /redact— detect PII in text, return redacted text + a placeholder→original mappingPOST /rehydrate— replace placeholders in a text with their original values, using a provided mappingGET /healthz— readiness probe (returns{"ok": true}once the model is loaded)
The model auto-downloads (~1.5B params) on first start to a Docker volume, so subsequent restarts are fast. Runs CPU-only — no GPU required.
{ "text": "Hans Müller schreibt an hans@firma.de und Anna an anna@firma.de" }Response — placeholders are indexed and de-duplicated so the same original value always maps to the same placeholder, and rehydration is unambiguous:
{
"redacted": "<PRIVATE_PERSON_1> schreibt an <PRIVATE_EMAIL_1> und <PRIVATE_PERSON_2> an <PRIVATE_EMAIL_2>",
"mapping": {
"<PRIVATE_PERSON_1>": "Hans Müller",
"<PRIVATE_EMAIL_1>": "hans@firma.de",
"<PRIVATE_PERSON_2>": "Anna",
"<PRIVATE_EMAIL_2>": "anna@firma.de"
},
"spans": [ ... ]
}{
"text": "Hallo <PRIVATE_PERSON_1>, ich antworte an <PRIVATE_EMAIL_1>.",
"mapping": {
"<PRIVATE_PERSON_1>": "Hans Müller",
"<PRIVATE_EMAIL_1>": "hans@firma.de"
}
}Response:
{ "text": "Hallo Hans Müller, ich antworte an hans@firma.de." }-
Find the n8n Docker network name:
docker inspect <n8n-container-name> \ --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
Typical names:
n8n_default,proxy,traefik, ... -
In Portainer → Stacks → Add stack:
- Build method: Repository
- Repository URL:
https://github.com/LOGIN-TB/privacy-filter-api - Compose path:
docker-compose.yml - Environment variables: set
N8N_NETWORKto the network name from step 1.
-
Deploy. First start takes 1-2 min (model download). The healthcheck has a 180 s grace period.
-
From n8n (same Docker network), reach the service at:
http://privacy-filter:9090/redact http://privacy-filter:9090/rehydrate http://privacy-filter:9090/healthzNo port is published to the host — the service is only reachable inside the Docker network.
If your stack lives in Coolify instead of Portainer, see COOLIFY.md — covers Application-from-Git, Service-with-pasted-Compose, network linkage to a sibling n8n, and optional public HTTPS via Coolify's Traefik.
For a step-by-step guide with node-level configuration, ASCII schematics of the typical patterns, and common pitfalls, see INTEGRATION.md.
The short version — three nodes wrap the LLM:
Trigger ─► [Redact PII (HTTP)] ─► [Apply Redaction (Set)] ─► LLM ─► [Rehydrate (HTTP)] ─► Respond
The LLM only ever sees redacted text. Add a system-prompt instruction telling the model to preserve placeholders verbatim (do not paraphrase <PRIVATE_PERSON_1> to "the person mentioned").
docker compose up --build
curl -s -X POST http://localhost:9090/redact \
-H 'content-type: application/json' \
-d '{"text":"Alice was born on 1990-01-02."}'To expose the port for local testing, add to docker-compose.yml:
ports:
- "9090:9090"opf recognises 8 PII span types — placeholders follow <LABEL_N>:
private_person— namesprivate_emailprivate_phoneprivate_addressprivate_urlprivate_dateaccount_numbersecret— credentials, tokens
Project glue: see LICENSE. The underlying opf library is governed by its own license (see openai/privacy-filter).