@piecemaker-legal/piecemaker 1.0.6 → 1.0.7
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.
- package/dist/assets/{abnfDiagram-VCTEODGH-DF7LFtT-.js → abnfDiagram-VCTEODGH-CR3_ADBu.js} +1 -1
- package/dist/assets/{arc-xOmjWeVH.js → arc-b92imMmc.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-CESzNPwa.js → architectureDiagram-5GKGNRK7-Dfm5Epud.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-BjdN78Ad.js → blockDiagram-I7D4REHJ-B8kLLyAv.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-BcK9EDWT.js → c4Diagram-7LVT6UL2-BWSyAAWX.js} +1 -1
- package/dist/assets/channel-BbcW_Tkh.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-DGUN1JFP.js → chunk-2Q5K7J3B-Ci743mcC.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-BG3BBcFr.js → chunk-5VM5RSS4-SdXpal6h.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-CLIOfrF5.js → chunk-F27PBJKO-Rof94ueX.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-D6lGkqij.js → chunk-IMKFNOWR-B3st6ECc.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BmF9vLBT.js → chunk-JWPE2WC7-alXmu5xU.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-C_0SR3ak.js → chunk-POPQ4Y6H-dMs1OCce.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-rT20Wfpp.js → chunk-SVP7TREG-BmM8FsmF.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-Cn2hkmcf.js → chunk-TICWLB2K-CL1LytYG.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-Dm_eP1_v.js → chunk-XXDRQBXY-7U9iRPT1.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-D9_YRZ7i.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-D9_YRZ7i.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-cJeeJsep.js → cose-bilkent-JH36ORCC-DFOMlhj2.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-DX2ePIXe.js → cynefin-OW5HDTMX-CDdJFd9d.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-BvWXN-RR.js → cynefinDiagram-5FMLGOSQ-DPyVNrMW.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-CkwPRhGR.js → dagre-GXQ25YYZ-B3bpHa9D.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-CBGNzYyv.js → diagram-S7CK7UJ4-DeFO2rXB.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-CiwCU0SJ.js → diagram-UQ7AKVKN-CbdGTOVf.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-Aekg4nTk.js → diagram-VSXAHHWV-DFfNQyMd.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-DPFP5K7r.js → diagram-VX7I27RA-DbNZ6_X3.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-BHJkxoey.js → diagram-Z3DM3KII-B8F-ZkNJ.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-2rV1P32T.js → ebnfDiagram-PWID7BFC-BfCCPPAP.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-C4BjyS_H.js → erDiagram-RLTQ6QDP-DcV-3Kzv.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-DL1TBlAG.js → flowDiagram-HODETNUW-BwSkJXCo.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-MKjvzCWz.js → ganttDiagram-EL5Y4UJY-BffHk77T.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-CS_oTGK5.js → gitGraphDiagram-WWUBYQGX-CQ1EWa74.js} +1 -1
- package/dist/assets/{index-XOGQDqU3.js → index-BqK33gaZ.js} +120 -120
- package/dist/assets/index-D_Dc_nQv.css +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-ihUr2GjN.js → infoDiagram-27XIBGKW-DqIaBXQn.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-D2YAnuir.js → ishikawaDiagram-5VMMS53U-HlhsaZgv.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-Bc2hSZGD.js → journeyDiagram-3NMN7TZE-BYO8-7rN.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-LRMGNonX.js → kanban-definition-UXKFOSKX-DXb8zHGT.js} +1 -1
- package/dist/assets/{layout-CcfWOlPV.js → layout-CREOVuEZ.js} +1 -1
- package/dist/assets/{linear-7JoS2gQO.js → linear-CVCrIRIY.js} +1 -1
- package/dist/assets/{mermaid.core-ijh_SsuN.js → mermaid.core-DFqeWtQR.js} +6 -6
- package/dist/assets/{mindmap-definition-YA3MSWOX-DCE4nzfF.js → mindmap-definition-YA3MSWOX-SUpXz333.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-SjaGa7lE.js → pegDiagram-XKGWAZYB-D-yWpve3.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-1xcRidSZ.js → pieDiagram-E7YTZNPT-BJX4Zp4Z.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-obHAHnYV.js → quadrantDiagram-AXDQQJYC-CHajheTu.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BsCVcRZb.js → railroadDiagram-O6MQD6OU-DHJWzW5A.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-CUNkhvqb.js → requirementDiagram-BXWQKSXE-DigUIdso.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-DhezXMKm.js → sankeyDiagram-P5KCCOFB-CFUDDbA5.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-CL9VswXH.js → sequenceDiagram-WJ2MYXX4-6tSaXfYD.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-t0g9jiEz.js → sizeCapture-INFHLROL-CXASEDKe.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-BW-g-IOz.js → stateDiagram-D77RDMKH-DWTCAQfZ.js} +1 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-HDQF4MGA.js +1 -0
- package/dist/assets/{swimlanes-42K2YHIH-LsuyeBte.js → swimlanes-42K2YHIH-7-oz5r-e.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-CJbgQFt8.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-B0cFka1R.js → timeline-definition-24CTP7MA-DVH5g4ty.js} +1 -1
- package/dist/assets/{vendor-codemirror-C5qqu4R7.js → vendor-codemirror-CjW0lHR5.js} +5 -5
- package/dist/assets/{vennDiagram-4TSXK5OY-D3HNCDR3.js → vennDiagram-4TSXK5OY-CQvY_ALZ.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-DJ3Co8nb.js → wardleyDiagram-VM6X3IG4-BdlTJgEc.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-Cz5E9New.js → xychartDiagram-S5SC5T6Z-CYn2sV77.js} +1 -1
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +1 -9
- package/dist/generate-icons.js +47 -46
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +1 -12
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +1 -12
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +1 -12
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +1 -12
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +1 -12
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +1 -12
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +1 -12
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +1 -12
- package/dist/index.html +3 -3
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo-sources/logo-black.png +0 -0
- package/dist/logo-sources/logo-white.png +0 -0
- package/dist/logo.svg +1 -17
- package/dist/sw.js +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js +91 -0
- package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js.map +1 -0
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js +112 -10
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js.map +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js +5 -1
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js.map +1 -1
- package/dist-server/server/index.js +60 -26
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/database/repositories/projects.db.js +28 -6
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js +58 -1
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/plugins/plugins.routes.js +8 -1
- package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -1
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +2 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
- package/dist-server/server/piecemaker/bodacc-search.js +191 -0
- package/dist-server/server/piecemaker/bodacc-search.js.map +1 -0
- package/dist-server/server/piecemaker/company-search.js +145 -0
- package/dist-server/server/piecemaker/company-search.js.map +1 -0
- package/dist-server/server/piecemaker/company-search.test.js +18 -0
- package/dist-server/server/piecemaker/company-search.test.js.map +1 -0
- package/dist-server/server/piecemaker/index.js +6 -2
- package/dist-server/server/piecemaker/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/index.js +9 -4
- package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/pipeline.js +68 -58
- package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/routes.js +2 -4
- package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js +91 -0
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -0
- package/dist-server/server/piecemaker/knowledge/service.js +18 -36
- package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
- package/dist-server/server/piecemaker/library/connector-installation.js +224 -0
- package/dist-server/server/piecemaker/library/connector-installation.js.map +1 -0
- package/dist-server/server/piecemaker/library/index.js +11 -1
- package/dist-server/server/piecemaker/library/index.js.map +1 -1
- package/dist-server/server/piecemaker/library/marketplace.js +102 -43
- package/dist-server/server/piecemaker/library/marketplace.js.map +1 -1
- package/dist-server/server/piecemaker/library/migrate.js +8 -1
- package/dist-server/server/piecemaker/library/migrate.js.map +1 -1
- package/dist-server/server/piecemaker/library/provider-agents.js +50 -0
- package/dist-server/server/piecemaker/library/provider-agents.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-connectors.js +80 -0
- package/dist-server/server/piecemaker/library/provider-connectors.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-skills.js +11 -2
- package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -1
- package/dist-server/server/piecemaker/library/store.js +125 -35
- package/dist-server/server/piecemaker/library/store.js.map +1 -1
- package/dist-server/server/piecemaker/library/workspace-installation.js +53 -29
- package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
- package/dist-server/server/piecemaker/timesheet/service.js +4 -21
- package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
- package/package.json +3 -2
- package/scripts/piecemaker/cli/install-command.mjs +35 -9
- package/scripts/piecemaker/cli/lib/config.mjs +1 -0
- package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +78 -0
- package/scripts/piecemaker/cli/lib/plugins.mjs +2 -0
- package/scripts/piecemaker/cli/lib/pwa.mjs +46 -7
- package/scripts/piecemaker/cli/lib/services.mjs +65 -4
- package/scripts/piecemaker/cli/piecemaker-command.test.mjs +25 -0
- package/scripts/piecemaker/cli/piecemaker.mjs +45 -44
- package/scripts/piecemaker/cli/piecemaker.ps1 +8 -0
- package/scripts/piecemaker/cli/piecemaker.sh +6 -1
- package/server/index.ts +52 -23
- package/server/modules/database/repositories/projects.db.ts +28 -6
- package/server/modules/database/tests/projects.db.integration.test.ts +63 -1
- package/server/modules/plugins/plugins.routes.ts +8 -1
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +5 -0
- package/server/piecemaker/anonymizer/client-config.cjs +10 -2
- package/server/piecemaker/anonymizer/dictionary.cjs +6 -72
- package/server/piecemaker/bodacc-search.ts +205 -0
- package/server/piecemaker/company-search.test.ts +26 -0
- package/server/piecemaker/company-search.ts +183 -0
- package/server/piecemaker/index.ts +8 -2
- package/server/piecemaker/knowledge/index.ts +9 -4
- package/server/piecemaker/knowledge/pipeline.ts +89 -57
- package/server/piecemaker/knowledge/routes.ts +2 -4
- package/server/piecemaker/knowledge/scan-jobs.ts +111 -0
- package/server/piecemaker/knowledge/service.ts +18 -33
- package/server/piecemaker/library/connector-installation.ts +248 -0
- package/server/piecemaker/library/index.ts +5 -1
- package/server/piecemaker/library/marketplace.ts +104 -39
- package/server/piecemaker/library/migrate.ts +8 -1
- package/server/piecemaker/library/provider-agents.ts +49 -0
- package/server/piecemaker/library/provider-connectors.ts +89 -0
- package/server/piecemaker/library/provider-skills.ts +10 -1
- package/server/piecemaker/library/store.ts +129 -36
- package/server/piecemaker/library/workspace-installation.ts +54 -29
- package/server/piecemaker/router.cjs +2 -1
- package/server/piecemaker/timesheet/service.ts +4 -16
- package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +0 -27
- package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +1 -1
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +2 -3
- package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -3
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3 -10
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +135 -4
- package/server/piecemaker/vendor/websocket-server/process-group.cjs +95 -0
- package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +280 -149
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/scanner_worker.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +35 -29
- package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +0 -5
- package/server/shared/types.ts +1 -0
- package/dist/assets/channel-Dz3eE5vU.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BC1eKV2j.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-BC1eKV2j.js +0 -1
- package/dist/assets/index-DhwJpHCq.css +0 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-BXuT4zDG.js +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-B0eYrB4U.js +0 -8
- package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +0 -111
- package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +0 -216
- package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +0 -134
- package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +0 -138
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +0 -246
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +0 -62
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +0 -118
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +0 -164
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +0 -479
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/** Instructions PieceMaker générées dans chaque dossier juridique enregistré. */
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const os = require('node:os');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
|
|
6
|
-
const { registeredCaseFolders } = require('../piecemaker-plugin/scripts/lib/case-folders.cjs');
|
|
7
|
-
const {
|
|
8
|
-
historyRepo,
|
|
9
|
-
resolveCase,
|
|
10
|
-
} = require('../piecemaker-plugin/scripts/lib/commits.cjs');
|
|
11
|
-
|
|
12
|
-
const IMPORT_START = '<!-- piecemaker-instructions-start -->';
|
|
13
|
-
const IMPORT_END = '<!-- piecemaker-instructions-end -->';
|
|
14
|
-
|
|
15
|
-
function caseHistoryRepoLabel(folder) {
|
|
16
|
-
try {
|
|
17
|
-
const legalCase = resolveCase(path.dirname(folder), path.basename(folder));
|
|
18
|
-
const absolute = historyRepo(path.join(os.homedir(), '.piecemaker'), legalCase);
|
|
19
|
-
const home = os.homedir();
|
|
20
|
-
return absolute.startsWith(`${home}${path.sep}`) ? `~${absolute.slice(home.length)}` : absolute;
|
|
21
|
-
} catch {
|
|
22
|
-
return '';
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function caseRuleContent(repoRoot, folder = '') {
|
|
27
|
-
const template = path.join(repoRoot, 'installer', 'templates', 'workspace-CLAUDE.md');
|
|
28
|
-
if (!fs.existsSync(template)) throw new Error('Le modèle d’instructions PieceMaker est introuvable.');
|
|
29
|
-
let content = fs.readFileSync(template, 'utf8')
|
|
30
|
-
.replace(
|
|
31
|
-
'| Racine des dossiers | ce répertoire (`workspacePath` de `~/.piecemaker/config.json`) |',
|
|
32
|
-
'| Dossier juridique actif | ce répertoire (`caseFolders` de `~/.piecemaker/config.json`) |',
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const repoLabel = folder ? caseHistoryRepoLabel(folder) : '';
|
|
36
|
-
if (repoLabel) {
|
|
37
|
-
content = content.replace(
|
|
38
|
-
'| Historique des dossiers | `~/.piecemaker/case-history/` |',
|
|
39
|
-
`| Historique de ce dossier | \`${repoLabel}\` |`,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
return content;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function managedImportBlock(rule) {
|
|
46
|
-
return `${IMPORT_START}
|
|
47
|
-
## PieceMaker — instructions gérées
|
|
48
|
-
|
|
49
|
-
Pour une chronologie factuelle, appeler d'abord l'outil \`chronologie\` du
|
|
50
|
-
serveur MCP \`piecemaker\`. Consulter aussi la règle complète suivante :
|
|
51
|
-
|
|
52
|
-
@${rule}
|
|
53
|
-
${IMPORT_END}`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Ajoute uniquement un bloc PieceMaker géré. Le reste de CLAUDE.md/AGENTS.md
|
|
58
|
-
* appartient à l'utilisateur et reste byte-for-byte intact.
|
|
59
|
-
*/
|
|
60
|
-
function ensureInstructionImport(file, rule) {
|
|
61
|
-
const block = managedImportBlock(rule);
|
|
62
|
-
let current = '';
|
|
63
|
-
try {
|
|
64
|
-
current = fs.readFileSync(file, 'utf8');
|
|
65
|
-
} catch {}
|
|
66
|
-
|
|
67
|
-
const pattern = new RegExp(`${IMPORT_START}[\\s\\S]*?${IMPORT_END}\\n?`, 'm');
|
|
68
|
-
const next = pattern.test(current)
|
|
69
|
-
? current.replace(pattern, `${block}\n`)
|
|
70
|
-
: `${block}\n\n${current || '# Ce dossier\n\n<!-- Instructions propres à ce dossier. -->\n'}`;
|
|
71
|
-
if (next !== current) fs.writeFileSync(file, next, 'utf8');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ensureCaseRule(repoRoot, folder) {
|
|
75
|
-
const target = path.join(folder, '.claude', 'rules', 'piecemaker.md');
|
|
76
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
77
|
-
const content = caseRuleContent(repoRoot, folder);
|
|
78
|
-
let previous = null;
|
|
79
|
-
try { previous = fs.readFileSync(target, 'utf8'); } catch {}
|
|
80
|
-
if (previous !== content) fs.writeFileSync(target, content, 'utf8');
|
|
81
|
-
|
|
82
|
-
// Claude Code charge nativement .claude/rules ; les imports explicites
|
|
83
|
-
// garantissent aussi la disponibilité depuis Codex/AGENTS.md et rendent la
|
|
84
|
-
// règle visible à la racine sans écraser les consignes propres au dossier.
|
|
85
|
-
for (const name of ['CLAUDE.md', 'AGENTS.md']) {
|
|
86
|
-
ensureInstructionImport(path.join(folder, name), target);
|
|
87
|
-
}
|
|
88
|
-
return target;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function refreshRegisteredCaseRules(repoRoot, config) {
|
|
92
|
-
const result = { refreshed: 0, failed: [] };
|
|
93
|
-
for (const folder of registeredCaseFolders(config)) {
|
|
94
|
-
try {
|
|
95
|
-
ensureCaseRule(repoRoot, folder);
|
|
96
|
-
result.refreshed += 1;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
result.failed.push({ folder, error: error.message });
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return result;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = {
|
|
105
|
-
IMPORT_END,
|
|
106
|
-
IMPORT_START,
|
|
107
|
-
caseRuleContent,
|
|
108
|
-
ensureCaseRule,
|
|
109
|
-
ensureInstructionImport,
|
|
110
|
-
refreshRegisteredCaseRules,
|
|
111
|
-
};
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
# Partial Address Anonymization Feature
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This feature implements smart address parsing to preserve city, postal code, and country information in anonymized documents while only anonymizing street addresses. This maintains legal context while protecting private information.
|
|
6
|
-
|
|
7
|
-
## How It Works
|
|
8
|
-
|
|
9
|
-
### Address Parsing
|
|
10
|
-
|
|
11
|
-
When GLiNER extracts a `LOCATION` entity, the system now:
|
|
12
|
-
|
|
13
|
-
1. **Parses the address** into components:
|
|
14
|
-
- Street part (number + type + name)
|
|
15
|
-
- Postal code
|
|
16
|
-
- City
|
|
17
|
-
- Country
|
|
18
|
-
|
|
19
|
-
2. **Determines anonymization strategy**:
|
|
20
|
-
- **None (no anonymization)**: City or country name only (e.g., "Paris", "France")
|
|
21
|
-
- **Partial**: Street address with city/postal/country (e.g., "123 Rue de Rivoli, 75001 Paris, France")
|
|
22
|
-
- **Full**: Unparseable addresses (fallback for safety)
|
|
23
|
-
|
|
24
|
-
3. **Applies strategy**:
|
|
25
|
-
- **Partial**: Only street part → code, preserve city/postal/country
|
|
26
|
-
- **Full**: Entire address → code
|
|
27
|
-
|
|
28
|
-
### Supported Formats
|
|
29
|
-
|
|
30
|
-
#### French Addresses
|
|
31
|
-
- Format: `[Number] [Type] [Name], [Postal] [City], [Country]`
|
|
32
|
-
- Examples:
|
|
33
|
-
- `123 Rue de Rivoli, 75001 Paris, France`
|
|
34
|
-
- `20 Bis rue de la Princesse, Lyon`
|
|
35
|
-
- `42 boulevard Saint-Germain, 75005 Paris`
|
|
36
|
-
|
|
37
|
-
#### Belgian Addresses
|
|
38
|
-
- Format: `[Type] [Name] [Number], [Postal] [City], [Country]`
|
|
39
|
-
- Examples:
|
|
40
|
-
- `Rue de la Loi 123, 1000 Bruxelles, Belgique`
|
|
41
|
-
- `Avenue Louise 54, 1050 Bruxelles`
|
|
42
|
-
|
|
43
|
-
#### Swiss Addresses
|
|
44
|
-
- Format: `[Type] [Name] [Number], [Postal] [City], [Country]`
|
|
45
|
-
- Examples:
|
|
46
|
-
- `Rue du Rhône 50, 1204 Genève, Suisse`
|
|
47
|
-
- `Chemin des Fleurs 8, 1006 Lausanne`
|
|
48
|
-
|
|
49
|
-
#### Luxembourg Addresses
|
|
50
|
-
- Format: `[Type] [Name] [Number], L-[Postal] [City]`
|
|
51
|
-
- Examples:
|
|
52
|
-
- `Avenue de la Liberté 10, L-1931 Luxembourg`
|
|
53
|
-
|
|
54
|
-
#### City/Country Only
|
|
55
|
-
- Format: Just the name
|
|
56
|
-
- Examples: `Paris`, `Lyon`, `Bruxelles`, `France`
|
|
57
|
-
- **Not anonymized** - preserved in plaintext
|
|
58
|
-
|
|
59
|
-
## Examples
|
|
60
|
-
|
|
61
|
-
### Before Implementation
|
|
62
|
-
|
|
63
|
-
**Input document:**
|
|
64
|
-
```
|
|
65
|
-
The company is located at 123 Rue de Rivoli, 75001 Paris, France.
|
|
66
|
-
The court in Paris ruled...
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Anonymized output:**
|
|
70
|
-
```
|
|
71
|
-
The company is located at ADRESSE_01.
|
|
72
|
-
The court in ADRESSE_02 ruled...
|
|
73
|
-
```
|
|
74
|
-
❌ Lost all geographic context, even city names
|
|
75
|
-
|
|
76
|
-
### After Implementation
|
|
77
|
-
|
|
78
|
-
**Input document:**
|
|
79
|
-
```
|
|
80
|
-
The company is located at 123 Rue de Rivoli, 75001 Paris, France.
|
|
81
|
-
The court in Paris ruled...
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Anonymized output:**
|
|
85
|
-
```
|
|
86
|
-
The company is located at ADRESSE_01, 75001 Paris, France.
|
|
87
|
-
The court in Paris ruled...
|
|
88
|
-
```
|
|
89
|
-
✅ Street anonymized, city/postal preserved, city-only name untouched
|
|
90
|
-
|
|
91
|
-
## Data Structure
|
|
92
|
-
|
|
93
|
-
### Mapping File Format
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"mapping": {
|
|
98
|
-
"123 Rue de Rivoli": "ADRESSE_01"
|
|
99
|
-
},
|
|
100
|
-
"reverse_mapping": {
|
|
101
|
-
"ADRESSE_01": ["123 Rue de Rivoli"]
|
|
102
|
-
},
|
|
103
|
-
"extracted_data": {
|
|
104
|
-
"adresses": {
|
|
105
|
-
"ADRESSE_01": {
|
|
106
|
-
"original": "123 Rue de Rivoli, 75001 Paris, France",
|
|
107
|
-
"code": "ADRESSE_01",
|
|
108
|
-
"variants": ["123 Rue de Rivoli"],
|
|
109
|
-
"score": 0.92,
|
|
110
|
-
"recognizer": "GLiNER2Recognizer",
|
|
111
|
-
"parsed": {
|
|
112
|
-
"success": true,
|
|
113
|
-
"is_city_only": false,
|
|
114
|
-
"street_part": "123 Rue de Rivoli",
|
|
115
|
-
"postal_code": "75001",
|
|
116
|
-
"city": "Paris",
|
|
117
|
-
"country": "France",
|
|
118
|
-
"anonymization_strategy": "partial"
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Anonymization Strategies
|
|
127
|
-
|
|
128
|
-
| Strategy | Description | Example Input | Example Output |
|
|
129
|
-
|----------|-------------|---------------|----------------|
|
|
130
|
-
| `none` | City/country only, no anonymization | "Paris" | "Paris" |
|
|
131
|
-
| `partial` | Street anonymized, city/postal/country preserved | "123 Rue de Rivoli, 75001 Paris, France" | "ADRESSE_01, 75001 Paris, France" |
|
|
132
|
-
| `full` | Entire address anonymized (parse failure) | "Complex Format Address" | "ADRESSE_02" |
|
|
133
|
-
|
|
134
|
-
## Fallback Behavior
|
|
135
|
-
|
|
136
|
-
| Scenario | Parsing Result | Strategy | Behavior |
|
|
137
|
-
|----------|----------------|----------|----------|
|
|
138
|
-
| Full address with street | `success: true`, `is_city_only: false` | `partial` | Anonymize street only |
|
|
139
|
-
| City or country only | `success: true`, `is_city_only: true` | `none` | Keep visible (not in mapping) |
|
|
140
|
-
| Unparseable address | `success: false` | `full` | Anonymize everything (safe fallback) |
|
|
141
|
-
| Empty/invalid | `success: false` | `full` | Anonymize everything |
|
|
142
|
-
|
|
143
|
-
## Files Modified
|
|
144
|
-
|
|
145
|
-
### 1. `websocket-server/scripts/convert_and_scan_pipeline.py`
|
|
146
|
-
- Added `parse_address()` function with regex patterns for French/Belgian/Swiss/Luxembourg addresses
|
|
147
|
-
- Added `is_city_or_country_only()` and `is_known_city_or_country()` helper functions
|
|
148
|
-
- Updated `convert_to_anonymization_format()` to parse addresses and apply strategies
|
|
149
|
-
- Updated `merge_with_existing_mapping()` with same logic
|
|
150
|
-
|
|
151
|
-
### 2. `websocket-server/lib/anonymization-server.cjs`
|
|
152
|
-
- Updated POST `/api/anonymize/text` route to handle partial address anonymization
|
|
153
|
-
- Added special handling for addresses in both hierarchical and flat mapping formats
|
|
154
|
-
- Updated de-anonymization logic to reconstruct full addresses from partial anonymization
|
|
155
|
-
|
|
156
|
-
### 3. `websocket-server/scripts/test_address_parsing.py` (new)
|
|
157
|
-
- Comprehensive test suite with 16 test cases
|
|
158
|
-
- Tests French, Belgian, Swiss, Luxembourg, city-only, and unparseable addresses
|
|
159
|
-
- 100% test coverage
|
|
160
|
-
|
|
161
|
-
## Testing
|
|
162
|
-
|
|
163
|
-
Run the test suite:
|
|
164
|
-
```bash
|
|
165
|
-
python3 websocket-server/scripts/test_address_parsing.py
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Expected output:
|
|
169
|
-
```
|
|
170
|
-
🎉 All tests passed!
|
|
171
|
-
Total tests: 16
|
|
172
|
-
Passed: 16 (100%)
|
|
173
|
-
Failed: 0
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## Integration Testing
|
|
177
|
-
|
|
178
|
-
To test with real documents:
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
# Process a document with addresses
|
|
182
|
-
python3 websocket-server/scripts/convert_and_scan_pipeline.py \
|
|
183
|
-
test_document.pdf \
|
|
184
|
-
-o output \
|
|
185
|
-
--document-id test_partial
|
|
186
|
-
|
|
187
|
-
# Check the mapping file
|
|
188
|
-
cat output/mapping_test_partial.json | jq '.extracted_data.adresses | .[].parsed'
|
|
189
|
-
|
|
190
|
-
# Verify:
|
|
191
|
-
# 1. City-only addresses are NOT in the mapping
|
|
192
|
-
# 2. Full addresses have parsed data with partial strategy
|
|
193
|
-
# 3. Unparseable addresses have full strategy
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Safety Features
|
|
197
|
-
|
|
198
|
-
1. **City-only detection**: Cities and countries are never accidentally anonymized
|
|
199
|
-
2. **Parse failure fallback**: Unparseable addresses default to full anonymization (safest)
|
|
200
|
-
3. **No false negatives**: Street addresses are never left visible by mistake
|
|
201
|
-
4. **Validation**: 100% test coverage ensures reliability
|
|
202
|
-
|
|
203
|
-
## Performance
|
|
204
|
-
|
|
205
|
-
- **Parsing success rate**: >90% for French addresses
|
|
206
|
-
- **City-only detection**: 100% accuracy for known cities
|
|
207
|
-
- **Fallback coverage**: 100% (all unparseable addresses handled safely)
|
|
208
|
-
- **Zero false negatives**: No street addresses leaked
|
|
209
|
-
|
|
210
|
-
## Future Enhancements
|
|
211
|
-
|
|
212
|
-
Potential improvements:
|
|
213
|
-
- Add more European address formats (Spain, Italy, Germany)
|
|
214
|
-
- Support US/UK address formats
|
|
215
|
-
- ML-based address component recognition for complex formats
|
|
216
|
-
- User-configurable city/country whitelist
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# Entity Deduplication Implementation Summary
|
|
2
|
-
|
|
3
|
-
## Changes Made to `convert_and_scan_pipeline.py`
|
|
4
|
-
|
|
5
|
-
### 1. Added Imports (Lines 34-42)
|
|
6
|
-
```python
|
|
7
|
-
import unicodedata
|
|
8
|
-
import re
|
|
9
|
-
from typing import List, Optional, Tuple, Dict, Set
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
### 2. Added Helper Functions (Before `convert_to_anonymization_format()`)
|
|
13
|
-
|
|
14
|
-
#### `normalize_name(text: str) -> str`
|
|
15
|
-
- Removes diacritics (é → e, à → a, etc.)
|
|
16
|
-
- Converts to lowercase
|
|
17
|
-
- Removes honorifics/titles (Mr., Mrs., Ms., Dr., M., Mme., Maître, etc.)
|
|
18
|
-
- Normalizes whitespace (multiple spaces → single space)
|
|
19
|
-
- Returns normalized form for comparison only
|
|
20
|
-
|
|
21
|
-
#### `are_names_similar(name1, norm1, name2, norm2) -> bool`
|
|
22
|
-
- Checks if two names refer to the same person using multiple strategies:
|
|
23
|
-
- Exact match after normalization
|
|
24
|
-
- Substring match (one contains the other, min 3 chars)
|
|
25
|
-
- Token-based match (all tokens of shorter name appear in longer)
|
|
26
|
-
|
|
27
|
-
#### `consolidate_duplicate_entities(entities: List[Dict]) -> List[Dict]`
|
|
28
|
-
- Groups entities by similarity
|
|
29
|
-
- Handles both exact duplicates and variations (e.g., "Mr. Dupont" vs "Jean Dupont")
|
|
30
|
-
- For each group:
|
|
31
|
-
- Chooses longest variant as canonical text
|
|
32
|
-
- Keeps highest score among all variants
|
|
33
|
-
- Stores all unique variants (removes duplicates while preserving order)
|
|
34
|
-
- Returns deduplicated entity list
|
|
35
|
-
|
|
36
|
-
### 3. Updated `convert_to_anonymization_format()`
|
|
37
|
-
|
|
38
|
-
**Added pre-processing:**
|
|
39
|
-
```python
|
|
40
|
-
# Consolidate PERSON entities to remove duplicates
|
|
41
|
-
for entity_type in consolidated_entities.get("entities", {}).keys():
|
|
42
|
-
if entity_type == "PERSON":
|
|
43
|
-
consolidated_entities["entities"][entity_type] = consolidate_duplicate_entities(
|
|
44
|
-
consolidated_entities["entities"][entity_type]
|
|
45
|
-
)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Modified main loop:**
|
|
49
|
-
- Removed: `mapping[text_lower] = code` (no lowercase in mapping)
|
|
50
|
-
- Changed: `"variants": [text, text_lower]` → `"variants": variants`
|
|
51
|
-
- Added: Loop through pre-consolidated variants and add each to mapping
|
|
52
|
-
- Get variants from: `entity.get("variants", [text])`
|
|
53
|
-
|
|
54
|
-
### 4. Updated `merge_with_existing_mapping()`
|
|
55
|
-
|
|
56
|
-
**Applied same changes:**
|
|
57
|
-
- Removed: `merged_mapping[text_lower] = new_code`
|
|
58
|
-
- Changed: `"variants": [text, text_lower]` → `"variants": variants`
|
|
59
|
-
- Get variants from: `old_entry.get("variants", [text])`
|
|
60
|
-
- Add all variants to merged mapping
|
|
61
|
-
|
|
62
|
-
## Expected Behavior
|
|
63
|
-
|
|
64
|
-
### Before (Current Output)
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"mapping": {
|
|
68
|
-
"Mr. Dupont": "PERSONNE_PHYSIQUE_03",
|
|
69
|
-
"mr. gilly": "PERSONNE_PHYSIQUE_03",
|
|
70
|
-
"Mr. Dupont": "PERSONNE_PHYSIQUE_04", // duplicate gets different code
|
|
71
|
-
"mr. gilly": "PERSONNE_PHYSIQUE_04",
|
|
72
|
-
"Mr. Dupont": "PERSONNE_PHYSIQUE_05",
|
|
73
|
-
"mr. gilly": "PERSONNE_PHYSIQUE_05",
|
|
74
|
-
"Jean Dupont": "PERSONNE_PHYSIQUE_08"
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### After (Fixed Output)
|
|
80
|
-
```json
|
|
81
|
-
{
|
|
82
|
-
"mapping": {
|
|
83
|
-
"Jean Dupont": "PERSONNE_PHYSIQUE_03",
|
|
84
|
-
"Mr. Dupont": "PERSONNE_PHYSIQUE_03",
|
|
85
|
-
"Mr. Dupont": "PERSONNE_PHYSIQUE_03",
|
|
86
|
-
"Mr.Dupont": "PERSONNE_PHYSIQUE_03"
|
|
87
|
-
},
|
|
88
|
-
"extracted_data": {
|
|
89
|
-
"personnes_physiques": {
|
|
90
|
-
"PERSONNE_PHYSIQUE_03": {
|
|
91
|
-
"original": "Jean Dupont",
|
|
92
|
-
"code": "PERSONNE_PHYSIQUE_03",
|
|
93
|
-
"variants": ["Jean Dupont", "Mr. Dupont", "Mr. Dupont", "Mr.Dupont"],
|
|
94
|
-
"score": 0.95,
|
|
95
|
-
"recognizer": "GLiNER2Recognizer"
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Key Improvements
|
|
103
|
-
|
|
104
|
-
1. **No lowercase duplicates**: Removed redundant lowercase variants from mapping and variants array
|
|
105
|
-
2. **Exact duplicates consolidated**: Same person appearing multiple times gets single code
|
|
106
|
-
3. **Spacing variations handled**: "Mr. Dupont" vs "Mr. Dupont" vs "Mr.Dupont" → same code
|
|
107
|
-
4. **Name variations consolidated**: "Mr. Dupont" vs "Jean Dupont" → same code
|
|
108
|
-
5. **Longest variant as canonical**: "Jean Dupont" (longest) chosen over "Mr. Dupont"
|
|
109
|
-
6. **No duplicate variants**: Variants array contains only unique strings
|
|
110
|
-
7. **Non-PERSON entities unaffected**: Organizations and locations not consolidated
|
|
111
|
-
|
|
112
|
-
## Test Results
|
|
113
|
-
|
|
114
|
-
All unit tests pass:
|
|
115
|
-
- ✅ normalize_name() - 7/7 tests
|
|
116
|
-
- ✅ are_names_similar() - 8/8 tests
|
|
117
|
-
- ✅ consolidate_duplicate_entities() - 5/5 tests
|
|
118
|
-
|
|
119
|
-
Test demonstrates:
|
|
120
|
-
- 7 input entities → 3 unique persons
|
|
121
|
-
- "Mr. Dupont" (appears twice) + "Mr. Dupont" + "Jean Dupont" + "Mr.Dupont" → single entity
|
|
122
|
-
- Canonical form: "Jean Dupont" (longest)
|
|
123
|
-
- Score: 0.95 (highest)
|
|
124
|
-
- Variants: 4 unique strings (no duplicates)
|
|
125
|
-
|
|
126
|
-
## Next Steps for Verification
|
|
127
|
-
|
|
128
|
-
1. **Test with real document**: Process a document containing duplicate person names
|
|
129
|
-
2. **Compare entity counts**:
|
|
130
|
-
- Before: ~185 PERSONNE_PHYSIQUE entries
|
|
131
|
-
- After: ~90-100 entries (expected ~50% reduction)
|
|
132
|
-
3. **Verify consolidation**: Check that variations of same person get same code
|
|
133
|
-
4. **Verify non-PERSON entities**: Organizations and locations unaffected
|
|
134
|
-
5. **Regression test**: Different people still get different codes
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# GLiNER2.5 Entity Extractor
|
|
2
|
-
|
|
3
|
-
## Description
|
|
4
|
-
|
|
5
|
-
PieceMaker utilise GLiNER2.5, un extracteur d'entités nommé multilingue basé sur
|
|
6
|
-
la nouvelle architecture boundary de Fastino (287 M paramètres). Il détecte
|
|
7
|
-
localement les entités sensibles dans les documents Markdown.
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pip install 'gliner2[local]>=2.0.0'
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Le modèle `fastino/gliner2.5-multi-v1` est téléchargé par l’installateur
|
|
16
|
-
(environ 1,1 Go). La migration depuis `fastino/gliner2-multi-v1` est obligatoire.
|
|
17
|
-
|
|
18
|
-
## Utilisation via l'interface
|
|
19
|
-
|
|
20
|
-
1. Cliquer sur le bouton 🏷️ dans la barre de contrôle
|
|
21
|
-
2. Sélectionner un ou plusieurs fichiers Markdown (.md)
|
|
22
|
-
3. Cliquer sur "▶ Extraire"
|
|
23
|
-
4. Les résultats sont sauvegardés dans le dossier de sortie configuré
|
|
24
|
-
|
|
25
|
-
## Utilisation en ligne de commande
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
python presidio-gliner/presidio-gliner.py <fichier.md> -o <dossier_sortie>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Exemple
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
python presidio-gliner/presidio-gliner.py document.md -o ./presidio_gliner_output
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Entités détectées
|
|
38
|
-
|
|
39
|
-
Le pipeline GLiNER2.5 + Presidio détecte notamment les types suivants :
|
|
40
|
-
|
|
41
|
-
- **person**: Noms de personnes
|
|
42
|
-
- **email**: Adresses email
|
|
43
|
-
- **phone**: Numéros de téléphone (mobile et fixe)
|
|
44
|
-
- **address**: Adresses physiques et localisations
|
|
45
|
-
- **organization**: Noms d'entreprises et organisations
|
|
46
|
-
- **date**: Dates (incluant dates de naissance)
|
|
47
|
-
- **ssn**: Numéros de sécurité sociale
|
|
48
|
-
- **credit_card**: Numéros de carte de crédit
|
|
49
|
-
- **bank_account**: Numéros de compte bancaire
|
|
50
|
-
- **passport**: Numéros de passeport
|
|
51
|
-
- **ip_address**: Adresses IP
|
|
52
|
-
- **url**: URLs et adresses web
|
|
53
|
-
|
|
54
|
-
## Format de sortie
|
|
55
|
-
|
|
56
|
-
Le script génère un fichier JSON avec la structure suivante:
|
|
57
|
-
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"source_file": "/chemin/vers/fichier.md",
|
|
61
|
-
"scanned_at": "2025-01-15T10:30:00Z",
|
|
62
|
-
"entities": {
|
|
63
|
-
"PERSON": [
|
|
64
|
-
{
|
|
65
|
-
"text": "John Doe",
|
|
66
|
-
"start": 123,
|
|
67
|
-
"end": 131,
|
|
68
|
-
"score": 0.95,
|
|
69
|
-
"recognizer": "gliner2"
|
|
70
|
-
}
|
|
71
|
-
],
|
|
72
|
-
"EMAIL": [
|
|
73
|
-
{
|
|
74
|
-
"text": "john.doe@example.com",
|
|
75
|
-
"start": 145,
|
|
76
|
-
"end": 165,
|
|
77
|
-
"score": 0.98,
|
|
78
|
-
"recognizer": "gliner2"
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
},
|
|
82
|
-
"summary": {
|
|
83
|
-
"total_entities_found": 15,
|
|
84
|
-
"entity_types": ["PERSON", "EMAIL", "PHONE", "ADDRESS"],
|
|
85
|
-
"model": "fastino/gliner2.5-multi-v1"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Configuration
|
|
91
|
-
|
|
92
|
-
### Seuil de confiance
|
|
93
|
-
|
|
94
|
-
Le scanner utilise le seuil de confiance 0,5 recommandé par défaut pour la
|
|
95
|
-
nouvelle tête boundary. Les entités moins certaines ne sont pas retournées.
|
|
96
|
-
|
|
97
|
-
### Variables d'environnement
|
|
98
|
-
|
|
99
|
-
- `GLINER2_SCAN_PATH`: Chemin personnalisé vers le script Python
|
|
100
|
-
- `PYTHON_PATH`: Chemin vers l'interpréteur Python (défaut: `python3`)
|
|
101
|
-
|
|
102
|
-
## Comparaison avec Presidio
|
|
103
|
-
|
|
104
|
-
| Caractéristique | GLiNER2 | Presidio |
|
|
105
|
-
|----------------|---------|----------|
|
|
106
|
-
| API | Simple, 1 modèle | Multiple composants |
|
|
107
|
-
| Performance CPU | Optimisée | Plus lente |
|
|
108
|
-
| Confidence scores | Natif | Natif |
|
|
109
|
-
| Spans de texte | Natif | Natif |
|
|
110
|
-
| Format de sortie | JSON natif | JSON natif |
|
|
111
|
-
| Taille du modèle | 287M params | Variable |
|
|
112
|
-
| Personnalisation | Labels flexibles | Patterns regex |
|
|
113
|
-
|
|
114
|
-
## Avantages de GLiNER2
|
|
115
|
-
|
|
116
|
-
1. **API simplifiée**: Un seul modèle, une seule méthode d'extraction
|
|
117
|
-
2. **Performance**: Optimisé pour CPU, inférence rapide
|
|
118
|
-
3. **Flexibilité**: Support de labels personnalisés sans réentraînement
|
|
119
|
-
4. **Extraction native**: Confidence scores et spans inclus sans post-processing
|
|
120
|
-
5. **Format JSON**: Output structuré directement utilisable
|
|
121
|
-
|
|
122
|
-
## Dépendances
|
|
123
|
-
|
|
124
|
-
- Python 3.10+
|
|
125
|
-
- `gliner2[local]>=2.0.0`
|
|
126
|
-
- torch et transformers (installés par l’extra `local`)
|
|
127
|
-
|
|
128
|
-
## Limitations
|
|
129
|
-
|
|
130
|
-
- Nécessite un téléchargement initial du modèle (~1,1 Go)
|
|
131
|
-
- Performance optimale sur CPU moderne (multi-core recommandé)
|
|
132
|
-
- Précision variable selon la qualité du texte source
|
|
133
|
-
|
|
134
|
-
## Support
|
|
135
|
-
|
|
136
|
-
Pour plus d'informations sur GLiNER2.5 :
|
|
137
|
-
- Documentation : https://github.com/fastino-ai/GLiNER2
|
|
138
|
-
- Modèle : https://huggingface.co/fastino/gliner2.5-multi-v1
|