File size: 4,380 Bytes
1766da1
 
 
 
 
 
 
a42c174
 
 
 
1766da1
 
 
a42c174
 
 
 
 
2b782d0
7e28f42
 
a42c174
 
2b782d0
a42c174
2b782d0
 
a42c174
 
 
2b782d0
a42c174
 
2b782d0
 
 
 
a42c174
1766da1
 
a42c174
 
 
 
1766da1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Documentation développeur Picarones

Guides courts pour étendre Picarones sans casser les invariants
fondamentaux du projet.

## Architecture

Voir [CLAUDE.md](../../CLAUDE.md) et
[`docs/explanation/architecture.md`](../explanation/architecture.md)
pour la cartographie complète.  En résumé : architecture **8
couches concentriques** (post-rewrite, canonique) :

```
picarones/
├── domain/              # Layer 1 — types purs (Pydantic, stdlib only)
│   ├── artifacts.py     # Artifact, ArtifactType (10 types)
│   ├── corpus.py        # CorpusSpec
│   ├── documents.py     # DocumentRef
│   ├── pipeline_spec.py # PipelineSpec, PipelineStep (Pydantic immutable)
│   ├── module_protocol.py # BaseModule (ABC)
│   ├── facts.py         # Fact, FactType, registre narratif
│   └── …
├── formats/             # Layer 2 — parsing/serialization (ALTO 4, PAGE XML, JSON)
├── evaluation/          # Layer 3 — métriques et calcul
│   ├── metrics/         # ~37 métriques (CER/WER, MUFI, philological, NER, …)
│   ├── statistics/      # Wilcoxon, Friedman/Nemenyi, bootstrap, Pareto
│   ├── views/, projectors/  # EvaluationView, projecteurs Alto/Page/CanonicalToText
│   ├── corpus.py        # Document, Corpus, GTLevel
│   └── benchmark_result.py # BenchmarkResult, EngineReport, DocumentResult
├── pipeline/            # Layer 4 — PipelineExecutor canonique (instance-based)
├── adapters/            # Layer 5 — adapters externes (libs externes autorisées)
│   ├── ocr/             # Tesseract, Pero, Mistral OCR, Google Vision, Azure DI, Precomputed
│   ├── llm/             # OpenAI, Anthropic, Mistral, Ollama
│   ├── vlm/             # Adapters VLM (zero-shot)
│   ├── corpus/          # IIIF, Gallica, HTR-United, HuggingFace, eScriptorium
│   └── storage/         # ArtifactStore, JobStore
├── app/                 # Layer 6 — services applicatifs (BenchmarkService, RunOrchestrator, JobRunner, benchmark_runner)
├── reports/             # Layer 7 — rendu HTML / JSON / CSV (22 renderers + 5 vues)
└── interfaces/          # Layer 8 — CLI Click, Web FastAPI
```

Règle d'import stricte : les flèches d'import vont uniquement
de l'extérieur vers l'intérieur (de bas en haut dans le diagramme).
Vérifié par `tests/architecture/test_layer_dependencies.py`.

## Guides d'extension

- [Étendre le moteur narratif](narrative-engine.md) — ajouter un type
  de fait, ses templates, l'enregistrer dans le registre.
- [Étendre le glossaire](extending-glossary.md) — documenter une
  nouvelle métrique, l'attacher à une colonne.
- [Étendre l'i18n](extending-i18n.md) — ajouter une nouvelle langue
  ou une clé d'interface.

## Invariants à respecter

1. **Pas de LLM dans le chemin critique** du rapport. La synthèse
   factuelle est rendue par des templates `str.format_map`. Tout LLM
   au moment de la génération est à proscrire (reproductibilité,
   coût, dépendance externe).
2. **Pas de prescription dans l'interface**. Le glossaire est factuel
   (« utilisé historiquement pour X »), pas prescriptif (« à choisir
   si vous êtes Y »). Le panneau de personnalisation a un warning
   explicite sur l'absence de pondération universelle.
3. **Toute valeur numérique remontée dans la synthèse doit être
   traçable au JSON d'entrée**. Le test
   `test_every_number_in_synthesis_is_traceable` vérifie ce contrat.
4. **Symétrie FR/EN** garantie par les tests. Toute nouvelle clé
   d'interface ou entrée de glossaire doit exister dans les deux
   langues.
5. **Déterminisme du rapport** : deux générations sur les mêmes
   données produisent le même HTML (octet à octet pour la synthèse).
   Aucun timestamp, ID aléatoire ou ordre non-trié dans le HTML
   généré.

## Lancer la suite de tests

```bash
pip install -e ".[dev,web]"
pytest tests/ -q --tb=short
```

À la date du Sprint 21 : **1244 tests passent, 2 sont skip** (dépendance
scipy optionnelle). Toute contribution doit conserver le statut "0
failed".

## Démo rapide

```bash
picarones demo --output /tmp/demo.html --docs 8
```

Génère un rapport sur des données fictives. Utile pour vérifier visuellement
qu'un nouveau composant s'intègre proprement.