Spaces:
Sleeping
API (app/main.py)
POST /analyze
Requête (multipart/form-data)
| Champ | Type | Requis | Description |
|---|---|---|---|
image |
fichier | oui | photo du terminal de pompe (jpeg/png/bmp/webp/tiff) |
fuel_price |
float | non | prix du litre configuré côté YELY — fait autorité sur celui lu à l'écran |
driver_id |
string | non | identifiant chauffeur (issu du scan QR côté YELY) |
pompiste_id |
string | non | identifiant pompiste |
station_id |
string | non | identifiant station |
Volontairement pas de paramètres techniques (seuil de confiance OCR, activer/désactiver la détection d'écran...) — contrairement au prototype précédent, ce endpoint n'expose que les champs métier attendus par le cahier des charges.
Réponse (200)
Voir README.md pour un exemple complet. Tous les champs correspondent
au §13 du cahier des charges — voir docs/POSTPROCESS_RULES.md pour le
détail du calcul de chaque valeur, docs/ARCHITECTURE.md pour le
pipeline complet.
Erreurs
| Statut | Cas |
|---|---|
400 |
type d'image non supporté, ou fichier illisible |
500 |
erreur interne inattendue pendant le traitement (journalisée dans logs/api.log avec la stack trace complète) |
Chargement du modèle
Le CRNN est chargé une seule fois au premier appel (singleton
_get_model()), pas à chaque requête — le chargement prend 30-90s sur CPU.
Conséquence pratique : ne pas lancer uvicorn --reload en usage normal,
chaque rechargement de code redémarre le worker et donc le modèle.
CORS
ALLOWED_ORIGINS (variable d'environnement, origines séparées par des
virgules) contrôle quels domaines peuvent appeler l'API depuis un
navigateur — nécessaire car le frontend (Netlify) et l'API (Hugging Face
Spaces) sont sur des domaines différents. Par défaut "*" (permissif,
adapté à une démo) ; à restreindre au domaine Netlify réel en production.
Journalisation
Chaque appel écrit une ligne JSON dans logs/api.log : requête (sans
l'image elle-même) + réponse complète. C'est la base du suivi de
performance — voir docs/MONITORING.md.
Traçabilité
Chaque photo reçue est sauvegardée dans photos/<transaction_id>.jpg
et référencée dans la réponse (photo_reference) — nécessaire pour
qu'un contrôle a posteriori (station, YELY) puisse revérifier une
transaction contestée, et c'est aussi la matière première de la boucle
d'apprentissage continu (docs/MONITORING.md).
POST /feedback
Correction a posteriori d'une transaction déjà traitée par /analyze —
voir docs/MONITORING.md pour le fonctionnement complet de la boucle
d'apprentissage continu.
| Champ | Type | Requis | Description |
|---|---|---|---|
photo_reference |
string | oui | valeur renvoyée par /analyze (doit exister dans photos/) |
corrected_prix |
float | non* | montant réellement correct |
corrected_volume |
float | non* | volume réellement correct |
corrected_prix_litre |
float | non* | prix du litre réellement correct |
corrected_by |
string | non | identifiant de qui corrige (pompiste/station) |
* au moins un des trois champs corrected_* est requis.
Réponses : 200 ({"success": true, "feedback_id": "..."}), 404 si
photo_reference ne correspond à aucune photo connue, 400 si aucune
correction n'est fournie.
GET /metrics
Aperçu agrégé des performances observées en production, calculé à la volée
à partir de logs/api.log (pas de paramètre, pas d'état en mémoire) :
total_requests, success_rate, avg_confidence_score, blocking_causes,
image_quality_distribution. Voir docs/MONITORING.md.
GET /failures
Les limit (défaut 20) dernières transactions bloquées (success=false),
les plus récentes en premier — alimente la section « Requêtes échouées » de
web/stats.html. Chaque élément : photo_reference, message,
image_quality, detected_liters, detected_amount, fuel_price,
confidence_score, transaction_datetime.
GET /photos/{photo_reference}
Ressert l'image sauvegardée par /analyze sous ce photo_reference (sert
l'affichage dans le tableau de bord et le formulaire de correction). 404
si la référence est inconnue. photo_reference est assaini côté serveur
(Path(...).name) avant résolution sous PHOTOS_DIR — aucune traversée de
répertoire possible même si la valeur contient ../.