Bruno Charest cc99fea20a
Some checks failed
CI / Lint & Format (push) Has been cancelled
CI / Tests (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
Add comprehensive test suite for image processing and related services
- Implement tests for database generator to ensure proper session handling.
- Create tests for EXIF extraction and conversion functions.
- Add tests for image-related endpoints, ensuring proper data retrieval and isolation between clients.
- Develop tests for OCR functionality, including language detection and text extraction.
- Introduce tests for the image processing pipeline, covering success and failure scenarios.
- Validate rate limiting functionality and ensure independent counters for different clients.
- Implement scraper tests to verify HTML content fetching and error handling.
- Add unit tests for various services, including storage and filename generation.
- Establish worker entry point for ARQ to handle background image processing tasks.
2026-02-24 11:22:10 -05:00

Imago

Backend FastAPI pour la gestion d'images et fonctionnalités AI, conçu comme complément à l'interface Web-thème Shaarli-Pro et toute autre applications qui voudrait l'utiliser.


Fonctionnalités

Feature Description
📸 Upload d'images Stockage + thumbnails, isolés par client (multi-tenant)
🛡️ Sécurité Authentification par API Key + scopes granulaires + Rate Limiting
🔍 Extraction EXIF Appareil photo, GPS, ISO, ouverture, date de prise de vue
📝 OCR Extraction du texte visible dans l'image (Tesseract + fallback AI)
🤖 Vision AI Description naturelle + classification par tags (Gemini / OpenRouter)
🔗 Résumé URL Scraping d'une page web + résumé AI
Rédaction de tâches Génération structurée d'une tâche à partir d'une description
📋 File de tâches ARQ Pipeline persistant avec retry automatique (Redis)
📊 Métriques Prometheus Endpoint /metrics + custom counters/histograms
💾 Storage abstrait Local (HMAC signed URLs) ou S3/MinIO (presigned URLs)
📈 Quota tracking Suivi du stockage par client avec enforcement
🔧 Logging structuré JSON (production) / Console colorée (dev) via structlog

Stack technique

FastAPI + Uvicorn       — Framework web async
SQLAlchemy (async)      — ORM + SQLite/Postgres
ARQ + Redis             — File de tâches persistante
Pillow + piexif         — Traitement d'images + EXIF
pytesseract             — OCR (Tesseract)
Google GenAI SDK        — Vision AI (Gemini)
aioboto3                — Stockage S3/MinIO
structlog               — Logging structuré JSON
Prometheus              — Métriques et monitoring
slowapi                 — Rate limiting par client
ruff                    — Linting + formatting

Installation

Prérequis

  • Python 3.12+ (3.14 supporté)
  • Tesseract OCR installé sur le système
  • Redis (optionnel, pour ARQ worker)
# Ubuntu/Debian
sudo apt install tesseract-ocr tesseract-ocr-fra tesseract-ocr-eng

# macOS
brew install tesseract tesseract-lang

# Windows
scoop install main/tesseract

Setup

Note

Les fichiers requirements.txt appliquent automatiquement des versions compatibles Python 3.14 (notamment pour Pillow et Pydantic).

# 1. Cloner et installer
git clone <repo>
cd imago

# Production
pip install -r requirements.txt

# Développement (inclut linting, tests, pre-commit)
pip install -r requirements-dev.txt
pre-commit install

# 2. Configuration
cp .env.example .env
# Éditer .env — voir la section Configuration ci-dessous

# 3. Migrations
alembic upgrade head
# La migration crée un client "default" et affiche sa clé API une seule fois.

# 4. Démarrage
python run.py                # API sur http://localhost:8000
python worker.py             # Worker ARQ (requiert Redis)

Avec Docker

docker-compose up -d         # API + Redis + Worker

Commandes utiles (Makefile)

make help          # Affiche toutes les commandes
make install-dev   # Dépendances dev + pre-commit
make lint          # Ruff + Mypy
make format        # Auto-format du code
make test          # Tests rapides
make test-cov      # Tests + couverture HTML
make serve         # Serveur dev (reload)
make worker        # Worker ARQ
make docker-up     # Docker compose up
make clean         # Nettoyage __pycache__, .pytest_cache, etc.

Pipeline de traitement AI

Chaque image uploadée déclenche un pipeline via ARQ (Redis) :

Upload → Sauvegarde fichier + thumbnail → BDD (PENDING)
                     │
                     ▼  (ARQ Worker — persistant, avec retry)
        ┌────────────────────────────────────────┐
        │  Étape 1 — Extraction EXIF             │
        │  Étape 2 — OCR (Tesseract + AI)        │
        │  Étape 3 — Vision AI (Gemini)          │
        └────────────────────────────────────────┘
                     │
                     ▼
              BDD (DONE) + événements Redis pub/sub

Important

Isolation multi-tenant : fichiers et données sont compartimentés par client_id. Un client ne peut ni voir, ni modifier, ni supprimer les images d'un autre.

Chaque étape est indépendante : un échec partiel n'arrête pas le pipeline. Priority queues : les clients premium ont une file dédiée. Retry automatique avec backoff exponentiel. Dead-letter après max retries.


Endpoints API

Images (Auth requise)

Méthode URL Description Scope
POST /images/upload Uploader une image images:write
GET /images Lister (paginé, filtrable, quota info) images:read
GET /images/{id} Détail complet images:read
GET /images/{id}/status Statut du pipeline images:read
GET /images/{id}/exif Métadonnées EXIF images:read
GET /images/{id}/ocr Texte OCR extrait images:read
GET /images/{id}/ai Description + tags AI images:read
GET /images/{id}/download-url URL signée de téléchargement images:read
GET /images/{id}/thumbnail-url URL signée du thumbnail images:read
GET /images/tags/all Tous les tags du client images:read
POST /images/{id}/reprocess Relancer le pipeline images:write
DELETE /images/{id} Supprimer image images:delete

Intelligence Artificielle (Auth requise)

Méthode URL Description Scope
POST /ai/summarize Résumé AI d'une URL ai:use
POST /ai/draft-task Rédaction de tâche ai:use

Administration & Clients (Admin only)

Méthode URL Description Scope
POST /auth/clients Créer un client API admin
GET /auth/clients Lister les clients admin
GET /auth/clients/{id} Détail d'un client admin
PATCH /auth/clients/{id} Modifier client (plan, scopes) admin
POST /auth/clients/{id}/rotate-key Régénérer clé API admin
DELETE /auth/clients/{id} Soft delete (désactivation) admin

Fichiers signés

Méthode URL Description Auth
GET /files/signed/{token} Télécharger via URL signée Token HMAC

Observabilité & Santé

Méthode URL Description Auth
GET / Info application Non
GET /health Santé du service Non
GET /health/detailed Santé détaillée (DB, Redis, ARQ, OCR) Non
GET /metrics Métriques Prometheus Non
GET /docs Documentation Swagger Non

Exemples d'utilisation

Tip

Tous les appels (sauf /health et /metrics) nécessitent une clé API valide passée dans le header X-API-Key.

Upload d'une image

curl -X POST http://localhost:8000/images/upload \
  -H "X-API-Key: your_api_key" \
  -F "file=@photo.jpg"

Réponse :

{
  "id": 1,
  "uuid": "a1b2c3d4-...",
  "original_name": "photo.jpg",
  "status": "pending",
  "message": "Image uploadée — traitement AI en cours"
}

Polling du statut

curl http://localhost:8000/images/1/status -H "X-API-Key: your_api_key"
{
  "id": 1,
  "status": "done",
  "started_at": "2024-01-15T10:30:00",
  "done_at": "2024-01-15T10:30:08"
}

Détail complet

curl http://localhost:8000/images/1 -H "X-API-Key: your_api_key"
{
  "id": 1,
  "original_name": "photo.jpg",
  "processing_status": "done",
  "exif": {
    "camera": {
      "make": "Canon",
      "model": "EOS R5",
      "iso": 400,
      "aperture": "f/2.8",
      "shutter_speed": "1/250",
      "focal_length": "50mm",
      "taken_at": "2024-06-15T14:30:00"
    },
    "gps": {
      "latitude": 48.8566,
      "longitude": 2.3522,
      "has_gps": true,
      "maps_url": "https://maps.google.com/?q=48.8566,2.3522"
    }
  },
  "ocr": {
    "has_text": true,
    "text": "Café de Flore",
    "language": "fr",
    "confidence": 0.94
  },
  "ai": {
    "description": "Une terrasse de café parisien animée en fin d'après-midi. Les tables en osier sont disposées sur le trottoir boulevard Saint-Germain, avec une clientèle détendue profitant du soleil. L'enseigne emblématique du Café de Flore est visible en arrière-plan.",
    "tags": ["café", "paris", "terrasse", "france", "bistrot", "extérieur", "urbain"],
    "confidence": 0.97,
    "model_used": "gemini-1.5-pro"
  }
}

Résumé d'URL

curl -X POST http://localhost:8000/ai/summarize \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/article", "language": "français"}'

Rédaction de tâche

curl -X POST http://localhost:8000/ai/draft-task \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Mettre à jour la documentation technique du projet backend",
    "context": "Projet Imago, backend FastAPI"
  }'

Configuration

Variable Défaut Description
ADMIN_API_KEY Clé maîtresse pour gérer les clients API
JWT_SECRET_KEY Secret pour la signature des tokens
AI_PROVIDER gemini gemini ou openrouter
GEMINI_API_KEY Clé API Gemini
DATABASE_URL SQLite local URL de connexion (SQLite ou Postgres)
REDIS_URL redis://localhost:6379/0 URL Redis pour ARQ
STORAGE_BACKEND local local ou s3
S3_BUCKET Bucket S3/MinIO
S3_ENDPOINT_URL Endpoint S3 custom (MinIO/R2)
S3_ACCESS_KEY Clé d'accès S3
S3_SECRET_KEY Secret S3
SIGNED_URL_SECRET Secret HMAC pour URLs signées locales
MAX_UPLOAD_SIZE_MB 50 Taille max par upload
OCR_ENABLED true Activer/désactiver l'OCR
WORKER_MAX_JOBS 10 Concurrence du worker ARQ
WORKER_MAX_TRIES 3 Retries max avant dead-letter
DEBUG false Mode debug (console logging)

Tests

# Tests rapides
make test

# Tests avec couverture
make test-cov

# Directement
python -m pytest tests/ -v --cov=app

76 tests couvrant : auth, isolation multi-tenant, rate limiting, pipeline, EXIF, OCR, AI, stockage.


CI/CD

Le pipeline GitHub Actions (.github/workflows/ci.yml) exécute :

  1. Lint — ruff check + format + mypy
  2. Tests — pytest + couverture
  3. Sécurité — bandit via ruff (règles S)
  4. Docker — build + smoke test (branche main uniquement)

Structure du projet

imago/
├── app/
│   ├── main.py                  # FastAPI + lifespan + Prometheus
│   ├── config.py                # Settings Pydantic
│   ├── database.py              # Engine SQLAlchemy async
│   ├── logging_config.py        # structlog JSON/Console
│   ├── metrics.py               # Prometheus custom metrics
│   ├── models/
│   │   ├── image.py             # Modèle Image
│   │   └── client.py            # APIClient + quotas
│   ├── schemas/
│   │   ├── __init__.py          # Schémas images + quota
│   │   └── auth.py              # Schémas Auth/Clients
│   ├── routers/
│   │   ├── images.py            # CRUD images + signed URLs
│   │   ├── ai.py                # Endpoints AI
│   │   ├── auth.py              # Gestion clients
│   │   └── files.py             # Serving signed local files
│   ├── dependencies/
│   │   └── auth.py              # verify_api_key, require_scope
│   ├── middleware/
│   │   ├── rate_limit.py        # slowapi configuration
│   │   └── logging_middleware.py # HTTP request logger
│   ├── services/
│   │   ├── storage.py           # Sauvegarde isolée par client
│   │   ├── storage_backend.py   # ABC + Local/S3 backends
│   │   ├── pipeline.py          # Pipeline EXIF → OCR → AI
│   │   ├── ai_vision.py         # Gemini/OpenRouter
│   │   ├── exif_service.py      # Extraction EXIF
│   │   ├── ocr_service.py       # Tesseract OCR
│   │   └── scraper.py           # Scraping web
│   └── workers/
│       ├── redis_client.py      # Redis pool partagé
│       └── image_worker.py      # ARQ worker + retries
├── tests/                       # 76 tests
├── .github/workflows/ci.yml     # CI/CD pipeline
├── pyproject.toml               # ruff, mypy, coverage config
├── Makefile                     # Commandes utiles
├── docker-compose.yml           # API + Redis + Worker
├── Dockerfile
├── requirements.txt             # Production deps
├── requirements-dev.txt         # Dev deps (lint, test)
├── .pre-commit-config.yaml      # Pre-commit hooks
├── worker.py                    # ARQ worker entrypoint
└── .env.example
Description
Application de gestion d'images
Readme 212 KiB
Languages
Python 98.4%
Makefile 1.3%
Dockerfile 0.3%