Documentation API

Guide complet pour utiliser le dashboard Predict W'AI avec son API FastAPI.

Sommaire
  1. Démarrage rapide
  2. Architecture technique
  3. Référence des endpoints
  4. Mode démo sans API
  5. Intégrer ses propres données
  6. Upload, analyse et modèle YOLOv8
  7. Copilote IA — emails prestataires
  8. Changelog

1. Démarrage rapide

Prérequis

Lancer le backend FastAPI

cd predictwai-app-main
pip install -r requirements.txt
uvicorn main:app --reload --host 0.0.0.0 --port 8000

L'API sera disponible à http://localhost:8000. La doc interactive Swagger est accessible à http://localhost:8000/docs.

Lancer le frontend

Ouvrez web/index.html avec VS Code Live Server (port 5500 par défaut) ou tout serveur HTTP local.

Le frontend utilise des chemins relatifs (css/, js/). Assurez-vous que votre serveur sert le dossier web/ comme racine, ou ouvrez web/index.html directement via Live Server depuis la racine du projet.

Configurer la connexion API

Par défaut le frontend pointe sur /api/v1 (même domaine). Si le backend tourne sur un port différent, modifiez la constante BASE dans js/bundle.js :

// js/bundle.js — ligne ~207
const BASE = 'http://localhost:8000/api/v1';

2. Architecture technique

predictwai-app-main/
├── api/
│   ├── main.py                ← Point d'entrée FastAPI + montage statiques
│   └── routers/
│       ├── sections.py        ← GET  /sections — GeoJSON tronçons
│       ├── predictions.py     ← GET  /predictions — horizons temporels
│       ├── budget.py          ← GET  /budget/overview + POST /budget/scenarios
│       ├── dashboard.py       ← GET  /dashboard/kpis
│       ├── analyze.py         ← POST /photos/analyze — pipeline YOLOv8 complet
│       ├── photos.py          ← POST /photos/upload + GET /photos/file/{filename}
│       └── copilote.py        ← POST /copilote/extract — LLM avec fallback
├── core/
│   ├── exif.py               ← Extraction GPS/EXIF (Pillow)
│   ├── detection.py          ← Inférence YOLOv8 + remapping classes → D-codes
│   ├── geo.py                ← WFS BD TOPO IGN + association photo↔tronçon
│   ├── aggregation.py        ← Agrégation scores par tronçon
│   └── optimization.py       ← Solveur MILP (PuLP + CBC)
├── ui/                        ← Interface Streamlit (alternative web)
│   ├── app.py                 ← Application Streamlit 6 onglets
│   ├── styles.py              ← Design system responsive (3 breakpoints)
│   └── tabs/                  ← Modules onglets (detection, scan, overview…)
├── train/                     ← Outils d'entraînement YOLOv8
│   ├── auto_train.py          ← Pipeline complet : téléchargement + entraînement
│   ├── download_pretrained.py ← Téléchargement checkpoint HuggingFace
│   ├── train.py               ← Fine-tuning sur dataset annoté
│   ├── evaluate.py            ← Évaluation mAP par classe
│   ├── prepare_dataset.py     ← Préparation structure YOLO
│   └── dataset.yaml           ← Configuration dataset YOLO
├── models/
│   └── best_last_model.pt    ← Modèle YOLOv8 road-damage (non versionné Git)
├── data/
│   └── photos/               ← Photos terrain (servi via /api/v1/photos/file/)
├── config.py                 ← Constantes globales (classes, seuils, remapping)
└── web/
    ├── index.html            ← SPA frontend
    ├── css/main.css          ← Design system
    ├── js/bundle.js          ← Application JS (tout-en-un, sans bundler)
    └── doc.html              ← Cette documentation

Le frontend est une SPA vanilla JS sans framework. Chaque écran (Overview, Scan, Predict…) est initialisé à la demande via navigate(). Les données sont chargées depuis l'API FastAPI via fetch().

L'application dispose de deux interfaces : la SPA vanilla JS (web/, servie par FastAPI sur le port 8000) et une interface Streamlit (ui/, streamlit run ui/app.py sur le port 8501). Les deux partagent le même backend core/.

3. Référence des endpoints

Tous les endpoints sont préfixés par /api/v1.

Dashboard

GET
/dashboard/kpis
KPIs agrégés du réseau : score moyen, répartition des urgences, budget, évolution temporelle.

Réponse exemple :

{
  "n_troncons": 42,
  "score_moyen": 58.3,
  "n_critique": 5,
  "n_urgent": 12,
  "n_planifie": 18,
  "n_surveille": 7,
  "cout_total_estime": 284000,
  "n_photos_total": 186,
  "confidence_moyenne": 0.81,
  "lineaire_km": 8.4,
  "budget_annuel": 1000000,
  "budget_consomme": 284000,
  "evolution_score": [
    {"date": "Jan 2025", "score": 68.0},
    {"date": "Avr 2025", "score": 58.3}
  ]
}

Tronçons (GeoJSON)

GET
/sections
FeatureCollection GeoJSON de tous les tronçons avec leurs propriétés (score, urgence, coût…).
GET
/sections/{id}
Détail d'un tronçon par identifiant (ex. TR-001).
PropriétéTypeDescription
idstringIdentifiant unique du tronçon (TR-001…)
nom_ruestringNom de la voie
communestringCommune INSEE
scorefloat 0-100Score d'état (0 = très dégradé, 100 = parfait)
urgenceenumCRITIQUE / URGENT / PLANIFIÉ / SURVEILLÉ
classe_dominantestringClasse YOLO dominante (D40, D20, D10, D00)
cout_estimefloatCoût de réfection estimé en €
longueur_mfloatLongueur en mètres
confidencefloat 0-1Confiance moyenne des détections IA

Prédictions

GET
/predictions?horizon={horizon}
Tronçons nécessitant une intervention dans l'horizon donné. horizon : all | 12m | 6m | 3m.

Budget

GET
/budget/overview
Aperçu du budget annuel : disponible, consommé, réserve imprévus, projets planifiés.
POST
/budget/scenarios
Simuler un scénario budgétaire. Body JSON : {"budget": 500000, "horizon": "12m"}.

Photos — upload & analyse IA

POST
/photos/analyze
Pipeline complet : EXIF → GPS → YOLOv8 → tronçons IGN → scores. Body : multipart/form-data, champ files.
POST
/photos/upload
Sauvegarde les photos dans data/photos/ sans lancer l'analyse. Body : multipart/form-data.
GET
/photos/file/{filename}
Sert une photo individuelle depuis data/photos/. Le nom de fichier doit être URL-encodé (encodeURIComponent) — gère les espaces et caractères spéciaux. Utilisé par la galerie du dashboard en mode démo.
// Exemple : charger une photo dans le navigateur
fetch('/api/v1/photos/file/' + encodeURIComponent('IMG_0142 - Copy.jpg'))
  .then(r => r.blob())
  .then(b => { img.src = URL.createObjectURL(b); });

Copilote IA

POST
/copilote/extract
Extraire les postes, montants et tronçons depuis un email ou devis prestataire (texte brut).
// Body JSON
{
  "texte": "De : contact@entreprise.fr\n... contenu email ...",
  "provider": "mistral"   // ou "claude"
}

// Réponse
{
  "fournisseur": "Vendée TP & Voirie SARL",
  "reference": "DEV-2026-0342",
  "montant_ht": 21146.0,
  "montant_ttc": 25375.20,
  "tva_pct": 20,
  "postes": [
    { "description": "Fraisage enrobé", "quantite": 800, "unite": "m²", "prix_unitaire": 4.50, "montant": 3600 }
  ],
  "troncons_concernes": ["TR-001"],
  "confidence": 0.94,
  "provider": "mistral"
}

4. Mode démo sans API

Le dashboard fonctionne sans backend grâce au mode démo intégré. Les données de démonstration représentent le réseau routier de Saint-Hilaire-de-Riez (85194).

Activer le mode démo

Cliquez sur le bouton ⚡ DÉMO en bas à gauche du dashboard. Toutes les requêtes API sont interceptées et retournent des données simulées réalistes.

Données démo disponibles

L'onglet 00 · OVERVIEW charge automatiquement la galerie photos démo au démarrage. Aucune action requise.

5. Intégrer ses propres données

Fournir les données tronçons

Le backend lit les tronçons depuis un fichier GeoJSON dans data/. Format attendu :

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "TR-001",
      "geometry": {
        "type": "LineString",
        "coordinates": [[-1.939, 46.703], [-1.940, 46.704]]
      },
      "properties": {
        "id": "TR-001",
        "nom_rue": "Route du Sel",
        "commune": "Ma Commune",
        "score": 18.5,
        "urgence": "CRITIQUE",
        "classe_dominante": "D40",
        "cout_estime": 12800,
        "longueur_m": 320,
        "confidence": 0.87
      }
    }
  ]
}

Adapter la commune et le centre de carte

Dans js/bundle.js, modifiez les coordonnées du centre de carte :

// Scan screen — ligne ~888
var center = [-1.942, 46.711];  // ← longitude, latitude de votre commune

Variables d'environnement backend

VariableRequisDescription
MISTRAL_API_KEYoptionnelClé API Mistral pour le Copilote IA
ANTHROPIC_API_KEYoptionnelClé API Claude pour le Copilote IA
DATA_DIRoptionnelChemin vers le dossier de données (défaut : ./data)
YOLO_MODELoptionnelChemin vers le modèle YOLOv8 (.pt)

6. Upload et analyse de photos

Les photos doivent être au format JPG ou PNG avec données EXIF GPS pour être géolocalisées automatiquement sur les tronçons IGN.

Flux d'analyse

  1. L'utilisateur dépose les photos dans l'onglet 01 · SCAN
  2. Le backend extrait les coordonnées GPS des métadonnées EXIF
  3. Chaque photo est géolocalisée sur le tronçon IGN le plus proche (rayon 50 m)
  4. YOLOv8 détecte les dégradations et remapping automatique vers les codes D00/D10/D20/D40 (quel que soit le modèle chargé)
  5. Un score 0-100 est calculé par tronçon et l'urgence est déterminée
  6. Le dashboard est mis à jour automatiquement (KPIs, carte, alertes)

Modèle YOLOv8 — classes et remapping

Le modèle actuel est ozair23/yolov8-road-damage-detector (HuggingFace, 6,2 MB). Il détecte 5 classes en anglais que le backend remapping automatiquement :

Sortie modèleCode ASTMDescriptionPoids ASTM
longitudinal crackD00Fissure longitudinale0.218
transverse crackD10Fissure transversale0.328
alligator crackD20Faïençage / alligator0.692
other corruptionD40Autre dégradation1.000
PotholeD40Nid-de-poule1.000

Ce remapping est défini dans config.py (constante REMAP_VERS_DCODE) et appliqué dans core/detection.py. Tout nouveau modèle aux noms de classes différents se configure via ce dictionnaire uniquement.

Score qualité chaussée (ASTM D6433-18)

score = round(exp(−S) × 100, 1)
S = Σ POIDS_ASTM[classe] × confiance

Exemples : 100 = aucun défaut · 37.9 = route très dégradée (3× D40) · 0 ≈ hors service

Entraîner un nouveau modèle

Le dossier train/ contient tous les outils nécessaires :

# Téléchargement automatique (HuggingFace public, pas d'auth)
python train/download_pretrained.py

# Pipeline complet : téléchargement dataset + conversion + entraînement
python train/auto_train.py

# Fine-tuning sur vos propres photos annotées
python train/prepare_dataset.py   # structurer data/photos/
labelImg                          # annoter (format YOLO)
python train/train.py --epochs 50 --batch 4

# Évaluation du modèle
python train/evaluate.py --model models/best_last_model.pt

7. Copilote IA — emails prestataires

Le Copilote IA (onglet 05 · COPILOTE IA) extrait automatiquement les données structurées depuis les emails et devis des entreprises de voirie.

Configuration des clés API

# .env
MISTRAL_API_KEY=sk-...   # Mistral AI (souverain FR/EU — provider principal)
ANTHROPIC_API_KEY=sk-... # Claude API (fallback automatique si Mistral indisponible)

Fallback automatique entre providers

Le backend gère un basculement automatique entre les deux providers LLM. Si le provider principal renvoie une erreur de crédit, quota ou authentification, le second provider est tenté automatiquement :

// Comportement selon provider sélectionné
provider = "mistral"  →  essai Mistral → si erreur crédit/quota → bascule Claude
provider = "claude"   →  essai Claude  → si erreur crédit/quota → bascule Mistral

Ce comportement est implémenté dans api/routers/copilote.py via la fonction _call_with_fallback().

Utilisation

  1. Collez le contenu d'un email ou devis dans la zone de texte
  2. Sélectionnez le fournisseur IA (Mistral ou Claude)
  3. Cliquez sur Extraire les données →
  4. L'IA identifie : fournisseur, référence, postes de travaux, montants HT/TTC, tronçons concernés
  5. Le résultat est exportable en PDF via ↓ PDF dans l'historique
Sans clé API configurée, utilisez le bouton Charger exemple démo pour tester l'extraction avec un devis fictif Vendée TP.

8. Changelog

v0.3.0 — Avril 2026


Predict W'AI · Road Maintenance OS · Documentation v1.1 · Avril 2026