Ce document explique comment le backend est structuré et comment les pièces communiquent, puis donne les commandes de configuration et d’exploitation.
| Service | Rôle | Exposé |
|---|---|---|
backend (fastapi) |
API HTTP : auth, upload EPUB, lecture des résultats. Distribue également le frontend. | 8000 |
worker (worker-taskiq) |
Consomme la file Redis et exécute le traitement EPUB → IA → DB. | — (interne) |
| postgres | Base de données relationnelle. | 5432 |
| redis | Double rôle : file de tâches taskiq + stockage de l’état/progression de chaque tâche (task_id). |
6379 |
| model-blip / model-florence / model-git | 3 services d’inférence IA, chacun expose POST /describe. |
8000 interne |
| lgtm | Stack d’observabilité (Loki, Grafana, Tempo, Mimir) recevant l’OTLP. | 3001 (Grafana) |
Trois fichiers compose coexistent :
docker-compose.yml(local),docker-compose.dev.ymletdocker-compose.prod.yml(images pré-construites depuis GHCR).
Upload — POST /api/epub/upload-epub (epub/controller.py)
.epub, taille ≤ 100 Mo, magic bytes PK\x03\x04, non-doublon.UPLOAD_TEMP_DIR, partagé via le volume epub_shared).task_id (UUID) → état initial stocké dans Redis.Task + Epub en PostgreSQL.process_epub_describe.kiq(...).{ "task_id": "..." }.Traitement — worker/worker.py : process_epub_describe
Task passe à in_progress.extract_images_epub extrait les images de l’EPUB (dossier temporaire).save_images insère les lignes Images en DB ; les images sont encodées en base64.stream_image_describe envoie les images aux 3 modèles en parallèle, par batch, et yield chaque résultat dès qu’il revient (un sémaphore par modèle plafonne la concurrence).DescriptionByIA) et l’état Redis est mis à jour → progression en temps réel.Task → completed, état final écrit dans Redis, dossier temporaire nettoyé.retry_on_error (3 essais) ; au démarrage du worker, recover_stuck_tasks reprend les tâches restées in_progress.Suivi & résultats
GET /api/task/{task_id} / GET /api/description/{task_id} : le frontend interroge l’état (servi depuis Redis / DB).POST /api/description/{task_id}/validate : un humain valide une description → DescriptionFinale.core/database/config.py)SQLAlchemy async (asyncpg), migrations via Alembic.
User ─┬─< Task ─┬─< Epub ─┬─< Images ─┬─< DescriptionByIA >─ ModelsIA
│ │ │ └─< DescriptionFinale >─ ModelsIA
└─< RefreshToken └────────────── (Images relié à Task et Epub)
user/admin.task_id_redis, status, total_images, processed_images).Task.image_file_name, image_position_in_epub).Les réglages sont centralisés dans core/settings.py (Pydantic Settings). Le fichier .env chargé est déterminé par APP_ENV.
⚠️ Deux mécanismes distincts dans compose, à ne pas confondre :
${VAR} (interpolation) : résolu par Compose au parsing, en lisant le .env du dossier (ou --env-file). Sert p. ex. au healthcheck pg_isready -U ${POSTGRES_USER}.env_file: / environment: : injecté dans le conteneur au runtime.Variables clés : SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES, REFRESH_TOKEN_EXPIRE_DAYS, POSTGRES_{HOST,USER,PASSWORD,DB,SSL}, REDIS_{HOST,PORT,URL}, UPLOAD_TEMP_DIR, URL_SALESFORCE_CPU_LARGE / URL_FLORANCE_2_LARGE / URL_GIT_LARGE, BATCH_SIZE, BATCH_MAX, DEBUG.
🩺 Piège connu : si
POSTGRES_USER/POSTGRES_PASSWORDsont vides dans le.env, le healthcheck devientpg_isready -U -d→ conteneur unhealthy →backend/workerrefusent de démarrer (dependency failed to start). Les identifiants Postgres ne sont par ailleurs lus qu’à la première initialisation du volumepostgres_data.
cd backend
alembic upgrade head # appliquer les migrations
alembic current # état actuel
alembic revision --autogenerate -m "description" # nouvelle migration après modif d'un modèle
alembic downgrade -1 # annuler la dernière
cd backend/ && fastapi dev
# ou
uvicorn backend.api.api:app --reload --log-level debug
docker exec -it desc-image-ia-redis-1 redis-cli
http://127.0.0.1:8000/docs
Root — GET / · GET /health
Authentification — POST /api/auth/register · POST /api/auth/admin/register · POST /api/auth/login · GET /api/auth/users/me · GET /api/auth/users/me/tasks · POST /api/auth/refresh · POST /api/auth/logout
Upload EPUB — POST /api/epub/upload-epub · GET /api/epub/download-epub/{file_name}
Descriptions — GET /api/description/{task_id} · POST /api/description/{task_id}/validate · POST /api/description/add_descriptions
Tâches — GET /api/task/admin · GET /api/task/{task_id}
pytest -m unit /path/file_or_folder
pytest -m integration /path/file_or_folder
pytest -m e2e /path/file_or_folder
Avec couverture :
pytest -m unit --cov=. --cov-report=term-missing --cov-config=.coveragerc
pytest -m integration --cov=. --cov-report=term-missing --cov-config=.coveragerc
pytest -m e2e --cov=. --cov-report=term-missing --cov-config=.coveragerc