Spaces:
Build error
Build error
Claude commited on
feat(sprint5-session-a): Dockerisation + configuration HuggingFace Spaces
Browse files- infra/Dockerfile : image python:3.11-slim, WORKDIR /app, PYTHONPATH=/app/backend,
port 7860, workers=1, data/ en volume, secrets en variables d'env (R06)
- Dockerfile (racine) : copie identique requise par HF Spaces SDK docker
- infra/docker-compose.yml : dev local, build context=repo root, volume ../data
- README.md : YAML front matter HF + docs développeur (lancer, tester, profils, providers)
- .huggingface/README.md : config Space HF (secrets, stockage Datasets, endpoints)
Convention HF Spaces : Dockerfile obligatoire à la racine → double fichier.
Structure image : /app/backend/app/ + /app/profiles/ + /app/prompts/ + /app/data/ (volume).
https://claude.ai/code/session_018woyEHc8HG2th7V4ewJ4Kg
- .huggingface/README.md +40 -0
- Dockerfile +47 -0
- README.md +110 -2
- infra/Dockerfile +49 -0
- infra/docker-compose.yml +25 -0
.huggingface/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Scriptorium AI
|
| 3 |
+
emoji: 📜
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: gold
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## Configuration HuggingFace Spaces
|
| 12 |
+
|
| 13 |
+
Ce Space utilise le SDK Docker. L'image est construite depuis le `Dockerfile`
|
| 14 |
+
à la racine du dépôt au moment du push.
|
| 15 |
+
|
| 16 |
+
### Secrets à configurer
|
| 17 |
+
|
| 18 |
+
Dans **Settings → Repository secrets**, renseigner selon le provider choisi :
|
| 19 |
+
|
| 20 |
+
| Secret | Description |
|
| 21 |
+
|--------|-------------|
|
| 22 |
+
| `AI_PROVIDER` | `google_ai_studio` \| `google_ai_api` \| `google_vertex` |
|
| 23 |
+
| `GOOGLE_AI_STUDIO_API_KEY` | Clé API Google AI Studio (si `AI_PROVIDER=google_ai_studio`) |
|
| 24 |
+
| `GOOGLE_AI_API_KEY` | Clé API Google AI (si `AI_PROVIDER=google_ai_api`) |
|
| 25 |
+
| `GOOGLE_VERTEX_PROJECT` | ID du projet GCP (si `AI_PROVIDER=google_vertex`) |
|
| 26 |
+
| `GOOGLE_VERTEX_LOCATION` | Région Vertex (défaut : `us-central1`) |
|
| 27 |
+
|
| 28 |
+
### Stockage des artefacts
|
| 29 |
+
|
| 30 |
+
Les images, JSON maîtres et exports XML sont stockés sur un **HuggingFace Dataset**
|
| 31 |
+
associé (pas dans l'image Docker). Le volume `/app/data` doit être monté via
|
| 32 |
+
le Dataset persistant du Space ou un Dataset dédié.
|
| 33 |
+
|
| 34 |
+
### Endpoints de vérification
|
| 35 |
+
|
| 36 |
+
```
|
| 37 |
+
GET /api/v1/profiles → liste les 4 profils de corpus disponibles
|
| 38 |
+
GET /docs → documentation Swagger interactive
|
| 39 |
+
GET /api/v1/corpora → liste des corpus ingérés
|
| 40 |
+
```
|
Dockerfile
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Scriptorium AI — image de production
|
| 2 |
+
# Ce fichier est la copie exacte de infra/Dockerfile.
|
| 3 |
+
# Il est requis à la racine du dépôt pour HuggingFace Spaces (SDK docker).
|
| 4 |
+
#
|
| 5 |
+
# Build depuis la racine du dépôt :
|
| 6 |
+
# docker build -t scriptorium-ai .
|
| 7 |
+
#
|
| 8 |
+
# Structure attendue dans l'image :
|
| 9 |
+
# /app/backend/app/ ← source Python (importable via PYTHONPATH)
|
| 10 |
+
# /app/profiles/ ← profils JSON
|
| 11 |
+
# /app/prompts/ ← templates de prompts
|
| 12 |
+
# /app/data/ ← créé vide ; à monter en volume pour les artefacts
|
| 13 |
+
|
| 14 |
+
FROM python:3.11-slim
|
| 15 |
+
|
| 16 |
+
WORKDIR /app
|
| 17 |
+
|
| 18 |
+
# ── Dépendances Python ─────────────────────────────────────────────────────
|
| 19 |
+
# On copie uniquement pyproject.toml pour exploiter le cache de layers Docker.
|
| 20 |
+
# Un stub app/__init__.py satisfait setuptools (discover packages) sans avoir
|
| 21 |
+
# besoin de copier tout le code source à ce stade.
|
| 22 |
+
COPY backend/pyproject.toml /tmp/build/
|
| 23 |
+
RUN mkdir -p /tmp/build/app \
|
| 24 |
+
&& touch /tmp/build/app/__init__.py \
|
| 25 |
+
&& pip install --no-cache-dir /tmp/build/ \
|
| 26 |
+
&& rm -rf /tmp/build
|
| 27 |
+
|
| 28 |
+
# ── Code source ────────────────────────────────────────────────────────────
|
| 29 |
+
COPY backend/app ./backend/app
|
| 30 |
+
COPY profiles/ ./profiles/
|
| 31 |
+
COPY prompts/ ./prompts/
|
| 32 |
+
|
| 33 |
+
# ── Répertoire des artefacts (vide dans l'image ; monté en volume) ─────────
|
| 34 |
+
RUN mkdir -p /app/data
|
| 35 |
+
|
| 36 |
+
# ── Secrets Google AI : JAMAIS dans l'image (R06) ─────────────────────────
|
| 37 |
+
# Passer au runtime via -e ou les Secrets HuggingFace Spaces :
|
| 38 |
+
# AI_PROVIDER, GOOGLE_AI_STUDIO_API_KEY, GOOGLE_AI_API_KEY,
|
| 39 |
+
# GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION
|
| 40 |
+
|
| 41 |
+
# PYTHONPATH permet l'import `app.main:app` depuis /app/backend/app/
|
| 42 |
+
ENV PYTHONPATH=/app/backend
|
| 43 |
+
|
| 44 |
+
EXPOSE 7860
|
| 45 |
+
|
| 46 |
+
# 1 worker au MVP — pas de Gunicorn, pas de multiprocessing
|
| 47 |
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
|
README.md
CHANGED
|
@@ -1,2 +1,110 @@
|
|
| 1 |
-
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Scriptorium AI
|
| 3 |
+
emoji: 📜
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: gold
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Scriptorium AI
|
| 12 |
+
|
| 13 |
+
Plateforme générique de génération d'éditions savantes augmentées pour documents
|
| 14 |
+
patrimoniaux numérisés : manuscrits médiévaux, incunables, cartulaires, archives,
|
| 15 |
+
chartes, papyri — tout type de document, toute époque, toute langue.
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
## Structure du dépôt
|
| 20 |
+
|
| 21 |
+
```
|
| 22 |
+
scriptorium-ai/
|
| 23 |
+
├── backend/ # API FastAPI + pipeline Python
|
| 24 |
+
│ ├── app/
|
| 25 |
+
│ │ ├── api/v1/ # endpoints REST (/api/v1/...)
|
| 26 |
+
│ │ ├── models/ # tables SQLAlchemy (SQLite async)
|
| 27 |
+
│ │ ├── schemas/ # modèles Pydantic v2
|
| 28 |
+
│ │ └── services/ # ingest / image / ai / export / search
|
| 29 |
+
│ ├── tests/ # suite pytest (477 tests)
|
| 30 |
+
│ └── pyproject.toml
|
| 31 |
+
├── profiles/ # 4 profils de corpus JSON
|
| 32 |
+
├── prompts/ # templates de prompts par profil
|
| 33 |
+
├── infra/ # Dockerfile + docker-compose (dev local)
|
| 34 |
+
├── Dockerfile # copie du Dockerfile pour HuggingFace Spaces
|
| 35 |
+
└── data/ # artefacts runtime — NON versionné
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
## Lancer en local (Docker)
|
| 41 |
+
|
| 42 |
+
```bash
|
| 43 |
+
# 1. Cloner le dépôt
|
| 44 |
+
git clone https://github.com/<org>/scriptorium-ai && cd scriptorium-ai
|
| 45 |
+
|
| 46 |
+
# 2. Définir les variables d'environnement
|
| 47 |
+
cp .env.example .env # puis renseigner les clés dans .env
|
| 48 |
+
|
| 49 |
+
# 3. Démarrer le service
|
| 50 |
+
docker compose -f infra/docker-compose.yml up --build
|
| 51 |
+
|
| 52 |
+
# 4. Vérifier
|
| 53 |
+
curl http://localhost:7860/api/v1/profiles
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
L'API est accessible sur `http://localhost:7860`. La documentation interactive
|
| 57 |
+
Swagger est disponible sur `http://localhost:7860/docs`.
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
## Lancer les tests
|
| 62 |
+
|
| 63 |
+
```bash
|
| 64 |
+
cd backend
|
| 65 |
+
pip install -e ".[dev]"
|
| 66 |
+
pytest tests/ -v --cov=app
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
Résultat attendu : **477 passed, 3 skipped**.
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## Profils disponibles
|
| 74 |
+
|
| 75 |
+
| Profil | Description |
|
| 76 |
+
|--------|-------------|
|
| 77 |
+
| `medieval-illuminated` | Manuscrits médiévaux enluminés (OCR diplomatique, iconographie, commentaire) |
|
| 78 |
+
| `medieval-textual` | Manuscrits médiévaux textuels (OCR, traduction, commentaire savant) |
|
| 79 |
+
| `early-modern-print` | Imprimés anciens (incunables, livres des XVIe–XVIIIe siècles) |
|
| 80 |
+
| `modern-handwritten` | Documents manuscrits modernes (cursive, archives, chartes) |
|
| 81 |
+
|
| 82 |
+
```bash
|
| 83 |
+
# Lister les profils via l'API
|
| 84 |
+
curl http://localhost:7860/api/v1/profiles
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
---
|
| 88 |
+
|
| 89 |
+
## Providers Google AI
|
| 90 |
+
|
| 91 |
+
Trois modes d'authentification sont supportés. Sélectionner via `AI_PROVIDER`.
|
| 92 |
+
|
| 93 |
+
| Provider | Variable `AI_PROVIDER` | Variables d'environnement requises |
|
| 94 |
+
|----------|------------------------|-------------------------------------|
|
| 95 |
+
| Google AI Studio (clé API) | `google_ai_studio` | `GOOGLE_AI_STUDIO_API_KEY` |
|
| 96 |
+
| Google AI API (legacy) | `google_ai_api` | `GOOGLE_AI_API_KEY` |
|
| 97 |
+
| Google Vertex AI | `google_vertex` | `GOOGLE_VERTEX_PROJECT`, `GOOGLE_VERTEX_LOCATION` |
|
| 98 |
+
|
| 99 |
+
Les clés ne doivent **jamais** figurer dans le code, les commits ou l'image Docker.
|
| 100 |
+
Sur HuggingFace Spaces, les renseigner dans **Settings → Repository secrets**.
|
| 101 |
+
|
| 102 |
+
---
|
| 103 |
+
|
| 104 |
+
## Déploiement HuggingFace Spaces
|
| 105 |
+
|
| 106 |
+
Ce dépôt est configuré pour HuggingFace Spaces (SDK Docker, port 7860).
|
| 107 |
+
Les artefacts de traitement (images, JSON maîtres, exports XML) sont stockés
|
| 108 |
+
sur HuggingFace Datasets — pas dans l'image Docker.
|
| 109 |
+
|
| 110 |
+
Voir `.huggingface/README.md` pour la configuration spécifique du Space.
|
infra/Dockerfile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Scriptorium AI — image de production
|
| 2 |
+
# Build depuis la racine du dépôt :
|
| 3 |
+
# docker build -f infra/Dockerfile -t scriptorium-ai .
|
| 4 |
+
#
|
| 5 |
+
# Structure attendue dans l'image :
|
| 6 |
+
# /app/backend/app/ ← source Python (importable via PYTHONPATH)
|
| 7 |
+
# /app/profiles/ ← profils JSON
|
| 8 |
+
# /app/prompts/ ← templates de prompts
|
| 9 |
+
# /app/data/ ← créé vide ; à monter en volume pour les artefacts
|
| 10 |
+
|
| 11 |
+
FROM python:3.11-slim
|
| 12 |
+
|
| 13 |
+
WORKDIR /app
|
| 14 |
+
|
| 15 |
+
# ── Dépendances système (lxml utilise des wheels binaires pré-compilés ;
|
| 16 |
+
# aucun outil de build requis sur cette image) ─────────────────────────────
|
| 17 |
+
# Aucun paquet système supplémentaire nécessaire.
|
| 18 |
+
|
| 19 |
+
# ── Dépendances Python ─────────────────────────────────────────────────────
|
| 20 |
+
# On copie uniquement pyproject.toml pour exploiter le cache de layers Docker.
|
| 21 |
+
# Un stub app/__init__.py satisfait setuptools (discover packages) sans avoir
|
| 22 |
+
# besoin de copier tout le code source à ce stade.
|
| 23 |
+
COPY backend/pyproject.toml /tmp/build/
|
| 24 |
+
RUN mkdir -p /tmp/build/app \
|
| 25 |
+
&& touch /tmp/build/app/__init__.py \
|
| 26 |
+
&& pip install --no-cache-dir /tmp/build/ \
|
| 27 |
+
&& rm -rf /tmp/build
|
| 28 |
+
|
| 29 |
+
# ── Code source ────────────────────────────────────────────────────────────
|
| 30 |
+
# Copié APRÈS l'installation des dépendances pour conserver le cache.
|
| 31 |
+
COPY backend/app ./backend/app
|
| 32 |
+
COPY profiles/ ./profiles/
|
| 33 |
+
COPY prompts/ ./prompts/
|
| 34 |
+
|
| 35 |
+
# ── Répertoire des artefacts (vide dans l'image ; monté en volume) ─────────
|
| 36 |
+
RUN mkdir -p /app/data
|
| 37 |
+
|
| 38 |
+
# ── Secrets Google AI : JAMAIS dans l'image (R06) ─────────────────────────
|
| 39 |
+
# Passer au runtime via -e ou docker-compose environment :
|
| 40 |
+
# AI_PROVIDER, GOOGLE_AI_STUDIO_API_KEY, GOOGLE_AI_API_KEY,
|
| 41 |
+
# GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION
|
| 42 |
+
|
| 43 |
+
# PYTHONPATH permet l'import `app.main:app` depuis /app/backend/app/
|
| 44 |
+
ENV PYTHONPATH=/app/backend
|
| 45 |
+
|
| 46 |
+
EXPOSE 7860
|
| 47 |
+
|
| 48 |
+
# 1 worker au MVP — pas de Gunicorn, pas de multiprocessing
|
| 49 |
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
|
infra/docker-compose.yml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# docker-compose pour développement local UNIQUEMENT.
|
| 2 |
+
# Lancer depuis la racine du dépôt :
|
| 3 |
+
# docker compose -f infra/docker-compose.yml up --build
|
| 4 |
+
#
|
| 5 |
+
# Les secrets ne doivent jamais figurer dans ce fichier (R06).
|
| 6 |
+
# Copier .env.example → .env et y renseigner les clés.
|
| 7 |
+
|
| 8 |
+
services:
|
| 9 |
+
api:
|
| 10 |
+
build:
|
| 11 |
+
context: .. # racine du dépôt = contexte de build
|
| 12 |
+
dockerfile: infra/Dockerfile
|
| 13 |
+
ports:
|
| 14 |
+
- "7860:7860"
|
| 15 |
+
volumes:
|
| 16 |
+
- ../data:/app/data # artefacts montés en volume, hors image
|
| 17 |
+
environment:
|
| 18 |
+
# Provider IA : google_ai_studio | google_vertex | google_ai_api
|
| 19 |
+
- AI_PROVIDER=${AI_PROVIDER:-google_ai_studio}
|
| 20 |
+
# Clés selon le provider choisi — à définir dans .env
|
| 21 |
+
- GOOGLE_AI_STUDIO_API_KEY=${GOOGLE_AI_STUDIO_API_KEY:-}
|
| 22 |
+
- GOOGLE_AI_API_KEY=${GOOGLE_AI_API_KEY:-}
|
| 23 |
+
- GOOGLE_VERTEX_PROJECT=${GOOGLE_VERTEX_PROJECT:-}
|
| 24 |
+
- GOOGLE_VERTEX_LOCATION=${GOOGLE_VERTEX_LOCATION:-us-central1}
|
| 25 |
+
restart: unless-stopped
|