best_engine_ai_helper.privacy module

privacy — local pseudonymization for cloud calls (Phase 6.4).

Replace personal data with realistic same-type surrogates before text leaves the machine for a cloud provider, and restore the originals on the way back. Marie -> Claudine, Lyon -> Paris: the prose stays natural (no PERSON_1 tokens), so the cloud model reasons over coherent text and quality is intact. The reverse map stays local.

Detection + surrogate proposal are done by a local LLM (via a resolved engine — Ollama/vLLM), asked for schema-constrained JSON. Being local, it never ships the raw text anywhere, and being an LLM it is context-aware: it catches quasi-identifiers (role + city + employer) and special-category facts (health, beliefs, …) that a pure PII regex misses. An optional deterministic layer (Microsoft Presidio + Faker + spaCy, the privacy extra) can augment it; see augment_with_presidio().

Honesty (GDPR Recital 26): pseudonymized data is still personal data. This is risk-reduction, not anonymization, and does not take cloud processing out of GDPR scope. Label outputs “pseudonymized”, never “anonymous”.

Author

Warith Harchaoui <warith.harchaoui@deraison.ai>

best_engine_ai_helper.privacy.augment_with_presidio(text, entities)[source]

Deterministic backstop (optional cloud extra): add Presidio+Faker hits.

Presidio (PII detection) + Faker (same-type surrogates) catch structured identifiers (emails, phones, card/IBAN, IPs) the LLM may miss, and add them to the entity list. Requires presidio-analyzer, presidio-anonymizer and Faker (the cloud extra) plus spaCy models; a no-op with a warning when they are absent. Full wiring lands in a later 6.4 step.

Parameters:
Return type:

list[dict[str, Any]]

best_engine_ai_helper.privacy.pseudonymize(text, engine, *, locale=None, min_len=2)[source]

Replace personal data in text with same-type surrogates using a local LLM.

Parameters:
  • text (str) – The text to scrub before it leaves the machine.

  • engine (dict | str) – A resolved engine descriptor (or path). Use a LOCAL engine — for a cloud brief pass engine["fallback"] so scrubbing never touches the cloud.

  • locale (str or None) – Optional locale hint (e.g. "fr_FR") so surrogates match the language.

  • min_len (int) – Ignore detected spans shorter than this (avoids mangling stray letters).

Returns:

mapping is {surrogate: original} — keep it LOCAL and feed it to restore() on the response.

Return type:

(scrubbed_text, mapping)

best_engine_ai_helper.privacy.restore(text, mapping)[source]

Swap surrogates back to their originals (inverse of pseudonymize()).

Longest surrogate first so a multi-word surrogate is restored before any of its parts.

Parameters:
Return type:

str