Spaces:
Running
Running
File size: 12,210 Bytes
742bfa0 5c80f64 ebf47e1 ff1843c ebf47e1 ff1843c b64f8e3 ebf47e1 3fe82fb ebf47e1 ff1843c ebf47e1 ff1843c ebf47e1 ff1843c 3fe82fb ff1843c ebf47e1 ff1843c ebf47e1 ff1843c ebf47e1 ff1843c 3fe82fb ff1843c ebf47e1 ff1843c ebf47e1 | 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | ---
title: Clafoutis MVP
emoji: 📚
sdk: docker
app_port: 7860
short_description: Prototype federated portal for cultural heritage resources.
---
# Clafoutis
Portail universel de recherche IIIF avec lecture dans Mirador et connecteurs extensibles.
## Objectif
Cette application permet de :
- rechercher des objets patrimoniaux dans plusieurs institutions ;
- agréger et normaliser les résultats dans un format commun ;
- afficher une galerie homogène de résultats ;
- ouvrir directement les ressources dans Mirador à partir de leurs manifests IIIF ;
- comparer plusieurs objets dans le même viewer ;
- exposer les fonctions principales via une API REST ;
- prévoir une couche MCP sans duplication de logique métier.
## Vision produit
Le produit est structuré en trois couches :
1. **Découverte** : recherche fédérée multi-sources ;
2. **Lecture** : visualisation et comparaison dans Mirador ;
3. **Interopérabilité** : API interne normalisée et couche MCP optionnelle.
Principe fondamental :
> Mirador est la couche de lecture, jamais la couche de recherche.
## Périmètre MVP
Le MVP doit inclure :
- recherche fédérée sur un petit nombre de sources ;
- schéma de données normalisé ;
- galerie de résultats ;
- ouverture simple et multiple dans Mirador ;
- import manuel d’un manifest IIIF ou d’une URL de notice ;
- description des sources disponibles et de leurs capacités ;
- robustesse aux échecs partiels.
Le MVP n’inclut pas :
- compte utilisateur ;
- annotation persistante ;
- index mondial exhaustif ;
- moissonnage global du web patrimonial ;
- recherche OCR universelle.
## Stack technique
### Frontend
- React
- TypeScript
- Tailwind CSS
- TanStack Query
- Zustand ou Redux Toolkit
- Mirador
### Backend
- Python 3.11+
- FastAPI
- Pydantic
- httpx async
### Déploiement
- Docker
- Hugging Face Spaces
## Architecture du projet
```text
app/
frontend/
src/
components/
pages/
hooks/
store/
lib/
types/
backend/
app/
api/
services/
connectors/
models/
mcp/
utils/
config/
tests/
unit/
integration/
docs/
Dockerfile
docker-compose.yml
README.md
```
## Concepts importants
### Schéma normalisé
Toutes les sources externes sont transformées dans un schéma commun de type `NormalizedItem`.
Le schéma normalisé est le cœur du projet : l’interface ne doit pas dépendre directement des payloads bruts des institutions.
### Connecteurs
Chaque source est branchée via un connecteur indépendant.
Chaque connecteur doit implémenter une interface commune, par exemple :
- `search(query, filters, page, page_size)`
- `get_item(source_id)`
- `resolve_manifest(item_or_url)`
- `healthcheck()`
- `capabilities()`
### Succès partiel
Si une source échoue, les autres doivent quand même répondre.
Le moteur fédéré ne doit jamais échouer globalement à cause d’un seul connecteur.
## Fonctionnalités prévues
- recherche simple multi-sources ;
- filtres par institution, type, langue, période, disponibilité IIIF ;
- galerie homogène ;
- ouverture d’un résultat dans Mirador ;
- comparaison de plusieurs manifests ;
- import manuel d’URL ;
- page Sources avec capacités déclaratives ;
- couche MCP optionnelle.
## Endpoints backend prévus
- `GET /api/health`
- `GET /api/sources`
- `POST /api/search`
- `GET /api/item/{id}`
- `POST /api/resolve-manifest`
- `POST /api/import`
### Heuristiques MVP de `/api/import`
Le connecteur générique `manifest_by_url` applique des heuristiques minimales et explicites :
1. **Manifest direct** : l’URL est considérée comme manifest si son chemin contient `manifest`
(ou se termine par `manifest.json`).
2. **Notice -> manifest** : si l’URL ne ressemble pas à un manifest, le backend tente des suffixes
courants, dans cet ordre :
- `/manifest`
- `/manifest.json`
- `/iiif/manifest`
- `/iiif/manifest.json`
Ces heuristiques sont volontairement simples au MVP et seront enrichies par source aux lots
connecteurs réels.
### Sécurité MVP import URL (validation + SSRF basique)
`/api/import` applique une validation stricte avant résolution :
- schémas autorisés : `http`, `https` uniquement ;
- rejet explicite de `localhost`/hôtes locaux ;
- rejet des IP privées/loopback/link-local/réservées/unspecified ;
- rejet des hôtes DNS qui résolvent vers ces plages privées/locales.
Limite connue MVP : cette protection SSRF reste basique et devra être durcie (allowlist,
résolution DNS contrôlée, protections réseau infra) avant production.
## Outils MCP prévus
- `search_items`
- `get_item`
- `resolve_manifest`
- `open_in_mirador`
- `list_sources`
## Installation locale
### Prérequis
- Python 3.11+
- Node.js 20+ ou version définie dans le projet
- npm, pnpm ou yarn
- Docker (optionnel mais recommandé)
### Backend
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
uvicorn app.main:app --app-dir app/backend --reload
```
### Frontend
```bash
cd app/frontend
npm install --legacy-peer-deps
npm run dev
```
Par défaut, le frontend appelle `http://localhost:8000`.
Optionnel :
```bash
VITE_API_BASE_URL=http://localhost:8000 npm run dev
```
## Variables d’environnement
Créer un fichier `.env` à partir de `.env.example`.
Variables backend principales (préfixe `CLAFOUTIS_`) :
```env
CLAFOUTIS_DEBUG=false
CLAFOUTIS_APP_HOST=0.0.0.0
CLAFOUTIS_APP_PORT=7860
CLAFOUTIS_REQUEST_TIMEOUT_SECONDS=8
CLAFOUTIS_CORS_ALLOW_ORIGINS=["http://localhost:5173"]
CLAFOUTIS_SERVE_FRONTEND=true
CLAFOUTIS_FRONTEND_DIST_DIR=app/frontend/dist
CLAFOUTIS_GALLICA_USE_FIXTURES=true
CLAFOUTIS_BODLEIAN_USE_FIXTURES=true
CLAFOUTIS_EUROPEANA_USE_FIXTURES=true
CLAFOUTIS_EUROPEANA_API_KEY=
# Hugging Face Spaces: HF_TOKEN est aussi accepté en fallback pour Europeana
# (utile si votre secret Space est nommé HF_TOKEN).
CLAFOUTIS_ENABLE_CAPABILITY_PROBING=true
CLAFOUTIS_CAPABILITY_PROBE_USE_FIXTURES=true
CLAFOUTIS_CAPABILITY_PROBE_TIMEOUT_SECONDS=2
CLAFOUTIS_CAPABILITY_PROBE_CACHE_TTL_SECONDS=300
```
Pour le frontend en mode dev local (Vite séparé) :
```env
VITE_API_BASE_URL=http://localhost:8000
```
## Packaging Docker (lot démo Hugging Face Spaces)
Stratégie MVP :
- image **unique** ;
- build frontend React dans une étape Node ;
- copie des assets `dist` dans l’image runtime Python ;
- backend FastAPI sert API + assets frontend (SPA fallback) sur un **port unique** ;
- mode fixtures activable par variables d’environnement (par défaut recommandé pour démo).
### Build image
```bash
docker build -t clafoutis-mvp .
```
### Run local (démo)
```bash
docker run --rm -p 7860:7860 \
-e PORT=7860 \
-e CLAFOUTIS_GALLICA_USE_FIXTURES=true \
-e CLAFOUTIS_BODLEIAN_USE_FIXTURES=true \
-e CLAFOUTIS_EUROPEANA_USE_FIXTURES=true \
clafoutis-mvp
```
Puis ouvrir :
- UI : `http://localhost:7860`
- API health : `http://localhost:7860/api/health`
### Hugging Face Spaces (Docker)
1. Créer un Space de type **Docker**.
2. Pousser ce dépôt (avec `Dockerfile`) dans le Space.
3. Définir les variables du Space (Settings -> Variables), au minimum :
- `PORT=7860`
- `CLAFOUTIS_GALLICA_USE_FIXTURES=true`
- `CLAFOUTIS_BODLEIAN_USE_FIXTURES=true`
- `CLAFOUTIS_EUROPEANA_USE_FIXTURES=true`
4. Optionnel : ajouter `CLAFOUTIS_EUROPEANA_API_KEY` pour le mode live Europeana.
Le backend accepte aussi `HF_TOKEN` en fallback si votre secret Space porte ce nom.
Le point d’entrée est `scripts/start.sh`, qui démarre Uvicorn sur `HOST/PORT` compatibles Space Docker.
## Sources prévues pour le MVP
- Gallica / BnF
- Bodleian Digital
- Europeana
- connecteur générique `manifest-by-url`
## Connecteur Gallica (lot 5)
### Hypothèses de mapping `NormalizedItem`
- `source_item_id` : ARK extrait des identifiants Gallica (`ark:/...`) ;
- `id` global : `gallica:{source_item_id}` ;
- `title` : premier champ `dc:title` disponible ;
- `creators` : liste des `dc:creator` ;
- `date_display` : premier `dc:date` ;
- `object_type` : dérivé de `dc:type` via mapping simple (`manuscript`, `book`, `map`, `image`, `newspaper`, `other`) ;
- `record_url` : premier `dc:identifier` ;
- `manifest_url` : construit depuis l’ARK (`https://gallica.bnf.fr/iiif/{ark}/manifest.json`) ;
- `institution` : `Bibliothèque nationale de France`.
### Stratégie de résolution de manifest
1. si `item.manifest_url` est déjà présent, il est renvoyé ;
2. sinon, extraction d’un ARK depuis `record_url` (ou URL fournie) ;
3. construction déterministe de l’URL IIIF manifest Gallica.
### Robustesse / mode fallback
- Le connecteur tente un mode live SRU Gallica ;
- pour éviter de casser la suite en environnement instable, un mode fixtures est disponible (`CLAFOUTIS_GALLICA_USE_FIXTURES=true` au MVP, valeur par défaut) ;
- en cas d’échec live, le connecteur renvoie un succès dégradé avec données fixtures et `partial_failures` explicite.
### Limites connues (MVP)
- le parsing SRU est volontairement minimal et basé sur un sous-ensemble Dublin Core ;
- certains champs Gallica restent absents/incertains selon les notices ;
- la détection fine des types documentaires sera améliorée aux lots suivants.
## Connecteurs Bodleian et Europeana (lot 6)
### Bodleian — mapping `NormalizedItem`
- `source_item_id` : identifiant objet Bodleian ;
- `id` global : `bodleian:{source_item_id}` ;
- `title`, `creators`, `date_display` : extraits du payload source ou fixtures ;
- `record_url` : URL notice Bodleian (`/objects/{id}/`) ;
- `manifest_url` : prioritairement fourni, sinon construit via pattern
`https://iiif.bodleian.ox.ac.uk/iiif/manifest/{id}.json` ;
- `institution` : `Bodleian Libraries`.
### Europeana — mapping `NormalizedItem`
- `source_item_id` : `id` Europeana ;
- `id` global : `europeana:{source_item_id}` ;
- `title`, `creators`, `date_display` : extraits du payload source ou fixtures ;
- `record_url` : `guid` Europeana (ou URL item fixture) ;
- `manifest_url` :
- `edmIsShownBy` si manifest explicite ;
- sinon fallback pattern `https://iiif.europeana.eu/presentation/{item_path}/manifest` ;
- `institution` : `Europeana` ou institution partenaire fixture.
### Capacités et mode robustesse
- les deux connecteurs implémentent `search`, `get_item`, `resolve_manifest`, `capabilities`, `healthcheck` ;
- stratégie **fixture-first** activée par défaut au MVP (`CLAFOUTIS_BODLEIAN_USE_FIXTURES=true`, `CLAFOUTIS_EUROPEANA_USE_FIXTURES=true`) pour préserver la stabilité ;
- en mode live, les erreurs réseau/API retombent en mode dégradé avec `partial_failures` explicites ;
- Europeana live nécessite une clé API (`CLAFOUTIS_EUROPEANA_API_KEY`).
### Limites connues (MVP)
- endpoints live Bodleian/Europeana restent best-effort et peuvent évoluer ;
- mapping conservateur pour limiter les faux positifs ;
- enrichissement sémantique (types, droits, OCR, langue fine) prévu après lot 6.
## Principes de développement
- code modulaire ;
- typage strict ;
- séparation claire frontend / backend / connecteurs ;
- aucune duplication de logique métier entre REST et MCP ;
- Mirador utilisé uniquement comme couche de lecture ;
- tests unitaires minimum sur les connecteurs ;
- tests d’intégration minimum sur les endpoints critiques.
## Ordre de développement recommandé
1. socle backend ;
2. socle frontend ;
3. intégration Mirador minimale ;
4. import manuel ;
5. connecteurs réels ;
6. ranking, cache et robustesse ;
7. couche MCP ;
8. déploiement Docker / Hugging Face Spaces.
## État du projet
Statut actuel : en cours de développement.
## Priorité actuelle
- [ ] Backend socle
- [ ] Frontend socle
- [ ] Intégration Mirador
- [ ] Import manuel
- [ ] Connecteur Gallica
- [ ] Connecteurs Bodleian et Europeana
- [ ] MCP
- [ ] Docker / déploiement HF Spaces
## Documentation
Voir aussi :
- `AGENTS.md`
- `PLANS.md`
- `docs/specs.md`
## Contribution
Avant toute contribution :
- lire `AGENTS.md` ;
- respecter l’architecture du projet ;
- ne pas dupliquer la logique métier ;
- garder les connecteurs isolés ;
- documenter clairement tout nouveau module.
|