Update official docs: API guide v2.0, architecture with new components
This commit is contained in:
+143
-188
@@ -1,245 +1,200 @@
|
||||
# Guide d'utilisation de l'API Imago
|
||||
|
||||
Bienvenue dans la documentation officielle de l'API REST d'Imago.
|
||||
**Note :** Tous les terminaux (endpoints) principaux présentés ici sont désormais servis sous le préfixe `/api/v1/` dans l'application locale.
|
||||
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](#-Authentification)
|
||||
- [🛡️ Scopes (Permissions)](#-scopes-permissions)
|
||||
- [📊 Plans et Rate Limiting](#-plans-et-rate-limiting)
|
||||
- [👥 Gestion des Clients (Admin uniquement)](#-gestion-des-clients-admin-uniquement)
|
||||
- [📁 Multi-tenancy et Isolation](#-multi-tenancy-et-isolation)
|
||||
- [📖 Référence des Endpoints](#-référence-des-endpoints)
|
||||
- [📸 Gestion des Images](#-gestion-des-images)
|
||||
- [🤖 Intelligence Artificielle](#-intelligence-artificielle)
|
||||
- [🔑 Administration (Admin uniquement)](#-administration-admin-uniquement)
|
||||
- [🏥 Santé et Status](#-santé-et-status)
|
||||
- [🚀 Exemples Rapides](#-exemples-rapides)
|
||||
## Sommaire
|
||||
- [Authentification](#-authentification)
|
||||
- [Scopes (Permissions)](#-scopes-permissions)
|
||||
- [Plans et Rate Limiting](#-plans-et-rate-limiting)
|
||||
- [Multi-tenancy et Isolation](#-multi-tenancy-et-isolation)
|
||||
- [Gestion des Clients (Admin)](#-gestion-des-clients-admin)
|
||||
- [Référence des Endpoints](#-reference-des-endpoints)
|
||||
- [Gestion des Images](#-gestion-des-images)
|
||||
- [Intelligence Artificielle](#-intelligence-artificielle)
|
||||
- [Administration](#-administration-admin)
|
||||
- [Dead Letter Queue](#-dead-letter-queue-admin)
|
||||
- [Santé et Status](#-sante-et-status)
|
||||
- [WebSocket (Temps Réel)](#-websocket-temps-reel)
|
||||
- [Exemples Rapides](#-exemples-rapides)
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Authentification
|
||||
## Authentification
|
||||
|
||||
Tous les endpoints (sauf `/health` et `/`) nécessitent une authentification via une **Clé API**.
|
||||
Tous les endpoints (sauf `/health`, `/`, `/metrics`) nécessitent une clé API.
|
||||
|
||||
### Header Authorization
|
||||
|
||||
Vous devez inclure votre clé dans le header `Authorization` de chaque requête :
|
||||
|
||||
```http
|
||||
Authorization: Bearer VOTRE_CLE_API_SECRET
|
||||
```
|
||||
Authorization: Bearer VOTRE_CLE_API
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Traitez votre clé API comme un mot de passe. Ne la partagez jamais et ne l'incluez pas dans du code client (frontend) accessible publiquement.
|
||||
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)
|
||||
## Scopes (Permissions)
|
||||
|
||||
L'accès aux fonctionnalités est contrôlé par des **scopes**. Chaque clé API est limitée à un ensemble de 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 |
|
||||
|
||||
| Scope | Description | Fonctions incluses |
|
||||
|-------|-------------|-------------------|
|
||||
| `images:read` | Lecture seule | Lister les images, voir les détails, EXIF, OCR, AI. |
|
||||
| `images:write` | Écriture | Uploader des images, relancer le pipeline de traitement. |
|
||||
| `images:delete`| Suppression | Supprimer définitivement des images. |
|
||||
| `ai:use` | Utilisation IA | Résumé d'URL, rédaction de tâches. |
|
||||
| `admin` | Administration | Gérer les clients API, voir les clés, modifier les plans. |
|
||||
Les scopes sont validés à la création du client — les valeurs invalides sont rejetées.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Plans et Rate Limiting
|
||||
## Plans et Rate Limiting
|
||||
|
||||
Le système applique des limites de requêtes (Rate Limits) basées sur le **Plan** de votre client. Les compteurs sont réinitialisés toutes les heures.
|
||||
Les limites sont dynamiques par plan et isolées par client. Support Redis pour la persistence.
|
||||
|
||||
| Plan | Uploads / heure | Requêtes AI / heure |
|
||||
|------|-----------------|---------------------|
|
||||
| Plan | Uploads/h | AI req/h |
|
||||
|---|---|---|
|
||||
| `free` | 20 | 50 |
|
||||
| `standard` | 100 | 200 |
|
||||
| `premium` | 500 | 1000 |
|
||||
|
||||
*Les requêtes de lecture (`GET`) ne sont pas limitées par défaut.*
|
||||
|
||||
---
|
||||
|
||||
## 👥 Gestion des Clients (Admin uniquement)
|
||||
|
||||
Si vous avez le scope `admin`, vous pouvez gérer les accès.
|
||||
|
||||
### Créer un nouveau client
|
||||
Config : `RATE_LIMIT_STORAGE_URL=redis://redis:***@## Gestion des Clients (Admin)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/auth/clients \
|
||||
-H "Authorization: Bearer CLE_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": "Application Mobile",
|
||||
"scopes": ["images:read", "images:write", "ai:use"],
|
||||
"plan": "standard"
|
||||
}'
|
||||
-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 ***
|
||||
```
|
||||
|
||||
**Réponse (Importante) :**
|
||||
```json
|
||||
{
|
||||
"id": "uuid-...",
|
||||
"api_key": "cle_generee_en_clair_une_seule_fois",
|
||||
"name": "Application Mobile",
|
||||
...
|
||||
}
|
||||
```
|
||||
> [!CAUTION]
|
||||
> La clé API n'est affichée **qu'une seule fois** à la création. Stockez-la immédiatement de manière sécurisée.
|
||||
|
||||
### Régénérer une clé (Rotation)
|
||||
|
||||
En cas de compromission, invalidez l'ancienne clé et générez-en une nouvelle :
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/auth/clients/{id}/rotate-key \
|
||||
-H "Authorization: Bearer CLE_ADMIN"
|
||||
```
|
||||
> La clé API n'est affichée qu'une seule fois à la création. Stockez-la immédiatement.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Multi-tenancy et Isolation
|
||||
## Multi-tenancy et Isolation
|
||||
|
||||
L'API est **multi-tenant**. Cela signifie que :
|
||||
- Vous ne voyez **que** les images uploadées avec votre clé.
|
||||
- Les IDs d'images sont globaux, mais si vous tentez d'accéder à l'ID d'un autre client, vous recevrez une erreur `404 Not Found`.
|
||||
- Vos fichiers physiques sont stockés dans un sous-répertoire dédié sur le serveur (`/data/uploads/{votre_client_id}/`).
|
||||
- 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}/`
|
||||
|
||||
---
|
||||
|
||||
## 📖 Référence des Endpoints
|
||||
## Reference des Endpoints
|
||||
|
||||
### 📸 Gestion des Images
|
||||
### Gestion des Images
|
||||
|
||||
#### Lister les images
|
||||
`GET /api/v1/images`
|
||||
- **Scope required** : `images:read`
|
||||
- **Query Params** :
|
||||
- `page` : Numéro de page (défaut: 1)
|
||||
- `page_size` : Taille de page (défaut: 20, max: 100)
|
||||
- `tag` : Filtrer par tag AI
|
||||
- `status` : Filtrer par statut (`pending`, `processing`, `done`, `error`)
|
||||
- `search` : Recherche textuelle dans le nom, la description AI ou l'OCR.
|
||||
| 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 |
|
||||
|
||||
#### Uploader une image
|
||||
`POST /api/v1/images/upload`
|
||||
- **Scope required** : `images:write`
|
||||
- **Body** : `multipart/form-data`
|
||||
- `file` : Le fichier image (JPEG, PNG, WebP, etc.)
|
||||
- **Note** : Lance automatiquement le pipeline AI en arrière-plan.
|
||||
**Recherche :** `GET /api/v1/images?search=motcle&tag=nature&status=done&page=1&page_size=20`
|
||||
|
||||
#### Détail complet d'une image
|
||||
`GET /api/v1/images/{id}`
|
||||
- **Scope required** : `images:read`
|
||||
- **Description** : Retourne toutes les données (Source, EXIF, OCR, AI).
|
||||
### Intelligence Artificielle
|
||||
|
||||
#### Statut du traitement
|
||||
`GET /api/v1/images/{id}/status`
|
||||
- **Scope required** : `images:read`
|
||||
- **Description** : Pour savoir si l'analyse par l'IA est terminée.
|
||||
| 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 |
|
||||
|
||||
#### Métadonnées spécifiques
|
||||
- `GET /api/v1/images/{id}/exif` : Données techniques de l'appareil et GPS.
|
||||
- `GET /api/v1/images/{id}/ocr` : Texte extrait de l'image.
|
||||
- `GET /api/v1/images/{id}/ai` : Description textuelle et tags générés.
|
||||
L'AI utilise le provider configuré (Gemini ou OpenRouter) avec circuit breaker : timeout configurable (`AI_REQUEST_TIMEOUT`) et retry exponentiel (`AI_MAX_RETRIES`).
|
||||
|
||||
#### Retraitement
|
||||
`POST /api/v1/images/{id}/reprocess`
|
||||
- **Scope required** : `images:write`
|
||||
- **Description** : Réinitialise et relance le pipeline d'analyse AI.
|
||||
### Administration (Admin)
|
||||
|
||||
#### Suppression
|
||||
`DELETE /api/v1/images/{id}`
|
||||
- **Scope required** : `images:delete`
|
||||
- **Description** : Supprime l'entrée en base et les fichiers sur le disque.
|
||||
| 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 |
|
||||
|
||||
#### Tags globaux
|
||||
`GET /api/v1/images/tags/all`
|
||||
- **Scope required** : `images:read`
|
||||
- **Description** : Liste tous les tags uniques utilisés par le 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 |
|
||||
|
||||
---
|
||||
|
||||
### 🤖 Intelligence Artificielle
|
||||
## Exemples Rapides
|
||||
|
||||
#### Résumé d'URL
|
||||
`POST /api/v1/ai/summarize`
|
||||
- **Scope required** : `ai:use`
|
||||
- **Body** (JSON) :
|
||||
```json
|
||||
{
|
||||
"url": "https://...",
|
||||
"language": "français"
|
||||
}
|
||||
```
|
||||
|
||||
#### Rédaction de tâche
|
||||
`POST /api/v1/ai/draft-task`
|
||||
- **Scope required** : `ai:use`
|
||||
- **Body** (JSON) :
|
||||
```json
|
||||
{
|
||||
"description": "Texte libre décrivant la tâche",
|
||||
"context": "Contexte optionnel",
|
||||
"language": "fr"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔑 Administration (Admin uniquement)
|
||||
*Nécessite le scope `admin`.*
|
||||
|
||||
- `POST /api/v1/auth/clients` : Créer un client (retourne la clé).
|
||||
- `GET /api/v1/auth/clients` : Lister tous les clients.
|
||||
- `GET /api/v1/auth/clients/{id}` : Voir les détails d'un client.
|
||||
- `PATCH /api/v1/auth/clients/{id}` : Modifier un client (nom, scopes, plan).
|
||||
- `POST /api/v1/auth/clients/{id}/rotate-key` : Changer la clé API.
|
||||
- `DELETE /api/v1/auth/clients/{id}` : Désactiver un client (suspension d'accès).
|
||||
|
||||
---
|
||||
|
||||
### 🏥 Santé et Status
|
||||
Ces endpoints sont **publics** et ne nécessitent aucune clé API.
|
||||
|
||||
- `GET /` : Informations de base sur l'application (Version, Status).
|
||||
- `GET /health` : Vérification complète de l'état (AI configurée, OCR actif, Modèle utilisé).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Exemples Rapides
|
||||
|
||||
### Lister mes images (Python / httpx)
|
||||
### Upload + suivi pipeline (Python)
|
||||
|
||||
```python
|
||||
import httpx
|
||||
import httpx, asyncio, websockets, json
|
||||
|
||||
headers = {"Authorization": "Bearer ma_super_cle"}
|
||||
r = httpx.get("http://localhost:8000/images", headers=headers)
|
||||
API = "http://localhost:8000"
|
||||
KEY = "ma_cle_api"
|
||||
headers = {"Authorization": f"Bearer {KEY}"}
|
||||
|
||||
for img in r.json()["items"]:
|
||||
print(f"ID: {img['id']} | Name: {img['original_name']}")
|
||||
```
|
||||
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']}")
|
||||
|
||||
### Uploader une image (Node.js / Axios)
|
||||
# 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
|
||||
|
||||
```javascript
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const FormData = require('form-data');
|
||||
# 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']}")
|
||||
|
||||
const form = new FormData();
|
||||
form.append('file', fs.createReadStream('vacances.jpg'));
|
||||
|
||||
axios.post('http://localhost:8000/images/upload', form, {
|
||||
headers: {
|
||||
...form.getHeaders(),
|
||||
'Authorization': 'Bearer ma_super_cle'
|
||||
}
|
||||
}).then(console.log);
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user