Aller au contenu

Référence de configuration

Module : piighost.config

Un fichier de configuration décrit un pipeline entier de façon déclarative. piighost le lit en TOML ou en JSON, choisi par le suffixe du fichier, le valide avec Pydantic, et construit le pipeline que le fichier décrit. Cette page documente chaque section et chaque type de composant.

from piighost.config import load_config, load_pipeline, load_thread_pipeline

L'extra config est requis (pip install piighost[config]), qui tire pydantic-settings. Les clés inconnues sont rejetées, donc une faute de frappe échoue à la validation au lieu d'être ignorée. Un type de composant peut demander son propre extra, nommé dans la colonne Extra du tableau qui le documente.


Points d'entrée

Fonction Renvoie Construit Mémoire
load_config(path) PipelineConfig rien, valide seulement quelconque
load_pipeline(path) AnonymizationPipeline un pipeline sans état rejette une section [memory]
load_thread_pipeline(path) ThreadAnonymizationPipeline un pipeline de thread requiert une section [memory]

load_config analyse et valide un fichier en PipelineConfig sans construire de composant, donc aucun modèle ne charge. load_pipeline construit un AnonymizationPipeline sans état et lève ConfigError si le fichier déclare une section [memory], car une mémoire décrit un pipeline de thread. load_thread_pipeline construit un ThreadAnonymizationPipeline et lève ConfigError si le fichier ne déclare aucune section [memory].

from piighost.config import load_pipeline, load_thread_pipeline

stateless = load_pipeline("pipeline.toml")       # no [memory]
thread = load_thread_pipeline("thread.toml")     # has [memory]

Format de fichier

Le suffixe choisit le parseur. Un suffixe .json est lu en JSON, la comparaison ignorant la casse, et tout le reste en TOML. Les deux formats portent le même schéma. Une section est une table TOML ou un objet JSON.

[detector]
type = "regex"
patterns = { EMAIL = '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' }

[linker]
type = "exact"

[anonymizer.placeholder]
type = "redact"
{
  "detector": { "type": "regex", "patterns": { "EMAIL": "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}" } },
  "linker": { "type": "exact" },
  "anonymizer": { "placeholder": { "type": "redact" } }
}

Surcharges par l'environnement

Chaque clé de premier niveau accepte une surcharge par une variable d'environnement préfixée PIIGHOST_, qu'elle porte un scalaire ou une section entière. PIIGHOST_NAME surcharge le scalaire name, et PIIGHOST_DETECTOR surcharge la section [detector] avec un objet JSON, rejeté comme erreur de validation quand ce n'est pas du JSON valide. Les surcharges se superposent au fichier clé par clé, donc une valeur d'environnement l'emporte sur celle du fichier et les clés qu'elle omet gardent la leur.

export PIIGHOST_NAME="local-en"
export PIIGHOST_DETECTOR='{"type": "exact", "values": {"Patrick": "PERSON"}}'

Aucun délimiteur d'imbrication n'est configuré, donc une variable comme PIIGHOST_DETECTOR__TYPE ne nomme aucun champ, et elle est ignorée sans erreur au lieu d'atteindre la clé type. Une section se surcharge uniquement par son objet JSON.

Les secrets ne sont jamais lus depuis le fichier. Chacun est lu depuis sa propre variable d'environnement à la construction, et une variable manquante lève ConfigError depuis build().

Secret Variable Format Utilisé par
Poivre de hachage PIIGHOST_HASH_PEPPER toute chaîne non vide [memory.hasher]
Clé de chiffrement PIIGHOST_CIPHER_KEY base64 de 16, 24 ou 32 octets [memory.cipher]
Clé de modération MISTRAL_API_KEY clé d'API Mistral [guard] type moderation
URL de base de données la valeur de url_env, PIIGHOST_DATABASE_URL par défaut une URL SQLAlchemy async [memory] type sqlalchemy

Sections

Les clés de premier niveau d'un PipelineConfig.

Section Requise Signification
name non Un nom de pipeline optionnel, un scalaire de premier niveau surchargeable par PIIGHOST_NAME
token_memo_ttl non Les secondes pendant lesquelles la carte de tokens mémoïsée d'un thread est gardée, un scalaire de premier niveau, exige un [memory]
[detector] oui L'étage de détection
[linker] non Le linker d'entités, par défaut ExactEntityLinker
[anonymizer] non L'étage de rendu, par défaut un Anonymizer avec une factory label-counter
[overlap_resolver] non Résout les détections qui se chevauchent, par défaut ConfidenceOverlapResolver
[expander] non Retrouve les occurrences manquées d'une valeur détectée
[entity_resolver] non Regroupe les entités qui désignent la même chose
[guard] non Revérifie la sortie pour une PII résiduelle
[override] non Force ou écarte des détections via une whitelist et une blacklist
[observation_redactor] non Une factory de placeholders caviardant les charges de trace
[memory] non La mémoire de conversation. Sa présence fait un pipeline de thread

[detector]

Discriminé sur type. Requis.

type = "regex"

Applique un regex par label, tiré des patterns en ligne, des catalogs nommés, ou des deux. Les catalogues fusionnent d'abord, puis les patterns en ligne, donc un pattern en ligne l'emporte sur un pattern de catalogue au même label. Au moins un pattern en ligne ou un catalogue est requis. Chaque pattern est validé comme un regex compilable au chargement, puis compilé sous re.ASCII, donc \d correspond à 0-9 et une classe de forme s'arrête au premier caractère non ASCII. Une valeur comme prénom@corp.com est donc reconnue à partir de nom.

Clé Type Défaut Signification
patterns dict[str, str] {} Correspondance label vers regex en ligne
catalogs list[str] [] Catalogues prêts, uniquement generic, us, eu, fr, tout autre nom échouant à la validation
[detector]
type = "regex"
catalogs = ["generic", "fr"]
patterns = { EMPLOYEE_ID = 'EMP-[0-9]{4}' }

type = "composite"

Exécute des détecteurs enfants ensemble et fusionne leurs détections.

Clé Type Signification
detectors list[detector] Les configs de détecteurs enfants, au moins un, sous [[detector.detectors]]
[detector]
type = "composite"

[[detector.detectors]]
type = "regex"
catalogs = ["generic"]

[[detector.detectors]]
type = "exact"
values = { Patrick = "PERSON" }

type = "exact"

Trouve les occurrences de valeurs littérales, chacune associée à un label.

Clé Type Signification
values dict[str, str] Correspondance valeur littérale vers label, au moins une
[detector]
type = "exact"
values = { Patrick = "PERSON", Lyon = "LOCATION" }

type = "chunked"

Enveloppe un détecteur avec un splitter qui découpe un texte long en tranches qui se chevauchent.

Clé Type Défaut Signification
detector detector Le détecteur exécuté sur chaque tranche, sous [detector.detector]
chunk_size int 1000 Taille maximale d'une tranche, supérieure à 0
chunk_overlap int 100 Chevauchement entre tranches, inférieur à chunk_size
[detector]
type = "chunked"
chunk_size = 2000
chunk_overlap = 200

[detector.detector]
type = "spacy"
model = "en_core_web_sm"

Détecteurs à modèle

Chacun nécessite son propre extra, et tous sauf presidio nécessitent un modèle. labels accepte une liste ou une map {emitted: internal}. max_concurrency plafonne les inférences concurrentes, ou None pour illimité.

type Extra Clés
gliner2 gliner2 model (requis), labels (requis), threshold (défaut 0.5), max_concurrency
spacy spacy model (requis), labels, max_concurrency
transformers transformers model (requis), labels, threshold (défaut 0.0), aggregation_strategy (défaut simple), max_concurrency
presidio presidio labels, language (défaut en), threshold (défaut 0.0)
llm llm model (requis), labels (requis), prompt, provider
[detector]
type = "gliner2"
model = "fastino/gliner2-multi-v1"
labels = ["PERSON", "LOCATION"]
threshold = 0.5

Le détecteur transformers passe aggregation_strategy à sa pipeline de classification de tokens, qui regroupe les sous-tokens en entités entières.

Le détecteur presidio ne prend aucune clé model, car le chemin par configuration construit l'AnalyzerEngine anglais par défaut de Presidio avec ses reconnaisseurs par défaut. Une autre langue, un reconnaisseur sur mesure ou un moteur NLP sur mesure passent par le chemin programmatique, en construisant le moteur et en le passant à PresidioDetector.

Le détecteur llm lit l'identifiant de son fournisseur depuis la variable d'environnement propre au fournisseur, jamais depuis le fichier.


[linker]

Optionnel. Par défaut ExactEntityLinker. Un seul linker existe, donc type le nomme sans discriminer une union.

type Signification
exact Regroupe les détections par valeur repliée en casse
[linker]
type = "exact"

[anonymizer]

Optionnel. Par défaut un Anonymizer avec une factory label-counter. Quand il est présent, il porte une table [anonymizer.placeholder] qui choisit la factory de placeholders, discriminée sur type.

type Token Clés
redact <<REDACT>>
label <<PERSON>>
label_counter <<PERSON:1>>
label_hash <<PERSON:a1b2c3d4>> hash_length (défaut 8, au moins 1)
mask P*** visible (défaut 1, 0 ou plus), mask_char (défaut *, exactement un caractère)
[anonymizer.placeholder]
type = "label_counter"

Le middleware a besoin d'une factory délimitée, donc redact, label, label_counter ou label_hash. La factory mask produit P***, qui ne garde aucun délimiteur et n'a pas de reconnaisseur.


[overlap_resolver]

Optionnel dans le fichier, mais l'étage tourne dans tous les cas. Omettre la section construit un ConfidenceOverlapResolver, et il n'existe aucun moyen supporté de désactiver l'étage, car l'étage de rendu suppose des spans disjoints. Un seul resolver existe, donc type le nomme sans discriminer une union.

type Signification
confidence Garde la détection la plus confiante quand deux se chevauchent
[overlap_resolver]
type = "confidence"

[expander]

Optionnel, et désactivé quand il est omis. Un seul expander existe, donc type le nomme sans discriminer une union.

type Clés Signification
word_boundary case_sensitive (défaut false) Retrouve les autres occurrences entières d'une valeur détectée
[expander]
type = "word_boundary"
case_sensitive = false

[entity_resolver]

Optionnel. Discriminé sur type.

type Extra Clés Signification
merge Unit les entités qui partagent des détections
separate Garde chaque entité distincte
fuzzy fuzzy threshold (défaut 0.85) Regroupe les entités au-dessus d'une similarité de Jaro-Winkler
[entity_resolver]
type = "fuzzy"
threshold = 0.85

[guard]

Optionnel. Discriminé sur type. Revérifie la sortie dé-identifiée pour une PII résiduelle et la refuse quand une PII subsiste.

type Extra Revérifie avec
detector Un détecteur réexécuté sur la sortie
llm llm Un modèle de chat à qui l'on demande la PII résiduelle
moderation mistral Un modèle de modération Mistral qui note la sortie

type = "detector"

Réexécute un détecteur sur la sortie. Porte une config imbriquée [guard.detector].

[guard]
type = "detector"

[guard.detector]
type = "regex"
patterns = { EMAIL = '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' }

type = "llm"

Demande à un modèle de chat de trouver une PII résiduelle.

Clé Type Signification
model str L'identifiant du modèle de chat (requis)
labels list ou dict Les labels à chercher (requis)
prompt str Un prompt qui remplace celui par défaut, ou omis
provider str Le fournisseur, ou omis pour l'inférer du modèle

type = "moderation"

Note la sortie avec un modèle de modération Mistral. L'identifiant est lu depuis MISTRAL_API_KEY à la construction, et build() lève ConfigError quand il est absent.

Clé Type Défaut Signification
model str mistral-moderation-latest Le modèle de modération
threshold float 0.5 Le score de catégorie au-dessus duquel le texte est signalé

[override]

Optionnel. Force des détections via une whitelist et en écarte via une blacklist. Chaque liste est une config de détecteur, [override.whitelist] et [override.blacklist], toutes deux optionnelles.

Clé Valeurs Défaut Signification
[override.whitelist] détecteur Un détecteur dont les hits sont forcés dans l'ensemble
[override.blacklist] détecteur Un détecteur dont les hits invalident des détections
blacklist_strategy exact, value, overlap value Comment un hit de blacklist invalide, même valeur repliée en casse, même span et label, ou tout span en chevauchement
whitelist_strategy respect_provenance, force respect_provenance Si un hit de whitelist laisse en clair une valeur introduite par l'assistant, ou la tokenise quand même
conflict_strategy whitelist_wins, blacklist_wins, raise whitelist_wins Qui l'emporte quand les deux listes se contredisent. raise refuse la collision avec ConflictingOverrideError
[override]
blacklist_strategy = "value"

[override.whitelist]
type = "regex"
patterns = { CODENAME = 'ACME-[A-Z]+' }

[override.blacklist]
type = "exact"
values = { "public@corp.com" = "EMAIL" }

[observation_redactor]

Optionnel. Une config de factory de placeholders, mêmes valeurs de type que [anonymizer.placeholder], caviardant les charges envoyées à un backend de traçage pour qu'une trace porte des tokens, pas des valeurs brutes.

[observation_redactor]
type = "label"

Omettre la section trace le texte en clair et les valeurs détectées, et un traceur actif émet alors un PIIGhostSecurityWarning. Le drapeau trace_clear_text du pipeline, qui fait taire cet avertissement, n'a aucune clé dans un fichier de configuration, donc un pipeline construit depuis un fichier ne peut pas assumer le traçage en clair. Passer trace_clear_text=True au pipeline est le chemin programmatique.


[memory]

Optionnel. Sa présence fait du pipeline un ThreadAnonymizationPipeline qui garde un état par thread. Discriminé sur type.

Le scalaire token_memo_ttl va avec, au premier niveau plutôt que dans cette section, puisqu'il borne la carte de tokens mémoïsée du pipeline et non le store. Le poser sans [memory] lève une erreur, un pipeline sans état ne mémoïsant rien. Pourquoi il compte sur un déploiement multi-worker est dans Déploiement multi-instance.

type Extra Stockage
in_memory Local au processus, perdu au redémarrage
redis redis Persistant, partagé entre workers
sqlalchemy sqlalchemy Durable, dans une base SQL

type = "in_memory"

Un stockage local au processus, perdu au redémarrage et non partagé entre workers.

Clé Type Défaut Signification
max_threads int None Plafond de threads gardés, éviction LRU au-delà (au moins 1)
ttl float None Expire un thread inactif paresseusement au prochain accès, en secondes (supérieur à 0)
[memory]
type = "in_memory"

type = "redis"

Un stockage persistant et multi-worker, qui indexe optionnellement chaque message stocké avec un hacheur et chiffre chaque valeur stockée avec un cipher.

Clé Type Défaut Signification
url str L'URL de connexion Redis (requis)
namespace str piighost Le préfixe de clé isolant les clés de cette librairie
ttl int None Secondes de vie d'un message stocké, ou omis pour garder jusqu'à l'éviction
[memory.hasher] hacheur Optionnel (les deux ou aucun). Le hacheur qui indexe chaque message
[memory.cipher] cipher Optionnel (les deux ou aucun). Le cipher qui chiffre chaque valeur

Configurez les deux, [memory.hasher] et [memory.cipher], ou aucun. Sans aucun, le backend stocke la correspondance en clair et émet un avertissement. Avec un seul, build() lève ConfigError.

Le hacheur, [memory.hasher], est discriminé sur type.

type Extra Clés Signification
sha256 HMAC-SHA256, un condensé rapide à clé
argon2 argon2 time_cost (défaut 2), memory_cost (défaut 19456), parallelism (défaut 1), hash_length (défaut 32) Argon2id, un condensé lent et gourmand en mémoire

Le cipher, [memory.cipher], a un seul type.

type Extra Signification
aesgcm crypto Chiffrement authentifié AES-GCM des valeurs stockées

Le hacheur lit son poivre depuis PIIGHOST_HASH_PEPPER et le cipher lit sa clé base64 depuis PIIGHOST_CIPHER_KEY, tous deux à la construction. Une valeur manquante ou mal formée lève ConfigError.

[memory]
type = "redis"
url = "redis://localhost:6379/0"
namespace = "piighost"
ttl = 3600

[memory.hasher]
type = "argon2"

[memory.cipher]
type = "aesgcm"

type = "sqlalchemy"

Un stockage durable et multi-worker adossé à n'importe quelle base supportée par SQLAlchemy (SQLite, PostgreSQL, ...). Il lit l'URL de la base depuis une variable d'environnement plutôt que le fichier de config, pour que l'URL et son mot de passe restent hors du gestionnaire de versions. Un hacheur et un cipher optionnels protègent les valeurs stockées exactement comme pour Redis.

Clé Type Défaut Signification
url_env str PIIGHOST_DATABASE_URL La variable d'environnement contenant l'URL async de la base
table_name str piighost_conversation_messages La table stockant les messages par thread
[memory.hasher] hacheur Optionnel (les deux ou aucun). Le hacheur qui indexe chaque message
[memory.cipher] cipher Optionnel (les deux ou aucun). Le cipher qui chiffre chaque valeur

Configurez les deux, [memory.hasher] et [memory.cipher], ou aucun, exactement comme pour Redis. Sans aucun, le backend stocke la correspondance en clair et émet un avertissement. Avec un seul, build() lève ConfigError.

L'URL doit utiliser un driver async, par exemple postgresql+asyncpg://... ou sqlite+aiosqlite://.... Une variable d'environnement manquante lève ConfigError à la construction. Appelez await memory.create_schema() une fois au démarrage pour créer la table.

[memory]
type = "sqlalchemy"
url_env = "PIIGHOST_DATABASE_URL"
table_name = "piighost_conversation_messages"

[memory.hasher]
type = "argon2"

[memory.cipher]
type = "aesgcm"

Exemple complet

Les clés de examples/config/pipeline.toml, un pipeline sans état qui tire un catalogue, ajoute un pattern en ligne, et active plusieurs étages optionnels. Le fichier lui-même porte les mêmes clés avec un commentaire sur chaque étage.

[detector]
type = "regex"
catalogs = ["generic"]
patterns = { EMPLOYEE_ID = 'EMP-[0-9]{4}' }

[overlap_resolver]
type = "confidence"

[expander]
type = "word_boundary"

[entity_resolver]
type = "fuzzy"
threshold = 0.85

[linker]
type = "exact"

[anonymizer.placeholder]
type = "label_counter"

[override.whitelist]
type = "regex"
patterns = { CODENAME = 'ACME-[A-Z]+' }

[guard]
type = "detector"

[guard.detector]
type = "regex"
patterns = { EMAIL = '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' }

[observation_redactor]
type = "label"

Le même contenu en JSON, choisi par un suffixe .json, est équivalent. Une table devient un objet, une table en ligne devient un objet imbriqué, et un tableau de tables devient un tableau d'objets.


Erreurs

Erreur Levée quand
ConfigFileError Le fichier est absent, illisible, ou du TOML ou JSON invalide
ConfigValidationError Les données analysées échouent à la validation du schéma
ConfigError Un secret manque à la construction, ou le mauvais point d'entrée est utilisé pour la mémoire déclarée

ConfigFileError et ConfigValidationError sont des sous-classes de ConfigError, donc attraper ConfigError couvre les trois. Les classes vivent dans piighost.exceptions, donc un appelant peut les attraper sans l'extra config.


Voir aussi