Justification des Choix
Documentation détaillée des décisions architecturales et techniques du projet THOR, avec métriques comparatives et justifications basées sur les benchmarks.
Architecture Pipeline
Flux de données
audio_filetext, confidenceorigin, destinationsteps[], total_timePrincipes architecturaux
Séparation modulaire
Interfaces abstraites STTModel, NLPModel, PathfindingModel
- Test unitaire de chaque module en isolation
- Échange de modèles sans modifier le code client
- Complexité divisée par 3 (debug facilité)
Registry dynamique
ModelRegistry avec lazy loading des modèles
- Startup rapide (~200ms vs ~3s sans lazy loading)
- Configuration YAML sans recompilation
- Ajout de nouveaux modèles = 1 décorateur
Types standardisés
Dataclasses STTResult, NLPExtraction, Route
- Contrat explicite entre modules
- Validation automatique des données
- Sérialisation JSON native (API)
Validation en couches
TranscriptValidator, CityValidator, ExtractionValidator
- Détection précoce des erreurs
- Suggestions de correction automatiques
- Métriques de confiance explicables
Système de Registry
class ModelRegistry:
_registry = {
"stt": {
"whisper": WhisperModel, # GPU optionnel
"vosk": VoskModel, # CPU only
"dummy": DummySTTModel
},
"nlp": {
"spacy_finetuned": SpacyNLPModel, # ◀ CHOISI
"regex_advanced": RegexAdvancedModel,
"transformers": TransformersNERModel
},
"pathfinding": {
"dijkstra": DijkstraModel # Temps pondéré
}
}
@classmethod
def get(cls, module_type: str, model_name: str):
return cls._registry[module_type][model_name]Choix STT : Whisper vs Vosk
Comparaison des processus
Whisper (small)
ChoisiVosk
TestéMétriques comparatives (30 échantillons)
Justification du choix Whisper
1. Précision critique pour le NLP
Les erreurs STT se propagent au NLP : une erreur de transcription peut rendre l'extraction d'entités impossible.
2. Transcriptions parfaites
Seul Whisper produit des transcriptions sans aucune erreur.
3. Post-traitement automatique
Whisper ajoute ponctuation et majuscules, facilitant la détection des noms propres.
4. Trade-off latence acceptable
387ms reste bien inférieur au seuil de perception humaine (~500ms).
Choix NLP : spaCy fine-tuné vs Regex vs Transformers
Comparaison des approches d'extraction
Regex Advanced
TestéspaCy fine-tuné
ChoisiProcessus d'entraînement spaCy
Métriques comparatives (test_nlp.jsonl)
| Modèle | F1-Score | Origine | Destination | Les 2 | Status |
|---|---|---|---|---|---|
| spaCy fine-tuné | 0.621 | 94.98% | 83.90% | 83.68% | Choisi |
| regex_advanced | 0.430 | 80.82% | 29.57% | 27.05% | Testé |
| spaCy (base) | 0.407 | 72.60% | 42.24% | 40.75% | Testé |
| Transformers (CamemBERT) | Erreur | - | - | - | Non retenu |
Justification du choix spaCy fine-tuné
1. Amélioration F1 de +53%
Le fine-tuning permet au modèle d'apprendre les labels ORIGIN/DESTINATION spécifiques à notre cas d'usage.
2. Précision destination corrigée
La regex échoue sur les destinations complexes ou implicites.
3. Compréhension contextuelle
spaCy comprend le contexte sémantique, pas seulement les patterns.
4. Pourquoi pas Transformers ?
CamemBERT a échoué sur notre dataset de test.
Pourquoi le Regex est insuffisant
- • Typos : "parir" → Paris non reconnu
- • Destinations implicites : "vers chez moi"
- • Structures complexes : "en passant par Avignon"
- • Variations régionales : "sur Marseille"
- • ~100 villes hardcodées seulement
- • Recall 39% vs 62% (−37%)
- • Pas d'apprentissage possible
- • Maintenance manuelle des patterns
Choix Pathfinding : Dijkstra avec pénalités
Algorithme de Dijkstra
function dijkstra(graph, origin, destination):
distances = {node: ∞ for all nodes}
distances[origin] = 0
parent = {}
priority_queue = [(0, origin)]
while priority_queue not empty:
current_dist, current = pop_min(priority_queue)
if current == destination:
return reconstruct_path(parent)
for neighbor, edge_data in graph.neighbors(current):
# ◀ PÉNALITÉ : temps × multiplicateur selon type de train
weight = edge_data.temps_min × PENALTY[edge_data.type_train]
new_dist = current_dist + weight
if new_dist < distances[neighbor]:
distances[neighbor] = new_dist
parent[neighbor] = current
push(priority_queue, (new_dist, neighbor))
return None # Pas de chemin trouvéSystème de pénalités par type de train
| Type de train | Pénalité | Justification |
|---|---|---|
| TGV, OUIGO, Lyria, Eurostar | ×1.0 | Priorité maximale : rapide, confortable |
| Intercités | ×1.3 | +30% pour favoriser TGV quand disponible |
| Train de nuit | ×1.5 | Lent mais utile pour longues distances |
| TER, Navette | ×2.0 | Régional, nombreux arrêts |
| Auto-train | ×2.5 | Très lent, cas spécifique |
| Correspondance (métro) | ×1.0 | Transfert inter-gare, neutre |
Exemple : Paris → Lyon
Construction du graphe depuis les données SNCF
- • Codes UIC (8 chiffres) via regex
- • Arrêts consécutifs par trip_id
- • Type train : OCETGV, OCEOUIGO, OCETER...
- • temps_moyen_min : moyenne observée
- • temps_min_min : minimum observé
- • nb_trains : fréquence journalière
Gestion des villes multi-gares
Système de scoring
Exemple : Paris
Justification du choix Dijkstra
1. Optimalité garantie
Dijkstra trouve toujours le chemin de poids minimal. Crucial pour un système de recommandation de trajets.
2. Pourquoi pas A* ?
A* nécessite une heuristique admissible.
→ Heuristique invalide → perte d'optimalité
3. Optimisation par le temps
Les utilisateurs optimisent leur temps de trajet, pas les kilomètres. Le système de pénalités encode cette préférence.
4. Performance suffisante
Avec 2,782 nœuds et 7,852 arêtes :
Correspondances inter-gares Paris
Arêtes spéciales pour les transferts métro entre gares parisiennes :
Données et prétraitement
Pipeline de données complète
generate_enhanced_graph.py- • Extraction codes UIC depuis stop_id
- • Calcul temps trajet entre arrêts consécutifs
- • Identification type train (TGV, TER, etc.)
train_station_converter.py- • Normalisation noms de villes
- • Construction aliases (Saint/St, etc.)
- • Index ville → [gares]
Données SNCF officielles
Source de vérité pour les temps de trajet
- Horaires réels (pas estimations)
- Couverture nationale exhaustive
- Mise à jour régulière (GTFS)
Optimisation par le temps
Métrique alignée avec les besoins utilisateurs
- Temps de trajet = critère principal
- Distance euclidienne non représentative
- TGV Paris-Lyon plus rapide malgré détours