Files
Imago/docs/API_GUIDE.md
T
bruno ae072dba26
CI / Lint & Format (push) Failing after 8s
CI / Tests (push) Has been skipped
CI / Security Scan (push) Failing after 9s
CI / Docker Build (push) Has been skipped
Update official docs: API guide v2.0, architecture with new components
2026-06-22 20:34:10 -04:00

7.3 KiB

Guide d'utilisation de l'API Imago

Bienvenue dans la documentation officielle de l'API REST d'Imago v2.0.0. Note : Tous les endpoints sont servis sous le préfixe /api/v1/.

Sommaire


Authentification

Tous les endpoints (sauf /health, /, /metrics) nécessitent une clé API.

Authorization: Bearer VOTRE_CLE_API

Ou via le header alternatif : X-API-Key: VOTRE_CLE_API

La clé API est hashée en SHA-256 + pepper (SECRET_KEY) avant stockage. Les comparaisons sont timing-safe.

Clé Master Admin

Définie par ADMIN_API_KEY dans .env. Cette clé spéciale a tous les droits sans être en base de données.


Scopes (Permissions)

Scope Accès
images:read Lister, voir détails, EXIF, OCR, AI, tags
images:write Uploader, relancer le pipeline
images:delete Supprimer des images
ai:use Résumé d'URL, rédaction de tâches
admin Gérer clients, voir stats, DLQ, docs

Les scopes sont validés à la création du client — les valeurs invalides sont rejetées.


Plans et Rate Limiting

Les limites sont dynamiques par plan et isolées par client. Support Redis pour la persistence.

Plan Uploads/h AI req/h
free 20 50
standard 100 200
premium 500 1000

Config : `RATE_LIMIT_STORAGE_URL=redis://redis:***@## Gestion des Clients (Admin)

# Créer un client
curl -X POST http://localhost:8000/api/v1/auth/clients \
  -H "Authorization: Bearer *** \
  -H "Content-Type: application/json" \
  -d '{"name":"App Mobile","scopes":["images:read","images:write","ai:use"],"plan":"standard"}'

# Rotation de clé
curl -X POST http://localhost:8000/api/v1/auth/clients/{id}/rotate-key \
  -H "Authorization: Bearer ***

La clé API n'est affichée qu'une seule fois à la création. Stockez-la immédiatement.


Multi-tenancy et Isolation

  • Chaque client voit uniquement ses propres images (filtrage WHERE client_id = X)
  • Les IDs sont globaux mais l'accès est vérifié → un client B qui tente l'ID du client A reçoit 404
  • Fichiers stockés dans uploads/{client_id}/ et thumbnails/{client_id}/

Reference des Endpoints

Gestion des Images

Méthode Endpoint Scope Description
POST /api/v1/images/upload images:write Upload (multipart) + lancement pipeline AI
GET /api/v1/images images:read Lister (pagination, filtres tag/status/search)
GET /api/v1/images/{id} images:read Détail complet (EXIF + OCR + AI)
GET /api/v1/images/{id}/status images:read Statut du pipeline (pending→done/error)
GET /api/v1/images/{id}/exif images:read Métadonnées EXIF + GPS
GET /api/v1/images/{id}/ocr images:read Texte extrait par OCR
GET /api/v1/images/{id}/ai images:read Description AI + tags + tokens consommés
POST /api/v1/images/{id}/reprocess images:write Relancer le pipeline AI
DELETE /api/v1/images/{id} images:delete Supprimer image + fichiers
GET /api/v1/images/{id}/download-url images:read URL signée temporaire (fichier original)
GET /api/v1/images/{id}/thumbnail-url images:read URL signée temporaire (thumbnail)
GET /api/v1/images/tags/all images:read Tous les tags uniques du client

Recherche : GET /api/v1/images?search=motcle&tag=nature&status=done&page=1&page_size=20

Intelligence Artificielle

Méthode Endpoint Scope Description
POST /api/v1/ai/summarize ai:use Résumé AI d'une URL (scraping + résumé + tags)
POST /api/v1/ai/draft-task ai:use Génération de tâche structurée

L'AI utilise le provider configuré (Gemini ou OpenRouter) avec circuit breaker : timeout configurable (AI_REQUEST_TIMEOUT) et retry exponentiel (AI_MAX_RETRIES).

Administration (Admin)

Méthode Endpoint Description
GET /admin/api/stats Stats globales (images, stockage, tokens, clients)
GET /admin/api/clients Liste des clients
POST /admin/api/clients/{id}/toggle Activer/désactiver un client
POST /admin/api/clients/{id}/reset-quota Remettre le quota à zéro
GET /admin/api/queue/status File d'attente ARQ (pending + dead jobs)
GET /admin/api/docs Liste des documents disponibles
GET /admin/api/docs/{filename} Contenu d'un document
POST /api/v1/auth/clients Créer un client (retourne la clé)
GET /api/v1/auth/clients Lister tous les clients
PATCH /api/v1/auth/clients/{id} Modifier un client
DELETE /api/v1/auth/clients/{id} Désactiver un client

Dead Letter Queue (Admin)

Jobs échoués après PIPELINE_MAX_RETRIES tentatives.

Méthode Endpoint Description
GET /admin/api/queue/dead?limit=50 Lister les jobs morts
POST /admin/api/queue/dead/{index}/retry Relancer un job mort
DELETE /admin/api/queue/dead Vider la DLQ

Santé et Status

Endpoints publics (pas d'authentification).

Méthode Endpoint Description
GET / Version et statut
GET /health Santé (AI, OCR, provider)
GET /health/detailed Diagnostic complet (BDD, Redis, ARQ, MinIO, OCR, AI, worker)
GET /metrics Métriques Prometheus

WebSocket (Temps Réel)

Endpoint Auth Description
ws://host/ws/pipeline/{image_id}?token=API_KEY API Key Événements live du pipeline + buffer 60s
ws://host/ws/admin/monitor?token=ADMIN_KEY Admin Monitoring global de tous les pipelines

Exemples Rapides

Upload + suivi pipeline (Python)

import httpx, asyncio, websockets, json

API = "http://localhost:8000"
KEY = "ma_cle_api"
headers = {"Authorization": f"Bearer {KEY}"}

async def main():
    # Upload
    files = {"file": open("photo.jpg", "rb")}
    r = httpx.post(f"{API}/api/v1/images/upload", files=files, headers=headers)
    img = r.json()
    print(f"Uploaded: {img['id']}")

    # Suivi WebSocket du pipeline
    async with websockets.connect(
        f"ws://localhost:8000/ws/pipeline/{img['id']}?token={KEY}"
    ) as ws:
        async for msg in ws:
            event = json.loads(msg)
            print(f"Pipeline: {event['event']}")
            if event["event"] in ("pipeline.done", "pipeline.error"):
                break

    # Résultat final
    detail = httpx.get(f"{API}/api/v1/images/{img['id']}/ai", headers=headers).json()
    print(f"Description: {detail['description']}")
    print(f"Tags: {detail['tags']}")

asyncio.run(main())