Claude commited on
Commit
cecde1f
·
unverified ·
1 Parent(s): 1c939df

chore: remplacer toutes les références bnf/picarones par maribakulj/Picarones

Browse files

- pyproject.toml : auteur → maribakulj, toutes les URLs du projet
- README.md, INSTALL.md, Dockerfile, CHANGELOG.md, SPECS.md : URLs GitHub et mentions institution
- importers (gallica, iiif, htr_united, huggingface, escriptorium) : User-Agent, institution, données d'exemple
- fixtures.py, cli.py, history.py : corpus/institution dans données de démo
- tests : noms de projets et institutions dans les jeux de données de test

Les URLs externes réelles (gallica.bnf.fr) et la terminologie technique (SRU) sont conservées.

https://claude.ai/code/session_017gXea9mxBQqDTAsSQd7aAq

CHANGELOG.md CHANGED
@@ -38,7 +38,7 @@ La numérotation de version suit [Semantic Versioning](https://semver.org/lang/f
38
  - `export_benchmark_as_layer()` : export des résultats benchmark comme couche OCR nommée dans eScriptorium
39
  - `connect_escriptorium()` : connexion avec validation automatique
40
  - **Gallica API** (`picarones/importers/gallica.py`)
41
- - `GallicaClient` : recherche SRU BnF par cote/titre/auteur/date/langue/type
42
  - Récupération OCR Gallica texte brut (`f{n}.texteBrut`)
43
  - Import IIIF Gallica avec enrichissement OCR comme vérité terrain de référence
44
  - Métadonnées OAI-PMH (`/services/OAIRecord`)
 
38
  - `export_benchmark_as_layer()` : export des résultats benchmark comme couche OCR nommée dans eScriptorium
39
  - `connect_escriptorium()` : connexion avec validation automatique
40
  - **Gallica API** (`picarones/importers/gallica.py`)
41
+ - `GallicaClient` : recherche SRU par cote/titre/auteur/date/langue/type
42
  - Récupération OCR Gallica texte brut (`f{n}.texteBrut`)
43
  - Import IIIF Gallica avec enrichissement OCR comme vérité terrain de référence
44
  - Métadonnées OAI-PMH (`/services/OAIRecord`)
Dockerfile CHANGED
@@ -44,7 +44,7 @@ FROM python:3.11-slim AS runtime
44
 
45
  LABEL description="Picarones — Plateforme de comparaison de moteurs OCR pour documents patrimoniaux"
46
  LABEL version="1.0.0"
47
- LABEL org.opencontainers.image.source="https://github.com/bnf/picarones"
48
  LABEL org.opencontainers.image.licenses="Apache-2.0"
49
 
50
  WORKDIR /app
 
44
 
45
  LABEL description="Picarones — Plateforme de comparaison de moteurs OCR pour documents patrimoniaux"
46
  LABEL version="1.0.0"
47
+ LABEL org.opencontainers.image.source="https://github.com/maribakulj/Picarones"
48
  LABEL org.opencontainers.image.licenses="Apache-2.0"
49
 
50
  WORKDIR /app
INSTALL.md CHANGED
@@ -67,7 +67,7 @@ tesseract --list-langs
67
  ### 2.3 Picarones
68
 
69
  ```bash
70
- git clone https://github.com/bnf/picarones.git
71
  cd picarones
72
 
73
  # Créer un environnement virtuel (recommandé)
@@ -121,7 +121,7 @@ brew install tesseract-lang # Installe tous les modèles
121
  ### 3.3 Picarones
122
 
123
  ```bash
124
- git clone https://github.com/bnf/picarones.git
125
  cd picarones
126
 
127
  python3.11 -m venv .venv
@@ -176,7 +176,7 @@ Télécharger depuis [git-scm.com](https://git-scm.com/download/win) et installe
176
  ### 4.4 Picarones
177
 
178
  ```powershell
179
- git clone https://github.com/bnf/picarones.git
180
  cd picarones
181
 
182
  python -m venv .venv
 
67
  ### 2.3 Picarones
68
 
69
  ```bash
70
+ git clone https://github.com/maribakulj/Picarones.git
71
  cd picarones
72
 
73
  # Créer un environnement virtuel (recommandé)
 
121
  ### 3.3 Picarones
122
 
123
  ```bash
124
+ git clone https://github.com/maribakulj/Picarones.git
125
  cd picarones
126
 
127
  python3.11 -m venv .venv
 
176
  ### 4.4 Picarones
177
 
178
  ```powershell
179
+ git clone https://github.com/maribakulj/Picarones.git
180
  cd picarones
181
 
182
  python -m venv .venv
README.md CHANGED
@@ -12,7 +12,7 @@ pinned: false
12
  > **Plateforme de comparaison de moteurs OCR/HTR pour documents patrimoniaux**
13
  Apache 2.0
14
 
15
- [![CI](https://github.com/bnf/picarones/actions/workflows/ci.yml/badge.svg)](https://github.com/bnf/picarones/actions/workflows/ci.yml)
16
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
17
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
18
 
@@ -67,7 +67,7 @@ documents historiques (manuscrits, imprimés anciens, archives).
67
  |--------|----------|
68
  | Dossier local | `picarones run --corpus ./corpus/` |
69
  | IIIF (Gallica, Bodleian, BL…) | `picarones import iiif <url>` |
70
- | Gallica (API BnF + OCR) | `GallicaClient` / `picarones import iiif` |
71
  | HuggingFace Datasets | `picarones import hf <dataset>` |
72
  | HTR-United | `picarones import htr-united` |
73
  | eScriptorium | `EScriptoriumClient` |
@@ -96,7 +96,7 @@ documents historiques (manuscrits, imprimés anciens, archives).
96
 
97
  ```bash
98
  # Cloner et installer
99
- git clone https://github.com/bnf/picarones.git
100
  cd picarones
101
  pip install -e .
102
 
 
12
  > **Plateforme de comparaison de moteurs OCR/HTR pour documents patrimoniaux**
13
  Apache 2.0
14
 
15
+ [![CI](https://github.com/maribakulj/Picarones/actions/workflows/ci.yml/badge.svg)](https://github.com/maribakulj/Picarones/actions/workflows/ci.yml)
16
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
17
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
18
 
 
67
  |--------|----------|
68
  | Dossier local | `picarones run --corpus ./corpus/` |
69
  | IIIF (Gallica, Bodleian, BL…) | `picarones import iiif <url>` |
70
+ | Gallica (API SRU + OCR) | `GallicaClient` / `picarones import iiif` |
71
  | HuggingFace Datasets | `picarones import hf <dataset>` |
72
  | HTR-United | `picarones import htr-united` |
73
  | eScriptorium | `EScriptoriumClient` |
 
96
 
97
  ```bash
98
  # Cloner et installer
99
+ git clone https://github.com/maribakulj/Picarones.git
100
  cd picarones
101
  pip install -e .
102
 
SPECS.md CHANGED
@@ -621,7 +621,7 @@ Risque spécifique aux pipelines OCR+LLM : le LLM "corrige" à tort des graphies
621
  | **Sprint 6** | 1-2 sem. | Interface web FastAPI, import HTR-United / HuggingFace, profils de normalisation, Ollama (LLMs locaux) |
622
  | **Sprint 7** | 1-2 sem. | Rapport HTML v2 : vue Caractères, scatter plots, heatmaps, clustering |
623
  | **Sprint 8** | 2 sem. | Intégration eScriptorium et Gallica API, suivi longitudinal, analyse de robustesse, prompts bibliothèque |
624
- | **Sprint 9+** | Continu | Tests utilisateurs BnF, documentation, packaging Docker, CI/CD, publication open-source |
625
 
626
  ---
627
 
 
621
  | **Sprint 6** | 1-2 sem. | Interface web FastAPI, import HTR-United / HuggingFace, profils de normalisation, Ollama (LLMs locaux) |
622
  | **Sprint 7** | 1-2 sem. | Rapport HTML v2 : vue Caractères, scatter plots, heatmaps, clustering |
623
  | **Sprint 8** | 2 sem. | Intégration eScriptorium et Gallica API, suivi longitudinal, analyse de robustesse, prompts bibliothèque |
624
+ | **Sprint 9+** | Continu | Tests utilisateurs, documentation, packaging Docker, CI/CD, publication open-source |
625
 
626
  ---
627
 
picarones/cli.py CHANGED
@@ -709,7 +709,7 @@ def history_cmd(
709
  \b
710
  Exemples :
711
  picarones history
712
- picarones history --engine tesseract --corpus "Chroniques BnF"
713
  picarones history --regression --regression-threshold 0.02
714
  picarones history --demo # données fictives de démonstration
715
  picarones history --export-json historique.json
 
709
  \b
710
  Exemples :
711
  picarones history
712
+ picarones history --engine tesseract --corpus "Chroniques médiévales"
713
  picarones history --regression --regression-threshold 0.02
714
  picarones history --demo # données fictives de démonstration
715
  picarones history --export-json historique.json
picarones/core/history.py CHANGED
@@ -565,7 +565,7 @@ def generate_demo_history(
565
  rng = random.Random(seed)
566
 
567
  engines = ["tesseract", "pero_ocr", "ancien_moteur"]
568
- corpus = "Chroniques médiévales BnF"
569
 
570
  # Trajectoires de CER simulées (amélioration progressive + bruit)
571
  base_cers = {
 
565
  rng = random.Random(seed)
566
 
567
  engines = ["tesseract", "pero_ocr", "ancien_moteur"]
568
+ corpus = "Chroniques médiévales"
569
 
570
  # Trajectoires de CER simulées (amélioration progressive + bruit)
571
  base_cers = {
picarones/fixtures.py CHANGED
@@ -30,7 +30,7 @@ from picarones.core.line_metrics import compute_line_metrics, aggregate_line_met
30
  from picarones.core.hallucination import compute_hallucination_metrics, aggregate_hallucination_metrics
31
 
32
  # ---------------------------------------------------------------------------
33
- # Textes GT réalistes (documents patrimoniaux BnF)
34
  # ---------------------------------------------------------------------------
35
 
36
  _GT_TEXTS = [
@@ -137,7 +137,7 @@ def _vlm_hallucinations(text: str, rng: random.Random) -> str:
137
  "Ledit document fut enregistré au greffe le lendemain.",
138
  "Signé et paraphé par le notaire royal en présence de témoins.",
139
  "Archives nationales, cote F/7/1234, pièce n° 42.",
140
- "Transcription réalisée d'après l'original conservé à la BnF.",
141
  "Le présent acte a été lu et approuvé par toutes les parties.",
142
  "En foi de quoi nous avons apposé notre sceau et notre signature.",
143
  "Registre des délibérations du Parlement de Paris, tome III.",
@@ -493,7 +493,7 @@ def generate_sample_benchmark(
493
  engine_reports.append(report)
494
 
495
  bm = BenchmarkResult(
496
- corpus_name="Corpus de test — Chroniques médiévales BnF",
497
  corpus_source="/corpus/chroniques/",
498
  document_count=n_docs,
499
  engine_reports=engine_reports,
@@ -501,7 +501,7 @@ def generate_sample_benchmark(
501
  "description": "Données de démonstration générées par picarones.fixtures",
502
  "script": "gothique textura",
503
  "langue": "Français médiéval (XIVe-XVe siècle)",
504
- "institution": "BnF — Département des manuscrits",
505
  },
506
  )
507
 
 
30
  from picarones.core.hallucination import compute_hallucination_metrics, aggregate_hallucination_metrics
31
 
32
  # ---------------------------------------------------------------------------
33
+ # Textes GT réalistes (documents patrimoniaux)
34
  # ---------------------------------------------------------------------------
35
 
36
  _GT_TEXTS = [
 
137
  "Ledit document fut enregistré au greffe le lendemain.",
138
  "Signé et paraphé par le notaire royal en présence de témoins.",
139
  "Archives nationales, cote F/7/1234, pièce n° 42.",
140
+ "Transcription réalisée d'après l'original conservé aux archives.",
141
  "Le présent acte a été lu et approuvé par toutes les parties.",
142
  "En foi de quoi nous avons apposé notre sceau et notre signature.",
143
  "Registre des délibérations du Parlement de Paris, tome III.",
 
493
  engine_reports.append(report)
494
 
495
  bm = BenchmarkResult(
496
+ corpus_name="Corpus de test — Chroniques médiévales",
497
  corpus_source="/corpus/chroniques/",
498
  document_count=n_docs,
499
  engine_reports=engine_reports,
 
501
  "description": "Données de démonstration générées par picarones.fixtures",
502
  "script": "gothique textura",
503
  "langue": "Français médiéval (XIVe-XVe siècle)",
504
+ "institution": "Département des manuscrits",
505
  },
506
  )
507
 
picarones/importers/escriptorium.py CHANGED
@@ -102,7 +102,7 @@ class EScriptoriumClient:
102
  Parameters
103
  ----------
104
  base_url:
105
- URL racine de l'instance (ex : ``"https://escriptorium.bnf.fr"``).
106
  token:
107
  Token d'authentification API (depuis Settings > API dans eScriptorium).
108
  timeout:
 
102
  Parameters
103
  ----------
104
  base_url:
105
+ URL racine de l'instance (ex : ``"https://escriptorium.example.org"``).
106
  token:
107
  Token d'authentification API (depuis Settings > API dans eScriptorium).
108
  timeout:
picarones/importers/gallica.py CHANGED
@@ -128,7 +128,7 @@ class GallicaClient:
128
  """Télécharge le contenu d'une URL."""
129
  req = urllib.request.Request(
130
  url,
131
- headers={"User-Agent": "Picarones/1.0 (BnF; research tool)"},
132
  )
133
  try:
134
  with urllib.request.urlopen(req, timeout=self.timeout) as resp:
 
128
  """Télécharge le contenu d'une URL."""
129
  req = urllib.request.Request(
130
  url,
131
+ headers={"User-Agent": "Picarones/1.0 (research tool)"},
132
  )
133
  try:
134
  with urllib.request.urlopen(req, timeout=self.timeout) as resp:
picarones/importers/htr_united.py CHANGED
@@ -62,7 +62,7 @@ _DEMO_CATALOGUE: list[dict] = [
62
  "language": ["Latin", "French"],
63
  "script": ["Gothic"],
64
  "century": [13, 14, 15],
65
- "institution": "IRHT / BnF",
66
  "description": "Manuscrits médiévaux latins et français, XIIIe-XVe siècles.",
67
  "license": "CC-BY 4.0",
68
  "lines": 8700,
@@ -104,7 +104,7 @@ _DEMO_CATALOGUE: list[dict] = [
104
  "language": ["French"],
105
  "script": ["Roman"],
106
  "century": [19],
107
- "institution": "BnF",
108
  "description": "Numérisations de journaux du XIXe siècle (Gallica).",
109
  "license": "etalab-2.0",
110
  "lines": 31000,
 
62
  "language": ["Latin", "French"],
63
  "script": ["Gothic"],
64
  "century": [13, 14, 15],
65
+ "institution": "IRHT",
66
  "description": "Manuscrits médiévaux latins et français, XIIIe-XVe siècles.",
67
  "license": "CC-BY 4.0",
68
  "lines": 8700,
 
104
  "language": ["French"],
105
  "script": ["Roman"],
106
  "century": [19],
107
+ "institution": "Gallica",
108
  "description": "Numérisations de journaux du XIXe siècle (Gallica).",
109
  "license": "etalab-2.0",
110
  "lines": 31000,
picarones/importers/huggingface.py CHANGED
@@ -106,14 +106,14 @@ _REFERENCE_DATASETS: list[dict] = [
106
  },
107
  {
108
  "dataset_id": "bnf-gallica/gallica-ocr",
109
- "title": "Gallica OCR — BnF",
110
  "description": "Extraits d'imprimés anciens numérisés depuis Gallica avec vérité terrain.",
111
  "language": ["French", "Latin"],
112
- "tags": ["ocr", "historical", "printed", "gallica", "bnf", "french"],
113
  "license": "etalab-2.0",
114
  "size_category": "10K<n<100K",
115
  "task": "image-to-text",
116
- "institution": "Bibliothèque nationale de France",
117
  "downloads": 2800,
118
  },
119
  {
 
106
  },
107
  {
108
  "dataset_id": "bnf-gallica/gallica-ocr",
109
+ "title": "Gallica OCR",
110
  "description": "Extraits d'imprimés anciens numérisés depuis Gallica avec vérité terrain.",
111
  "language": ["French", "Latin"],
112
+ "tags": ["ocr", "historical", "printed", "gallica", "french"],
113
  "license": "etalab-2.0",
114
  "size_category": "10K<n<100K",
115
  "task": "image-to-text",
116
+ "institution": "Gallica",
117
  "downloads": 2800,
118
  },
119
  {
picarones/importers/iiif.py CHANGED
@@ -315,7 +315,7 @@ def _download_url(
315
  ) -> bytes:
316
  """Télécharge une URL avec retry exponentiel."""
317
  headers = {
318
- "User-Agent": "Picarones/1.0 (BnF OCR benchmark platform; https://github.com/bnf/picarones)"
319
  }
320
  last_exc: Optional[Exception] = None
321
  for attempt in range(retries):
 
315
  ) -> bytes:
316
  """Télécharge une URL avec retry exponentiel."""
317
  headers = {
318
+ "User-Agent": "Picarones/1.0 (OCR benchmark platform; https://github.com/maribakulj/Picarones)"
319
  }
320
  last_exc: Optional[Exception] = None
321
  for attempt in range(retries):
pyproject.toml CHANGED
@@ -9,7 +9,7 @@ description = "Plateforme de comparaison de moteurs OCR/HTR pour documents patri
9
  readme = "README.md"
10
  requires-python = ">=3.11"
11
  license = { text = "Apache-2.0" }
12
- authors = [{ name = "Bibliothèque nationale de France — Département numérique" }]
13
  keywords = ["ocr", "htr", "patrimoine", "benchmark", "cer", "wer", "gallica", "escriptorium", "iiif"]
14
  classifiers = [
15
  "Development Status :: 5 - Production/Stable",
@@ -36,11 +36,11 @@ dependencies = [
36
  ]
37
 
38
  [project.urls]
39
- Homepage = "https://github.com/bnf/picarones"
40
- Documentation = "https://github.com/bnf/picarones/blob/main/INSTALL.md"
41
- Repository = "https://github.com/bnf/picarones"
42
- Changelog = "https://github.com/bnf/picarones/blob/main/CHANGELOG.md"
43
- "Bug Tracker" = "https://github.com/bnf/picarones/issues"
44
 
45
  [project.optional-dependencies]
46
  # Développement et tests
 
9
  readme = "README.md"
10
  requires-python = ">=3.11"
11
  license = { text = "Apache-2.0" }
12
+ authors = [{ name = "maribakulj" }]
13
  keywords = ["ocr", "htr", "patrimoine", "benchmark", "cer", "wer", "gallica", "escriptorium", "iiif"]
14
  classifiers = [
15
  "Development Status :: 5 - Production/Stable",
 
36
  ]
37
 
38
  [project.urls]
39
+ Homepage = "https://github.com/maribakulj/Picarones"
40
+ Documentation = "https://github.com/maribakulj/Picarones/blob/main/INSTALL.md"
41
+ Repository = "https://github.com/maribakulj/Picarones"
42
+ Changelog = "https://github.com/maribakulj/Picarones/blob/main/CHANGELOG.md"
43
+ "Bug Tracker" = "https://github.com/maribakulj/Picarones/issues"
44
 
45
  [project.optional-dependencies]
46
  # Développement et tests
tests/test_sprint6_web_interface.py CHANGED
@@ -81,7 +81,7 @@ class TestHTRUnitedEntry:
81
  d = {
82
  "id": "test-corpus", "title": "Test Corpus", "url": "https://github.com/test/corpus",
83
  "language": ["French"], "script": ["Gothic"], "century": [14, 15],
84
- "institution": "BnF", "description": "Un corpus de test.", "license": "CC-BY 4.0",
85
  "lines": 5000, "format": "ALTO", "tags": ["test", "médiéval"],
86
  }
87
  e = HTRUnitedEntry.from_dict(d)
 
81
  d = {
82
  "id": "test-corpus", "title": "Test Corpus", "url": "https://github.com/test/corpus",
83
  "language": ["French"], "script": ["Gothic"], "century": [14, 15],
84
+ "institution": "Test Org", "description": "Un corpus de test.", "license": "CC-BY 4.0",
85
  "lines": 5000, "format": "ALTO", "tags": ["test", "médiéval"],
86
  }
87
  e = HTRUnitedEntry.from_dict(d)
tests/test_sprint8_escriptorium_gallica.py CHANGED
@@ -79,7 +79,7 @@ class TestEScriptoriumClient:
79
  from picarones.importers.escriptorium import EScriptoriumClient, EScriptoriumProject
80
  client = EScriptoriumClient("https://example.org", token="tok")
81
  mock_data = [
82
- {"pk": 1, "name": "Projet BnF", "slug": "projet-bnf",
83
  "owner": {"username": "user1"}, "documents_count": 5},
84
  ]
85
  with patch.object(client, "_paginate", return_value=mock_data):
@@ -87,7 +87,7 @@ class TestEScriptoriumClient:
87
  assert len(projects) == 1
88
  assert isinstance(projects[0], EScriptoriumProject)
89
  assert projects[0].pk == 1
90
- assert projects[0].name == "Projet BnF"
91
  assert projects[0].document_count == 5
92
 
93
  def test_list_documents_with_project_filter(self):
 
79
  from picarones.importers.escriptorium import EScriptoriumClient, EScriptoriumProject
80
  client = EScriptoriumClient("https://example.org", token="tok")
81
  mock_data = [
82
+ {"pk": 1, "name": "Projet Test", "slug": "projet-test",
83
  "owner": {"username": "user1"}, "documents_count": 5},
84
  ]
85
  with patch.object(client, "_paginate", return_value=mock_data):
 
87
  assert len(projects) == 1
88
  assert isinstance(projects[0], EScriptoriumProject)
89
  assert projects[0].pk == 1
90
+ assert projects[0].name == "Projet Test"
91
  assert projects[0].document_count == 5
92
 
93
  def test_list_documents_with_project_filter(self):
tests/test_sprint8_longitudinal_robustness.py CHANGED
@@ -43,7 +43,7 @@ class TestBenchmarkHistory:
43
  def test_record_single(self, db):
44
  db.record_single(
45
  run_id="run001",
46
- corpus_name="BnF Test",
47
  engine_name="tesseract",
48
  cer_mean=0.12,
49
  wer_mean=0.20,
 
43
  def test_record_single(self, db):
44
  db.record_single(
45
  run_id="run001",
46
+ corpus_name="Corpus Test",
47
  engine_name="tesseract",
48
  cer_mean=0.12,
49
  wer_mean=0.20,