Picarones / CLAUDE.md
Claude
feat(migration): Phase 0 du retrait legacy — foundation
71f166b unverified
|
Raw
History Blame
11.7 kB

CLAUDE.md — Picarones

Plateforme de benchmark OCR/HTR pour documents patrimoniaux. Repo : github.com/maribakulj/Picarones HuggingFace Space : huggingface.co/spaces/Ma-Ri-Ba-Ku/Picarones (Docker, port 7860)


Architecture — coexistence legacy + rewrite

Voir le manifeste complet dans docs/explanation/architecture.md.

Le projet a deux arborescences qui cohabitent par design depuis le rewrite ciblé S27-S46 (cf. docs/migration/rewrite-status-s46.md) :

Arbo cible (post-rewrite) — chemin canonique pour tout nouveau code :

domain → formats → evaluation → pipeline → adapters → app → reports_v2 → interfaces

Règle d'import stricte : les dépendances vont uniquement de l'extérieur vers l'intérieur. Vérifié par tests/architecture/test_layer_dependencies.py.

Arbo legacy (pré-rewrite)picarones/{cli,web,engines,llm, pipelines,report,measurements,extras,modules,core}/ reste exécutable le temps que les callers externes (HuggingFace Space, scripts BnF) migrent. Ne pas y ajouter de nouveau code. Calendrier de retrait documenté dans le CHANGELOG.


Setup

pip install -e ".[dev,web]"          # toujours inclure [web] pour les tests
pytest tests/ -q --tb=short          # lancer les tests
picarones demo --output rapport.html # rapport démo sans moteur installé
picarones serve --port 8080          # interface web locale

Structure

picarones/
├── core/                       Cercle 1 — abstractions pures (7 modules)
│   ├── modules.py              BaseModule, ArtifactType
│   ├── corpus.py               Document, Corpus, GTLevel, payloads typés
│   ├── results.py              DocumentResult, EngineReport, BenchmarkResult
│   ├── metric_registry.py      MetricSpec, register_metric, compute_at_junction
│   ├── metric_hooks.py         register_document_metric, register_corpus_aggregator
│   ├── pipeline.py             PipelineRunner, PipelineSpec, PipelineStep
│   └── facts.py                Fact, FactType, FactImportance, DetectorRegistry
│
├── measurements/               Cercle 2 — métriques officielles (~55 modules)
│   ├── runner.py               run_benchmark (orchestration)
│   ├── statistics/             sous-package (Wilcoxon, Friedman/Nemenyi, bootstrap, Pareto, clustering, corrélation, distributions, CDD)
│   ├── metrics.py / normalization.py / builtin_hooks.py
│   ├── confusion.py / taxonomy.py / calibration.py / line_metrics.py / ...
│   ├── readability.py / reliability.py / searchability.py / ner.py / ...
│   ├── mufi.py / abbreviations.py / unicode_blocks.py / roman_numerals.py
│   ├── pipeline_benchmark.py / pipeline_comparison.py / pipeline_spec_loader.py
│   └── narrative/              moteur narratif (arbiter, renderer, registry,
│                                18 détecteurs en 6 familles : ranking, pareto,
│                                stratum, quality, history, ensemble)
│
├── engines/                    Cercle 2 — adapters OCR (5)
│   ├── base.py                 BaseOCREngine (hérite de BaseModule)
│   ├── tesseract.py / pero_ocr.py
│   ├── mistral_ocr.py / google_vision.py / azure_doc_intel.py
│
├── llm/                        Cercle 2 — adapters LLM (4)
│   ├── base.py / mistral_adapter.py / openai_adapter.py
│   └── anthropic_adapter.py / ollama_adapter.py
│
├── pipelines/                  Cercle 2 — pipelines OCR+LLM intégrés
│   ├── base.py (OCRLLMPipeline) / over_normalization.py
│
├── modules/                    Cercle 2 — modules BaseModule officiels
│   └── alto_text_to_mono_region.py
│
├── extras/                     Cercle 3 — plugins / extensions
│   └── importers/              IIIF, Gallica, HTR-United, HuggingFace, eScriptorium
│
├── report/                     Cercle 3 — rendu HTML
│   ├── generator.py / colors.py / diff_utils.py
│   ├── views/                  5 vues thématiques
│   ├── templates/ / i18n/ / glossary/ / vendor/
│   └── *_render.py             ~22 renderers (calibration, NER, Pareto, etc.)
│
├── cli/                        Cercle 3 — Click (7 fichiers)
├── web/                        Cercle 3 — FastAPI (app.py, jobs.py)
├── prompts/                    8 fichiers .txt FR+EN
├── data/                       Tables indicatives (pricing.yaml)
└── fixtures.py                 Corpus de test fictifs

État des tests et bugs historiques

pytest tests/5050 passed, 12 skipped, 8 deselected, 0 failed (post-S59). Les deselected sont les markers live (5 tests d'intégration contre vraie API/binaire) + network (3 tests qui hit le réseau réel), opt-in en local via pytest -m live ou pytest -m network. Le compteur en prose est synchronisé automatiquement par scripts/gen_readme_tables.py — toute modification manuelle sera ré-écrasée au prochain make lint.

Bugs documentés antérieurement — tous résolus

Bug Statut Sprint de résolution
Pipeline OCR+LLM sortie vide (tesseract → ministral-3b-latest) ✅ Résolu Sprint 15 — adapter Mistral logue finish_reason, completion_tokens, normalise les ContentChunk
CI python-multipart manquant ✅ Résolu pyproject.toml expose python-multipart>=0.0.9 dans les extras dev ET web; ci.yml:71 installe .[dev,web]
Tests fixtures post-Sprint 10 (counts moteurs, flag is_pipeline) ✅ Résolu Fixtures mises à jour
Test Windows SQLite test_history_empty_db ✅ Résolu try/except OSError + gc.collect() avant unlink
Test HuggingFace test_search_language_filter ✅ Résolu Assertion corrigée

En cas de régression sur un de ces bugs, chercher les fichiers de test correspondants (test_sprint15_llm_pipeline_bugs.py, test_sprint8_escriptorium_gallica.py, test_sprint6_web_interface.py) avant de ré-ouvrir une enquête.


Règles importantes — ne pas toucher

  • Ne jamais retirer python-multipart des dépendances : FastAPI vérifie sa présence à l'import du module (décoration @app.post avec UploadFile), pas à l'exécution. Ça casse tous les tests web au setup.
  • Ne jamais mettre except Exception: pass : remplacer par logger.warning("[module] fonctionnalité dégradée : %s", e).
  • Toujours utiliser logger.warning avec message explicite quand une fonctionnalité optionnelle échoue (confusion, taxonomy, structure, image_quality, etc.).
  • Avant tout push, lancer make lint (ou ruff check picarones/ tests/). La config est centralisée dans pyproject.toml sous [tool.ruff], donc CI, Makefile et invocation directe produisent le même résultat. Le job lint du CI est bloquant — un F401 (import inutilisé) ou un E741 (variable ambiguë) fait échouer la PR, par design.
  • Les profils de normalisation sont dans picarones/measurements/normalization.py — l'endpoint /api/normalization/profiles doit les lire dynamiquement depuis ce fichier, pas depuis une liste statique.

Variables d'environnement

# Clés API LLM (configurées dans HuggingFace Space Settings → Variables and secrets)
MISTRAL_API_KEY=...
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...

# OCR cloud (optionnel)
GOOGLE_APPLICATION_CREDENTIALS=/path/to/creds.json
AZURE_DOC_INTEL_ENDPOINT=https://...
AZURE_DOC_INTEL_KEY=...

Pipelines OCR+LLM — modes

Mode Description
zero_shot Le LLM reçoit l'image directement et transcrit sans OCR préalable (VLM)
post_correction_texte OCR → texte brut → LLM corrige le texte (modèles texte seul)
post_correction_image_texte OCR → LLM reçoit image + texte brut pour correction (VLM)

ministral-3b-latest = modèle texte pur → utiliser mode post_correction_texte uniquement.


CI/CD

  • CI GitHub Actions : .github/workflows/ci.yml — Python 3.11/3.12, Linux/macOS/Windows
  • Sync HuggingFace : .github/workflows/sync_to_huggingface.yml — push auto sur main (nécessite secret HF_TOKEN dans GitHub Settings → Secrets → Actions)
  • HuggingFace Space : Docker sur port 7860

Sprints réalisés

L'historique détaillé des 97+ sprints du projet (de la fondation S1 jusqu'au rewrite ciblé S27-S46 puis l'audit institutionnel S47-S59) est dans le CHANGELOG.md à la racine. Cette page, auparavant pléthorique, ne le duplique plus — un seul endroit où chercher.

Pour le travail courant, ce qui compte :

  • Phase active : audit institutionnel post-S57 vers la release 1.3.0 (cf. section [Unreleased] du CHANGELOG).
  • Documents de référence : docs/migration/rewrite-status-s46.md (état du rewrite), docs/audits/ (audits historiques figés), docs/roadmap/evolution-2026.md (plan stratégique).

Moteur narratif

Le modèle de données (Fact, FactType, FactImportance, DetectorRegistry) vit en cercle 1 dans picarones/core/facts.py. Les détecteurs et le rendu vivent en cercle 2 :

picarones/measurements/narrative/
├── __init__.py              API publique + pipeline build_synthesis
├── arbiter.py               Tri par importance, non-redondance, anti-contradiction
├── renderer.py              Rendu templates YAML par str.format_map (déterministe)
├── registry.py              Registre par défaut des détecteurs
├── templates/{fr,en}.yaml   18 templates × 2 langues
└── detectors/               18 détecteurs en 6 familles
    ├── ranking.py           5 (global_leader, statistical_tie, significant_gap,
    │                          speed_winner, median_mean_gap_warning)
    ├── pareto.py            2 (pareto_alternative, cost_outlier)
    ├── stratum.py           3 (stratum_winner, stratum_collapse,
    │                          stratification_recommended)
    ├── quality.py           4 (error_profile_outlier, llm_hallucination_flag,
    │                          robustness_fragile, confidence_warning)
    ├── history.py           3 (engine_off_baseline, engine_unstable,
    │                          regression_in_history)
    └── ensemble.py          1 (ensemble_opportunity)

Principe anti-hallucination : chaque valeur numérique ou nom d'entité dans le payload d'un Fact provient du JSON d'entrée. Le test test_sprint19_narrative_engine.py parse la synthèse rendue et vérifie la traçabilité.

Règle anti-contradiction (arbitre) : si SIGNIFICANT_GAP (Wilcoxon non corrigé) et STATISTICAL_TIE (Nemenyi corrigé) concernent les mêmes moteurs, Nemenyi l'emporte.

Pipeline : build_synthesis(benchmark_data, lang, max_facts=5) détecte, arbitre, rend.


Contexte développement