nomos-ai 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -h \"^import\\\\|^from\" /c/Users/corla/Desktop/projects/NomosAI/*.py /c/Users/corla/Desktop/projects/NomosAI/src/*.py)",
5
+ "Bash(grep -h \"except ImportError\\\\|sys.exit.*pip install\" /c/Users/corla/Desktop/projects/NomosAI/src/*.py)"
6
+ ]
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .uv/
7
+ .venv/
8
+ *.whl
9
+ data/example/
@@ -0,0 +1,62 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ NomosAI is a CLI document anonymization tool for legal/compliance use cases. It detects and replaces PII in documents (DOCX, PDF, TXT, MD, RST) and outputs anonymized Markdown files with GDPR-compliant metadata. The project is Python 3, French-first, with no build system or test suite.
8
+
9
+ ## Setup
10
+
11
+ ```bash
12
+ pip install -r requirements.txt
13
+ python -m spacy download fr_core_news_lg # required for French (default)
14
+ python -m spacy download en_core_web_lg # optional for English
15
+ ```
16
+
17
+ ## Running the Tool
18
+
19
+ A conda env is installed on this machine to run the python scripts in this project.
20
+ Conda env name nomosai
21
+
22
+ ```bash
23
+ # Single file
24
+ python anonymize.py report.pdf
25
+
26
+ # Specify output
27
+ python anonymize.py contract.docx --output contract_redacted.md
28
+
29
+ # Batch (recursive directory)
30
+ python anonymize.py dossier/ --recursive --language fr --output dossier_anonymise/
31
+
32
+ # Limit entity types
33
+ python anonymize.py notes.txt --entities PERSON EMAIL_ADDRESS PHONE_NUMBER
34
+
35
+ # Adjust confidence threshold (default 0.55)
36
+ python anonymize.py file.pdf --score-threshold 0.6
37
+ ```
38
+
39
+ ## Architecture
40
+
41
+ The pipeline is: **Reader → Engine → Formatter → Output file**
42
+
43
+ 1. **`src/readers.py`** — Converts DOCX/PDF/TXT/MD/RST into a list of `Block` dataclasses (`type`, `text`, `cells`). Block types: `heading1/2/3`, `paragraph`, `table_row`, `list_item`, `hr`.
44
+
45
+ 2. **`src/engine.py`** — Core anonymization logic.
46
+ - `DocumentAnonymizer` wraps the Microsoft Presidio analyzer (backed by spaCy NLP).
47
+ - Replaces PII with numbered placeholders (`[PERSON_1]`, `[EMAIL_2]`) — the same PII value always maps to the same placeholder within a document.
48
+ - French-specific recognizers are injected into the registry when `language=="fr"`.
49
+ - `_HIGH_CONFIDENCE_ONLY` set (`FR_SIREN`, `FR_CNI`, `FR_POSTAL_CODE`) requires score ≥ 0.70 regardless of the `--score-threshold` flag.
50
+
51
+ 3. **`src/recognizers_fr.py`** — Custom regex recognizers for French PII: NIR (sécu), SIRET, SIREN, TVA, CNI, passport, driving license, postal codes, French phone numbers. Each is a `PatternRecognizer` registered for `language="fr"`.
52
+
53
+ 4. **`src/formatter.py`** — Renders anonymized blocks as Markdown with a YAML frontmatter (source, timestamp, language, entity counts, GDPR flag) and a RGPD compliance footer.
54
+
55
+ 5. **`anonymize.py`** — CLI entry point; parses args, wires up engine + reader + formatter, handles single-file and batch modes.
56
+
57
+ ## Key Implementation Notes
58
+
59
+ - **Presidio is the detection backbone**: adding a new entity type means writing a `PatternRecognizer` or `EntityRecognizer` subclass in `recognizers_fr.py` and registering it.
60
+ - **Replacement order matters**: `engine.py` processes Presidio results in reverse position order to avoid index drift during in-place string substitution.
61
+ - **Batch mode** generates a GDPR summary report alongside the anonymized files.
62
+ - **No config file**: all defaults live in `anonymize.py` (default language `fr`, default threshold `0.55`).
@@ -0,0 +1,294 @@
1
+ # NomosAI — Guide d'utilisation (Serveur MCP)
2
+
3
+ NomosAI expose ses capacités d'anonymisation via un serveur MCP (Model Context Protocol),
4
+ ce qui permet à un agent LLM (Claude Code, Claude Desktop) d'anonymiser et de restaurer
5
+ des documents directement, sans passer par le CLI.
6
+
7
+ ---
8
+
9
+ ## Prérequis
10
+
11
+ **Première installation (une seule fois par machine) — installer `uv` :**
12
+
13
+ - **Windows** — ouvre PowerShell et colle :
14
+ ```
15
+ powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
16
+ ```
17
+ - **Mac** — ouvre Terminal et colle :
18
+ ```bash
19
+ curl -LsSf https://astral.sh/uv/install.sh | sh
20
+ ```
21
+
22
+ `uv` gère automatiquement Python et toutes les dépendances (spaCy, Presidio, modèle
23
+ français `fr_core_news_lg`). Aucun conda, aucun `pip install`, aucun `spacy download`
24
+ n'est nécessaire.
25
+
26
+ > **Windows — important :** après l'installation, `uv` et `uvx` ne sont pas disponibles
27
+ > dans le terminal déjà ouvert. **Ferme et rouvre un nouveau terminal** (PowerShell ou
28
+ > cmd) avant de continuer — sans ça, toutes les commandes suivantes échoueront avec
29
+ > *"n'est pas reconnu comme commande"*.
30
+
31
+ > **Première utilisation :** au premier démarrage, `uvx` télécharge automatiquement
32
+ > le modèle spaCy `fr_core_news_lg` (~550 Mo) et installe ~80 paquets — cela prend
33
+ > **2 à 5 minutes** selon la connexion. Les démarrages suivants sont instantanés.
34
+
35
+ ---
36
+
37
+ ## 1. Brancher à Claude Desktop (recommandé)
38
+
39
+ Édite le fichier de configuration de Claude Desktop :
40
+
41
+ - **Windows :** `%APPDATA%\Claude\claude_desktop_config.json`
42
+ - **Mac :** `~/Library/Application Support/Claude/claude_desktop_config.json`
43
+
44
+ Ajoute (ou crée) ce contenu :
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "nomos-ai": {
50
+ "command": "uvx",
51
+ "args": ["nomos-ai"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Redémarre Claude Desktop. Le serveur apparaît dans la liste des outils (icône marteau).
58
+
59
+ ---
60
+
61
+ ## 2. Brancher à Claude Code
62
+
63
+ ### Étape 1 — Enregistrer le serveur
64
+
65
+ Ouvre un terminal **dans le dossier du projet** et exécute cette commande **une seule fois** :
66
+
67
+ ```bash
68
+ claude mcp add nomos-ai -- uvx --from "C:\chemin\vers\NomosAI" nomos-ai
69
+ ```
70
+
71
+ Remplace `C:\chemin\vers\NomosAI` par le chemin absolu du dossier cloné.
72
+ Exemple : `C:\Users\prenom\Desktop\projects\NomosAI`.
73
+
74
+ ### Étape 2 — Pré-chauffer l'environnement (première fois uniquement)
75
+
76
+ La première fois, `uvx` doit télécharger les dépendances (~550 Mo). Lance manuellement
77
+ le serveur une fois pour déclencher ce téléchargement **avant** de faire la vérification :
78
+
79
+ ```bash
80
+ uvx --from "C:\chemin\vers\NomosAI" nomos-ai
81
+ ```
82
+
83
+ Attends que les logs s'affichent (`INFO Loaded recognizer: ...`), puis interromps
84
+ avec `Ctrl+C`. Le cache est maintenant prêt.
85
+
86
+ ### Étape 3 — Vérifier la connexion
87
+
88
+ ```bash
89
+ claude mcp list
90
+ # → nomos-ai uvx --from ... ✓ Connected
91
+ ```
92
+
93
+ > **"Failed to connect" à l'étape 3 ?** C'est normal si l'étape 2 n'est pas terminée
94
+ > (téléchargement encore en cours). Attend la fin du téléchargement et relance
95
+ > `claude mcp list`.
96
+
97
+ Le serveur démarre automatiquement quand Claude Code en a besoin.
98
+
99
+ ---
100
+
101
+ ## 3. Tester les outils manuellement (inspecteur MCP)
102
+
103
+ Pour explorer et tester les outils interactivement :
104
+
105
+ ```bash
106
+ npx @modelcontextprotocol/inspector uvx nomos-ai
107
+ ```
108
+
109
+ Ouvre ensuite `http://localhost:5173` dans un navigateur.
110
+
111
+ ---
112
+
113
+ ## 4. Anonymiser du texte brut
114
+
115
+ Demande à l'agent (dans Claude Code ou Claude Desktop) :
116
+
117
+ > *« Anonymise ce texte : "Le Dr Jean Dupont, joignable au 01 23 45 67 89, travaille
118
+ > à la clinique Saint-Louis. Son numéro de sécu est 1 85 06 75 123 456 78." »*
119
+
120
+ L'agent appelle l'outil `anonymize_text` et retourne dans sa réponse :
121
+
122
+ - le **texte anonymisé** avec les placeholders (`[PERSONNE_1]`, `[TELEPHONE_1]`…)
123
+ - les **statistiques** de détection par type d'entité
124
+ - l'**index complet** des remplacements (placeholder → valeur originale)
125
+
126
+ ### Paramètres disponibles
127
+
128
+ | Paramètre | Défaut | Description |
129
+ |-----------|--------|-------------|
130
+ | `text` | — | Texte à anonymiser |
131
+ | `language` | `"fr"` | Langue NLP : `fr`, `en`, `de`, `es`, `it`, `nl`, `pt` |
132
+ | `entities` | tous | Limiter à certains types, ex. `["PERSON", "EMAIL_ADDRESS"]` |
133
+ | `score_threshold` | `0.55` | Seuil de confiance (0.0–1.0) |
134
+
135
+ ---
136
+
137
+ ## 5. Anonymiser un fichier
138
+
139
+ Formats supportés : `.docx`, `.pdf`, `.txt`, `.md`, `.rst`
140
+
141
+ Demande à l'agent :
142
+
143
+ > *« Anonymise le fichier `C:\dossiers\contrat.pdf` »*
144
+
145
+ ou avec options :
146
+
147
+ > *« Anonymise `C:\dossiers\contrat.pdf` en français, uniquement les noms et e-mails,
148
+ > et écris le résultat dans `C:\dossiers\anonymise\contrat.md` »*
149
+
150
+ L'agent appelle `anonymize_file` et génère deux fichiers :
151
+
152
+ | Fichier | Contenu | Confidentialité |
153
+ |---------|---------|-----------------|
154
+ | `contrat_anonymise.md` | Document anonymisé, partageable | Public |
155
+ | `contrat_anonymise-index.md` | Mapping placeholder → valeur originale | **Confidentiel** |
156
+
157
+ ### Paramètres disponibles
158
+
159
+ | Paramètre | Défaut | Description |
160
+ |-----------|--------|-------------|
161
+ | `file_path` | — | Chemin absolu du fichier source |
162
+ | `output_path` | `<nom>_anonymise.md` | Chemin du `.md` de sortie |
163
+ | `language` | `"fr"` | Langue NLP |
164
+ | `entities` | tous | Types d'entités à détecter (voir section 7) |
165
+ | `score_threshold` | `0.55` | Seuil de confiance |
166
+ | `write_index` | `true` | Générer le fichier confidentiel `-index.md` |
167
+
168
+ > **Important :** Conserve le fichier `-index.md` si tu veux pouvoir restaurer le document
169
+ > original ultérieurement. Sans lui, la désanonymisation est impossible.
170
+
171
+ ---
172
+
173
+ ## 6. Désanonymiser un document
174
+
175
+ Demande à l'agent :
176
+
177
+ > *« Restaure le fichier `C:\dossiers\contrat_anonymise.md` »*
178
+
179
+ L'agent appelle `deanonymize_file`. Il cherche automatiquement `contrat_anonymise-index.md`
180
+ dans le même dossier et génère `contrat_restaure.md`.
181
+
182
+ Si l'index est dans un emplacement différent :
183
+
184
+ > *« Restaure `C:\dossiers\contrat_anonymise.md` avec l'index
185
+ > `C:\archives\contrat_anonymise-index.md` »*
186
+
187
+ ### Paramètres disponibles
188
+
189
+ | Paramètre | Défaut | Description |
190
+ |-----------|--------|-------------|
191
+ | `anonymized_file_path` | — | Chemin du `.md` anonymisé |
192
+ | `index_path` | auto-détecté | Chemin de l'index si non standard |
193
+ | `output_path` | `<stem>_restaure.md` | Chemin du fichier restauré |
194
+
195
+ ---
196
+
197
+ ## 7. Découvrir les types de PII détectables
198
+
199
+ Demande à l'agent :
200
+
201
+ > *« Quels types d'entités NomosAI peut-il détecter en français ? »*
202
+
203
+ L'agent appelle `list_entities` et liste tous les types disponibles. Réponse instantanée,
204
+ sans chargement du modèle NLP.
205
+
206
+ ### Types actifs par défaut (français)
207
+
208
+ | Type | Label | Description |
209
+ |------|-------|-------------|
210
+ | `PERSON` | `PERSONNE` | Noms de personnes physiques |
211
+ | `ORGANIZATION` | `ORGANISATION` | Noms d'organisations ou entreprises |
212
+ | `LOCATION` | `LIEU` | Lieux géographiques, adresses |
213
+ | `EMAIL_ADDRESS` | `EMAIL` | Adresses e-mail |
214
+ | `PHONE_NUMBER` | `TELEPHONE` | Numéros de téléphone |
215
+ | `IBAN_CODE` | `IBAN` | Codes IBAN bancaires |
216
+ | `CREDIT_CARD` | `CARTE_CREDIT` | Numéros de carte de crédit |
217
+ | `URL` | `URL` | URLs et liens web |
218
+ | `IP_ADDRESS` | `IP` | Adresses IP |
219
+ | `FR_NIR` | `NIR` | Numéro INSEE / Sécurité Sociale (15 chiffres) |
220
+ | `FR_SIRET` | `SIRET` | Identifiant établissement (14 chiffres) |
221
+ | `FR_SIREN` | `SIREN` | Identifiant entreprise (9 chiffres) |
222
+ | `FR_TVA` | `TVA` | Numéro TVA intracommunautaire |
223
+ | `FR_PASSPORT` | `PASSEPORT` | Numéro de passeport français |
224
+ | `FR_CNI` | `CNI` | Carte Nationale d'Identité (12 chiffres) |
225
+ | `FR_DRIVING_LICENSE` | `PERMIS` | Permis de conduire post-2013 (AA-NNN-AA) |
226
+ | `FR_POSTAL_CODE` | `CODE_POSTAL` | Code postal français (avec contexte) |
227
+
228
+ ### Types opt-in (à activer explicitement)
229
+
230
+ Ces types génèrent du bruit s'ils sont activés par défaut ; ils doivent être demandés
231
+ explicitement dans le paramètre `entities` :
232
+
233
+ | Type | Label | Description |
234
+ |------|-------|-------------|
235
+ | `DATE_TIME` | `DATE` | Dates et heures |
236
+ | `FILE_PATH` | `CHEMIN_FICHIER` | Chemins de fichiers Windows/Unix (français uniquement) |
237
+
238
+ Exemple d'activation :
239
+
240
+ > *« Anonymise `rapport.pdf` en détectant aussi les dates »*
241
+ > → l'agent passe `entities: ["PERSON", "EMAIL_ADDRESS", ..., "DATE_TIME"]`
242
+
243
+ ---
244
+
245
+ ## 8. Récapitulatif des outils MCP
246
+
247
+ | Outil | Usage typique |
248
+ |-------|---------------|
249
+ | `anonymize_text` | Anonymiser un extrait de texte passé directement à l'agent |
250
+ | `anonymize_file` | Anonymiser un fichier `.docx/.pdf/.txt/.md/.rst` sur disque |
251
+ | `deanonymize_file` | Restaurer un `.md` anonymisé à partir de son index confidentiel |
252
+ | `list_entities` | Lister les types de PII détectables (réponse instantanée) |
253
+
254
+ ---
255
+
256
+ ## 9. Flux de travail typique
257
+
258
+ ```
259
+ Document original (.pdf / .docx)
260
+
261
+
262
+ anonymize_file
263
+
264
+ ├─► contrat_anonymise.md ← partageable, traitable par LLM
265
+ └─► contrat_anonymise-index.md ← confidentiel, à conserver précieusement
266
+
267
+
268
+ deanonymize_file
269
+
270
+
271
+ contrat_restaure.md ← document original restauré
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Utilisation locale (développeurs)
277
+
278
+ Pour les contributeurs qui travaillent sur le code source, l'environnement conda `nomosai`
279
+ reste utilisable :
280
+
281
+ ```bash
282
+ conda activate nomosai
283
+ python -m nomosai.server # démarre le serveur MCP manuellement
284
+ python anonymize.py rapport.pdf # CLI d'anonymisation
285
+ python deanonymize.py rapport_anonymise.md # CLI de restauration
286
+ ```
287
+
288
+ Configuration Claude Code (développement local) :
289
+
290
+ ```bash
291
+ claude mcp add nomos-ai \
292
+ --cwd "C:\Users\corla\Desktop\projects\NomosAI" \
293
+ -- "C:\Users\corla\anaconda3\envs\nomosai\python.exe" -m nomosai.server
294
+ ```
@@ -0,0 +1,300 @@
1
+ Metadata-Version: 2.4
2
+ Name: nomos-ai
3
+ Version: 0.1.0
4
+ Summary: GDPR-compliant document anonymization MCP server for legal use
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: mcp[cli]>=1.0
7
+ Requires-Dist: pdfminer-six>=20221105
8
+ Requires-Dist: pdfplumber>=0.11
9
+ Requires-Dist: presidio-analyzer>=2.2.351
10
+ Requires-Dist: presidio-anonymizer>=2.2.351
11
+ Requires-Dist: pypdf>=4.0
12
+ Requires-Dist: python-docx>=1.1
13
+ Requires-Dist: spacy<3.9,>=3.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # NomosAI — Anonymiseur de documents juridiques
17
+
18
+ Détecte et masque les données personnelles (RGPD) dans des documents `.docx`, `.pdf`, `.txt`, `.md` et `.rst`, et produit un Markdown structuré avec métadonnées de conformité.
19
+ Moteur : [Microsoft Presidio](https://github.com/microsoft/presidio) + [spaCy](https://spacy.io/) · **Langue par défaut : français**.
20
+
21
+ Distribué comme **serveur MCP** — utilisable directement depuis Claude Desktop ou Claude Code, sans interface graphique.
22
+
23
+ ---
24
+
25
+ ## Installation rapide (utilisateurs finaux)
26
+
27
+ **Étape 1 — Installer `uv` (une seule fois par machine) :**
28
+
29
+ - **Windows :** ouvre PowerShell et colle :
30
+ ```
31
+ powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
32
+ ```
33
+ - **Mac :** ouvre Terminal et colle :
34
+ ```bash
35
+ curl -LsSf https://astral.sh/uv/install.sh | sh
36
+ ```
37
+
38
+ **Étape 2 — Ajouter NomosAI à Claude Desktop :**
39
+
40
+ Édite `%APPDATA%\Claude\claude_desktop_config.json` (Windows) ou
41
+ `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac) :
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "nomos-ai": {
47
+ "command": "uvx",
48
+ "args": ["nomos-ai"]
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ Redémarre Claude Desktop. Au premier démarrage, `uvx` télécharge automatiquement toutes les dépendances (modèle spaCy `fr_core_news_lg` inclus, ~600 Mo) — environ 1 à 3 minutes. Les démarrages suivants sont instantanés.
55
+
56
+ Pour plus de détails, voir le **[Guide d'utilisation MCP](NomosAI-Anonymisation-UserGuide.md)**.
57
+
58
+ ---
59
+
60
+ ## Formats supportés
61
+
62
+ | Entrée | Librairie |
63
+ |--------|-----------|
64
+ | `.docx` | `python-docx` |
65
+ | `.pdf` | `pdfminer.six` (fallback : `pypdf`) |
66
+ | `.txt` / `.md` / `.rst` | natif |
67
+
68
+ ---
69
+
70
+ ## Installation développeur
71
+
72
+ Pour travailler sur le code source :
73
+
74
+ ```bash
75
+ # Cloner le dépôt et installer en mode éditable
76
+ pip install -e .
77
+
78
+ # Ou via conda (environnement existant)
79
+ conda activate nomosai
80
+ pip install -e .
81
+ ```
82
+
83
+ Le modèle spaCy est installé automatiquement comme dépendance du package.
84
+ Pour ajouter le modèle anglais (optionnel) :
85
+
86
+ ```bash
87
+ python -m spacy download en_core_web_lg
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Anonymisation — `anonymize.py`
93
+
94
+ ```bash
95
+ # Fichier unique (sortie : <nom>_anonymise.md)
96
+ python anonymize.py rapport.pdf
97
+
98
+ # Sortie explicite
99
+ python anonymize.py contrat.docx --output contrat_anon.md
100
+
101
+ # Dossier complet
102
+ python anonymize.py dossier/ --output dossier_anonymise/
103
+
104
+ # Dossier récursif
105
+ python anonymize.py dossier/ --recursive --language fr
106
+
107
+ # Limiter les types d'entités
108
+ python anonymize.py notes.txt --entities PERSON EMAIL_ADDRESS PHONE_NUMBER
109
+
110
+ # Ajuster le seuil de confiance (défaut : 0.55)
111
+ python anonymize.py file.pdf --score-threshold 0.6
112
+
113
+ # Activer les entités opt-in (dates, chemins fichiers)
114
+ python anonymize.py file.pdf --entities PERSON DATE_TIME FILE_PATH
115
+ ```
116
+
117
+ Chaque exécution produit deux fichiers :
118
+
119
+ | Fichier | Contenu |
120
+ |---------|---------|
121
+ | `<nom>_anonymise.md` | Document anonymisé avec frontmatter YAML RGPD |
122
+ | `<nom>_anonymise-index.md` | **Confidentiel** — table `placeholder → valeur originale` |
123
+
124
+ En mode dossier, un `RAPPORT_ANONYMISATION.md` de synthèse est également généré.
125
+
126
+ ---
127
+
128
+ ## Désanonymisation — `deanonymize.py`
129
+
130
+ Restaure les valeurs originales à partir de l'index.
131
+
132
+ ```bash
133
+ # Index auto-détecté (<fichier>-index.md voisin)
134
+ python deanonymize.py contrat_anonymise.md
135
+
136
+ # Index explicite
137
+ python deanonymize.py contrat_anonymise.md --index contrat_anonymise-index.md
138
+
139
+ # Sortie explicite
140
+ python deanonymize.py contrat_anonymise.md --output contrat_restaure.md
141
+
142
+ # Dossier complet
143
+ python deanonymize.py dossier_anonymise/ --output dossier_restaure/
144
+ ```
145
+
146
+ > ⚠ Ce script restaure des données personnelles. Réservez-le aux personnes habilitées.
147
+
148
+ ---
149
+
150
+ ## Entités détectées
151
+
152
+ ### Par défaut
153
+
154
+ | Entité | Label | Description |
155
+ |--------|-------|-------------|
156
+ | `PERSON` | `[PERSONNE_N]` | Noms de personnes (NLP + titres Pr/Dr/M./Mme) |
157
+ | `ORGANIZATION` | `[ORGANISATION_N]` | Noms d'organisations |
158
+ | `LOCATION` | `[ADRESSE_N]` | Lieux, adresses |
159
+ | `EMAIL_ADDRESS` | `[EMAIL_N]` | Adresses e-mail |
160
+ | `PHONE_NUMBER` | `[TELEPHONE_N]` | Numéros français (+33, 0033, local) |
161
+ | `URL` | `[URL_N]` | URLs |
162
+ | `IP_ADDRESS` | `[IP_N]` | Adresses IP |
163
+ | `CREDIT_CARD` | `[CARTE_BANCAIRE_N]` | Numéros de carte bancaire |
164
+ | `IBAN_CODE` | `[IBAN_N]` | IBAN |
165
+ | `NRP` | `[ID_NATIONAL_N]` | Identifiants nationaux |
166
+ | `MEDICAL_LICENSE` | `[LICENCE_MEDICALE_N]` | Licences médicales |
167
+ | `CRYPTO` | `[CRYPTO_N]` | Adresses crypto |
168
+
169
+ ### Reconnaisseurs français supplémentaires
170
+
171
+ | Entité | Label | Exemples |
172
+ |--------|-------|---------|
173
+ | `FR_NIR` | `[NIR_N]` | Numéro de sécurité sociale (15 chiffres) |
174
+ | `FR_SIRET` | `[SIRET_N]` | SIRET (14 chiffres) |
175
+ | `FR_SIREN` | `[SIREN_N]` | SIREN (9 chiffres) |
176
+ | `FR_TVA` | `[TVA_N]` | TVA intracommunautaire |
177
+ | `FR_PASSPORT` | `[PASSEPORT_N]` | Passeport français |
178
+ | `FR_CNI` | `[CNI_N]` | Carte nationale d'identité |
179
+ | `FR_DRIVING_LICENSE` | `[PERMIS_N]` | Permis de conduire |
180
+ | `FR_POSTAL_CODE` | `[CODE_POSTAL_N]` | Code postal (avec contexte) |
181
+
182
+ ### Entités opt-in (à activer via `--entities`)
183
+
184
+ | Entité | Label | Remarque |
185
+ |--------|-------|---------|
186
+ | `DATE_TIME` | `[DATE_N]` | Dates — exclus par défaut (bruit dans les rapports) |
187
+ | `FILE_PATH` | `[CHEMIN_FICHIER_N]` | Chemins Windows/Unix — français uniquement, exclus par défaut |
188
+
189
+ ---
190
+
191
+ ## Architecture
192
+
193
+ ```
194
+ anonymize.py CLI principal (lecture, anonymisation, écriture)
195
+ deanonymize.py CLI de restauration à partir de l'index
196
+ src/
197
+ nomosai/
198
+ readers.py Lecture DOCX/PDF/TXT/MD/RST → liste de Block
199
+ engine.py Moteur Presidio + filtres faux positifs + dédup spans
200
+ recognizers_fr.py Reconnaisseurs regex français (NIR, SIRET, téléphone…)
201
+ formatter.py Rendu Markdown + frontmatter RGPD
202
+ server.py Serveur MCP (FastMCP, transport stdio)
203
+ pyproject.toml Métadonnées du package et dépendances
204
+ ```
205
+
206
+ **Pipeline :** `Reader → Engine → Formatter → fichier .md + fichier -index.md`
207
+
208
+ ---
209
+
210
+ ## Qualité de détection
211
+
212
+ ### Seuils de confiance
213
+
214
+ Le seuil global par défaut est `0.55`. Certains types ont un plancher plus élevé pour réduire les faux positifs :
215
+
216
+ | Type | Seuil minimum |
217
+ |------|---------------|
218
+ | `LOCATION` | 0.80 (sur-détection dans les tableaux PDF) |
219
+ | `FR_SIREN` | 0.70 |
220
+ | `FR_CNI` | 0.70 |
221
+ | `FR_POSTAL_CODE` | 0.70 |
222
+
223
+ ### Filtres anti-faux-positifs
224
+
225
+ L'engine rejette automatiquement les détections dont le texte :
226
+ - est une lettre ou sigle de 1–3 caractères (`F`, `NR`, `ET`…)
227
+ - est une valeur statistique (`N=1 035`, `75,6`…)
228
+ - est un numéro de section (`II.4`, `I.1`…)
229
+ - est un fragment tout-en-majuscules multi-mots (en-tête de tableau)
230
+ - contient des artefacts OCR (espaces intrus dans un mot)
231
+
232
+ ---
233
+
234
+ ## Ajouter un reconnaisseur personnalisé
235
+
236
+ ```python
237
+ from presidio_analyzer import PatternRecognizer, Pattern
238
+
239
+ MY_RECOGNIZER = PatternRecognizer(
240
+ supported_entity="MY_ENTITY",
241
+ supported_language="fr",
242
+ patterns=[Pattern("MY_PATTERN", r"\bREGEX\b", score=0.85)],
243
+ context=["mot", "clé", "contextuel"],
244
+ )
245
+ ```
246
+
247
+ Ajouter l'instance dans `get_french_recognizers()` de `src/nomosai/recognizers_fr.py` et son label dans `FRENCH_ENTITY_LABELS`.
248
+
249
+ Voir la [doc Presidio](https://microsoft.github.io/presidio/analyzer/adding_recognizers/).
250
+
251
+ ---
252
+
253
+ ## Publier une nouvelle version sur PyPI
254
+
255
+ ### Première publication (une seule fois)
256
+
257
+ 1. Créer un compte sur [pypi.org](https://pypi.org/account/register/)
258
+ 2. Générer un token API : **Account Settings → API tokens → Add API token**
259
+ 3. Publier :
260
+
261
+ ```bash
262
+ uv build
263
+ uv publish --token pypi-<VOTRE_TOKEN>
264
+ ```
265
+
266
+ ### Mettre à jour une version existante
267
+
268
+ ```bash
269
+ # 1. Incrémenter la version dans pyproject.toml
270
+ # ex. version = "0.1.0" → version = "0.2.0"
271
+
272
+ # 2. Construire et publier
273
+ uv build
274
+ uv publish --token pypi-<VOTRE_TOKEN>
275
+ ```
276
+
277
+ ### Vérifier l'installation depuis PyPI
278
+
279
+ Sur une machine sans l'environnement de développement :
280
+
281
+ ```bash
282
+ uvx nomos-ai
283
+ # → le serveur MCP démarre (attend sur stdin, pas d'erreur)
284
+ ```
285
+
286
+ ### Stocker le token de façon permanente
287
+
288
+ Pour ne pas retaper le token à chaque publication, créer `~/.pypirc` :
289
+
290
+ ```ini
291
+ [pypi]
292
+ username = __token__
293
+ password = pypi-<VOTRE_TOKEN>
294
+ ```
295
+
296
+ Puis publier simplement avec :
297
+
298
+ ```bash
299
+ uv publish
300
+ ```