[{"content":"Contexte Les sites intérieurs sont souvent documentés avec une caméra sur stabilisateur tenue à la main plutôt qu\u0026rsquo;avec un scanner de qualité topographique. L\u0026rsquo;objectif était de transformer ces vidéos en livrables 3D exploitables (nuage dense, maillage texturé, orthovues en plan et en élévation, scène Gaussian Splatting et exports web légers), sans aucune étape manuelle entre la captation et le résultat. La chaîne de traitement s\u0026rsquo;exécute nativement sous Windows sur une RTX 5090 (Blackwell, sm_120) partagée avec d\u0026rsquo;autres charges GPU de longue durée ; elle ne doit donc jamais les préempter.\nApproche flowchart TB A[\"inbox/projet/vidéos + fichier GO\"] --\u003e B[\"Extraction d'images clésrecouvrement par flot optique + netteté\"] B --\u003e C[\"SfM COLMAP 4.2.1SIFT, mapper global\"] C --\u003e D{\"Contrôle qualité : enregistrement, reprojection,continuité de trajectoire\"} D -- échec --\u003e C2[\"Repli : mapper incrémental\"] --\u003e D D -- succès --\u003e E[\"OpenMVS 2.4 (build sm_120)densification, maillage, raffinement, texture\"] E --\u003e F[\"Alignement orthogravité, sol par RANSAC, lacet Manhattan\"] F --\u003e G[\"Rendus Blenderorthos, axonométries, orbite\"] E --\u003e H[\"Entraînement gsplatstratégie MCMC ou par défaut\"] G --\u003e I[\"Exports webPotree, GLB, SOG\"] H --\u003e I I --\u003e J[\"outbox : livrables, report.json, STATUS\"]Méthodes Sélection d\u0026rsquo;images clés guidée par le recouvrement. Un suivi KLT associé à une similitude estimée par RANSAC évalue le recouvrement avec la dernière image clé. Une image est émise lorsque le recouvrement descend sous 0,80, que le suivi est perdu ou qu\u0026rsquo;une limite de temps est atteinte. Le candidat le plus net (variance du laplacien) est celui retenu. SfM avec contrôle qualité explicite. Le mapper global de COLMAP est rapide mais non déterministe. Lors des essais, il a produit des reconstructions qui satisfaisaient les critères d\u0026rsquo;enregistrement et de reprojection tout en étant géométriquement incohérentes. Un contrôle de continuité de trajectoire (sauts supérieurs à 25 fois le pas médian de la caméra) déclenche un repli automatique sur le mapper incrémental. En dessous de 20 points par image, l\u0026rsquo;étape échoue. Fiabilisation du MVS. Le binaire Windows officiel d\u0026rsquo;OpenMVS ne contient que des noyaux sm_89 ; il a donc été recompilé pour sm_120. La ROI objet est désactivée pour les pièces car elle rognait le nuage. Le raffinement est abandonné lorsqu\u0026rsquo;il diverge, et le nivellement des coutures (qui noircissait des faces) est désactivé. Orthovues prêtes pour la métrique. L\u0026rsquo;axe vertical est déduit des orientations des caméras. Un plan de sol estimé par RANSAC fixe z = 0 et un histogramme des azimuts des normales aux murs (modulo 90°) fixe le lacet Manhattan. Une référence optionnelle à deux points fixe l\u0026rsquo;échelle. La transformation 4×4 est conservée afin d\u0026rsquo;être réappliquée au maillage et au splat. Gaussian Splatting. gsplat 1.6.0 a été compilé pour sm_120 avec CUDA 13 sous MSVC, ce qui a nécessité des correctifs locaux. L\u0026rsquo;entraînement utilise la stratégie MCMC avec un budget de gaussiennes et se replie sur la stratégie 3DGS par défaut lorsque MCMC diverge. Exploitation. Les projets démarrent en mode dossier surveillé dès qu\u0026rsquo;un fichier GO apparaît. Les étapes peuvent être reprises ou refaites. Une garde GPU attend qu\u0026rsquo;une quantité suffisante de VRAM soit libre pendant une période stable, sérialise les étapes GPU via un fichier verrou et enregistre le pic de VRAM par étape dans report.json. Un contrôle qualité dégradé produit un statut DONE_WITH_ALERTS plutôt qu\u0026rsquo;un succès silencieux. Résultats Premier déploiement réel : cinq emplacements dans un showroom commercial, une vidéo 4K tournée à la main par emplacement, traitée sans intervention en environ 30 minutes par emplacement.\nEmplacement Images SfM enregistrées / points / reproj. Nuage dense PSNR / SSIM du splat 1 116 116/116 · 21 458 · 1,49 px 1,40 M 23,2 / 0,86 2 103 103/103 · 18 972 · 1,75 px 1,23 M 20,6 / 0,81 3 47 47/47 · 13 167 · 1,17 px 1,26 M 23,1 / 0,86 4 121 121/121 · 11 970 · 1,34 px 1,99 M 21,9 / 0,85 (stratégie par défaut) 5 64 64/64 · 12 106 · 1,48 px 0,91 M 21,8 / 0,83 Toutes les images ont été enregistrées pour chaque emplacement. L\u0026rsquo;erreur de reprojection était de 1,17–1,75 px. Pics de VRAM mesurés : SIFT +1,3 Go, appariement +1,6 Go, texturation +0,5 Go, Blender +5,4 Go, et splatting avec 3 M de gaussiennes à 1920 px +25,2 Go. Le build OpenMVS sm_120 a densifié le test de validation rapide synthétique en 17 s. Le repli CPU a pris environ 40 min. L\u0026rsquo;analyse des métadonnées a révélé des vitesses d\u0026rsquo;obturation de 1/50–1/100 s (environ 14 px de flou de bougé en 4K) ainsi qu\u0026rsquo;une sensibilité ISO et une balance des blancs automatiques. La compensation d\u0026rsquo;exposition de gsplat (ppisp) n\u0026rsquo;a apporté aucun gain (PSNR 20,5 contre 20,6). La limite de qualité tient à la captation, pas au solveur. Limites \u0026amp; suite Un PSNR d\u0026rsquo;à peine plus de 20 reflète le flou de bougé et l\u0026rsquo;exposition automatique. Le protocole de captation impose désormais une vitesse d\u0026rsquo;obturation de 1/250–1/500 s, une exposition et une balance des blancs verrouillées, ainsi qu\u0026rsquo;un passage dédié au sol. La fusion de vidéos provenant d\u0026rsquo;emplacements différents a provoqué de faux appariements et un modèle incohérent ; chaque emplacement est donc traité séparément. Les sols carrelés sombres et brillants se reconstruisent mal. L\u0026rsquo;alignement Manhattan n\u0026rsquo;est pas encore fiable en présence de mobilier et de vitrages. Les étapes CPU constituent le goulot d\u0026rsquo;étranglement sur une machine virtuelle à 4 vCPU. Prévu : comparaison avec une suite de photogrammétrie commerciale sur les mêmes images, et nouvel essai du raffinement de maillage avec le build sm_120. Stack technique Python 3.11 · OpenCV · Open3D · NumPy · COLMAP 4.2.1 · OpenMVS 2.4 · gsplat 1.6.0 · PyTorch 2.14 (CUDA 13) · Blender 5.2 · FFmpeg · PotreeConverter · glTF-Transform · splat-transform\n","date":"2026-10-01T00:00:00Z","permalink":"/fr/research/photogrammetry-splatting/","title":"De la vidéo tournée à la main à la photogrammétrie et au Gaussian Splatting"},{"content":"Contexte Fort-de-France (Martinique) ne dispose de presque aucune donnée ouverte locale. Les jeux de données de la ville ont été mis à jour pour la dernière fois en 2019, et il n\u0026rsquo;existe ni compteurs piétons publics, ni chiffres ouverts de fréquentation des transports en commun, ni comptages routiers ouverts à l\u0026rsquo;échelle du centre-ville. Le projet cherche à savoir jusqu\u0026rsquo;où les données ouvertes nationales et des flux archivés en continu permettent de décrire le centre-ville comme un système de points d\u0026rsquo;intérêt (commerces, administrations, établissements scolaires, santé, culture, portes d\u0026rsquo;entrée) et de flux (résidents, navetteurs, élèves, visiteurs, croisiéristes, véhicules, bus) sur un horizon de dix ans (2016–2026).\nAucune source ne répond seule à cette question. Le répertoire des entreprises sait où sont les établissements, mais pas qui les fréquente. Le recensement sait où les habitants dorment, mais pas où ils passent la journée. Les flux de transport montrent les bus, pas leurs passagers ; les calendriers d\u0026rsquo;escales montrent les navires, pas les croisiéristes à terre. La démarche consiste donc à croiser de nombreuses sources hétérogènes sur un cadre spatial et temporel commun, pour que chacune comble un angle mort des autres, puis à confronter le résultat aux rares signaux mesurés qui existent.\nApproche La méthode est issue d\u0026rsquo;un précédent projet de base de connaissances que j\u0026rsquo;ai mené. Les données brutes sont immuables et adressées par leur contenu. Chaque base de données est jetable et reconstruite à partir d\u0026rsquo;elles. Chaque valeur conserve sa provenance, et un ensemble d\u0026rsquo;invariants est vérifié à chaque reconstruction.\nflowchart TB A[Catalogue des sourcessources.yaml] --\u003e B[Stockage brut immuablesha256 + manifeste JSONL] C[Collecteurs planifiésMeta tous les 14 jours · GTFS-RT 60 s] --\u003e B B --\u003e D[Extracteurs versionnésParquet normalisé] D --\u003e E[Entrepôt spatial DuckDBreconstruit, jamais modifié] E --\u003e F[Invariants QA I1–I6] E --\u003e G[Statistiquesrequetes/*.sql] E --\u003e H[Application de bureaucarte + sélecteur temporel] G --\u003e I[Calage surdes signaux mesurés]Méthodes Acquisition. Chaque téléchargement est haché (SHA-256) et consigné dans un manifeste JSONL, et l\u0026rsquo;acquisition est idempotente. Les fichiers nationaux de plus de 1 Go (répertoire Sirene des entreprises) sont lus sous forme d\u0026rsquo;extraits distants par requêtes HTTP Range, filtrés sur la commune. La requête de filtrage est enregistrée comme partie intégrante de la provenance. Sources éphémères. Meta Movement Distribution ne conserve que 90 jours en ligne : une tâche planifiée l\u0026rsquo;archive donc tous les 14 jours. Un collecteur de bus interroge les positions des véhicules GTFS-RT toutes les 60 s et les prévisions toutes les 10 min, et compresse chaque journée en zip avec une somme de contrôle SHA-256. Cadre spatial. Les données sont stockées en WGS84 et calculées en EPSG:5490 sur la grille INSEE de 200 m. Les points d\u0026rsquo;intérêt sont classés selon une typologie unique (codes NAF, balises OSM, arrêts), avec une famille, un poids et un rythme horaire sur sept créneaux. Modèles. La présence horaire par carreau combine résidents (Filosofi 2021, répartis de manière dasymétrique sur les bâtiments), salariés, élèves et touristes. Un modèle de Huff estime les zones de chalandise. Les croisiéristes à terre sont modélisés à partir des horaires et des capacités des navires. Un modèle gravitaire à l\u0026rsquo;échelle de l\u0026rsquo;île, avec affectation BPR, couvre les visiteurs et le trafic de transit. Qualité. Six invariants sont vérifiés, de la provenance à l\u0026rsquo;absence de données personnelles. Les paramètres non confirmés sont consignés dans un journal des décisions. Sources de données Le croisement des sources est le cœur du projet. Les registres d\u0026rsquo;entreprises (Sirene, BODACC, URSSAF) donnent le stock et la rotation des activités, mais ne disent rien des personnes qui les entourent. Le recensement et les données fiscales (RP, Filosofi) situent les habitants, leurs revenus et la vacance des logements, mais seulement la nuit. Les fichiers de navettes et l\u0026rsquo;enquête nationale de mobilité (MOBPRO, MOBSCO, EMP) disent qui se déplace, pourquoi et quand. Les flux de transport, d\u0026rsquo;accidents et de qualité de l\u0026rsquo;air (GTFS-RT, BAAC, Madininair) sont les seules traces mesurées du mouvement. Les calendriers d\u0026rsquo;escales et les capacités des navires apportent une population qu\u0026rsquo;aucun recensement ne compte. Les référentiels géographiques (IGN, OpenStreetMap, grille INSEE de 200 m) rendent enfin tout cela comparable, carreau par carreau.\nLe catalogue recense 120 sources : 51 intégrées, 32 à intégrer, 7 à vérifier, 13 disponibles uniquement sur demande, 5 payantes, 1 sur partenariat et 11 non retenues. Les tableaux ci-dessous listent toutes les sources intégrées et résument les autres par thème.\nEntreprises, emplois et équipements Source Apport Période / fréquence Statut Base Sirene des entreprises — INSEE Établissements, code d\u0026rsquo;activité (NAF), dates de création et de fermeture, tranches d\u0026rsquo;effectif Historique complet ; stock reconstituable à toute date 2016–2026 Intégrée BODACC — DILA Rotation et défaillances des commerces (ventes de fonds, procédures collectives) 2016–2026, quotidienne Intégrée Base permanente des équipements (BPE) géolocalisée — INSEE Commerces, services, santé, administrations, enseignement, sport, tourisme Éditions 2024 et 2025, annuelle Intégrée Établissements et effectifs salariés commune × APE — URSSAF / Acoss Emploi salarié privé par activité 2006–2025, annuelle Intégrée Annuaire de l\u0026rsquo;éducation et effectifs d\u0026rsquo;élèves — MENJ / DEPP Écoles, localisation, élèves par rentrée, personnels Effectifs 2016–2025 Intégrée FINESS — DREES / ARS Établissements sanitaires et sociaux, pharmacies Extraction de mai 2026, bimestrielle Intégrée Overture Maps (places) — Overture Maps Foundation Points d\u0026rsquo;intérêt avec score de confiance (couche de comparaison) Extrait figé de la release 2026-09-23, mensuelle Intégrée OpenStreetMap (Overpass) — contributeurs OpenStreetMap Points d\u0026rsquo;intérêt, commerces, voirie, cheminements piétons État courant Intégrée Monuments historiques (Mérimée / POP) — ministère de la Culture Attracteurs patrimoniaux (cathédrale, bibliothèque Schœlcher, fort Saint-Louis) Courant Intégrée 23 autres — par ex. Flores, emploi salarié localisé (INSEE), Foursquare Open Source Places, LOCOMVAC, locaux commerciaux vacants (DGFiP), Google Places Cataloguées Population, revenus et logement Source Apport Période / fréquence Statut Recensement, bases infracommunales IRIS (RP) — INSEE Résidents, âge, CSP, logements (vacance, motorisation), actifs RP 2016 → RP 2022, annuelle Intégrée Filosofi par IRIS — INSEE Revenus disponibles et déclarés, pauvreté 2016–2021, annuelle Intégrée Filosofi carroyé 200 m, fichiers — INSEE Ménages fiscaux, individus, pauvreté, logements sociaux et âges au carreau de 200 m 2015, 2017, 2019, 2021 Intégrée Filosofi carroyé 200 m, couche WFS Géoplateforme — INSEE Géométries des carreaux Couche 2015 Intégrée IRCOM, impôt sur le revenu par commune — DGFiP Foyers fiscaux, revenus déclarés 2016–2024, annuelle Intégrée Cafdata — CNAF Allocataires du RSA, des aides au logement et des prestations familiales 2020–2024 (2022 manquant), annuelle Intégrée Quartiers prioritaires (QPV) — ANCT / INSEE Géographie prioritaire, qui inclut le centre-ville Contours 2024 Intégrée LOVAC — Cerema / DGALN Vacance courte et structurelle (≥ 2 ans) du parc privé Éditions 2020–2026, annuelle Intégrée RPLS, parc locatif social — SDES Logements sociaux (adresse, surface, loyer, vacance) 2023 et 2025 Intégrée Sitadel, permis de construire — SDES Logements et locaux autorisés, commencés, démolis 2013–2026, mensuelle Intégrée DVF géolocalisées — DGFiP / Etalab Mutations immobilières (prix, surfaces, locaux commerciaux) 2021–2025, fenêtre glissante de 5 ans Intégrée 8 autres — par ex. fichiers détail du recensement et populations légales (INSEE), DV3F et Fichiers fonciers (Cerema / DGFiP), population carroyée WorldPop / GHSL Cataloguées Mobilité et transports Source Apport Période / fréquence Statut Mobilités professionnelles (MOBPRO) — INSEE Navettes domicile → travail entre communes 2016–2022, annuelle Intégrée Mobilités scolaires (MOBSCO) — INSEE Navettes domicile → études entre communes 2016–2022, annuelle Intégrée Enquête mobilité des personnes 2018-2019 (EMP) — SDES Motifs, horaires de départ et de retour, durées d\u0026rsquo;activité, distances 2018–2019 Intégrée GTFS, réseau urbain zone Centre (Mozaïk, BHNS) — Martinique Transport Offre théorique de transports collectifs Archives depuis juin 2023 Intégrée GTFS-RT, collecte continue — Martinique Transport Vitesses observées des bus, bus en service, remplissage déclaré Depuis le 7 octobre 2026 ; 60 s (positions), 10 min (prévisions) Intégrée GTFS, navettes maritimes — Martinique Transport Navettes débarquant au front de mer Versions depuis août 2024 Intégrée Accidents corporels de la circulation (BAAC) — ONISR Accidents localisés (piétons, véhicules), avec l\u0026rsquo;heure 2016–2024 chargés Intégrée Movement Distribution — Meta Data for Good / HDX Part des usagers restés à domicile, à moins de 10 km, entre 10 et 100 km, au-delà de 100 km Quotidienne ; fenêtre de 90 jours, archivée tous les 14 jours Intégrée Movement Range Maps — Meta Data for Good / HDX Variation des déplacements, part des usagers restés sur place Mars 2020 → mai 2022, quotidienne (arrêtée) Intégrée BD TOPO, réseau routier principal — IGN Graphe routier de l\u0026rsquo;île pour l\u0026rsquo;affectation du trafic Courant Intégrée BD TOPO, tronçons de route — IGN Largeur de chaussée, voies et sens, pour métrer le stationnement le long des rues Courant Intégrée Parkings OpenStreetMap — contributeurs OpenStreetMap Parkings, type, capacité déclarée Courant Intégrée 18 autres — par ex. fréquentation et validations (Martinique Transport, sur demande), comptages routiers (sur demande), données de téléphonie Orange Flux Vision (payantes), Waze for Cities / Strava Metro (partenariat), campagne de comptages piétons (à créer) Cataloguées Tourisme et croisière Source Apport Période / fréquence Statut Calendrier des escales du port de Fort-de-France — CruiseMapper Escales navire par navire, avec heures d\u0026rsquo;arrivée et de départ Mars 2026 → mars 2029 ; archivage mensuel, les mois passés disparaissant du site Intégrée Fiches navires — CruiseMapper Capacité passagers, équipage, jauge des navires en escale Courant Intégrée Bilans de saison de croisière — Comité martiniquais du tourisme (CMT), via la presse Croisiéristes et escales par saison, terminaux de croisière Saisons 2024-2025 et 2025-2026 Intégrée PortWatch — FMI / HDX Escales quotidiennes issues de l\u0026rsquo;AIS 2019–2026, quotidienne Intégrée Trafic aérien commercial mensuel — DGAC Arrivées à l\u0026rsquo;aéroport Martinique Aimé Césaire (saisonnalité touristique) 1990–2025, mensuelle Intégrée Hébergements touristiques classés — Atout France Hôtels et résidences classés, chambres et capacité Stock courant Intégrée Capacité des communes en hébergement touristique — INSEE Hôtels par catégorie, campings, résidences, villages vacances 2015–2026, annuelle Intégrée 7 autres — par ex. DATAtourisme (ADN Tourisme), enquête de fréquentation hôtelière (INSEE), Inside Airbnb / AirDNA, données d\u0026rsquo;escales du port Cataloguées Contexte : météo, air, calendrier, sécurité Source Apport Période / fréquence Statut Données climatologiques de base — Météo-France Pluie, température, vent (stations de Fort-de-France Desaix et du Lamentin) 2010–2026, horaire / quotidienne Intégrée Qualité de l\u0026rsquo;air — Madininair NO₂ comme indicateur indirect du trafic, ainsi que PM10, PM2,5, O₃ et H₂S des sargasses Horaire ; NO₂ mensuel 2016–2026 Intégrée Base communale de la délinquance enregistrée — SSMSI Infractions enregistrées 2016–2025, annuelle Intégrée Jours fériés en Martinique — DINUM Calendrier, dont le 22 mai 2006–2031 Intégrée Calendrier scolaire — MENJ Vacances scolaires, dont celles de Carnaval 2017-2018 → 2026-2027 Intégrée Pageviews — Wikimedia Foundation Intérêt en ligne pour Fort-de-France, le Carnaval et le patrimoine 2016–2026, mensuelle Intégrée 4 autres — par ex. lumières nocturnes NASA Black Marble, Google Trends / GDELT, agenda des événements (à constituer) Cataloguées Géographie et fonds de carte Source Apport Période / fréquence Statut Périmètres d\u0026rsquo;étude — projet Centre-ville et centre élargi (provisoires, voir D1) Version 0.1 Intégrée API Découpage administratif (geo.api.gouv.fr) — DINUM / IGN / INSEE Contour de la commune et population légale Courant Intégrée Contours IRIS — IGN / INSEE Maille infracommunale du recensement Couche courante Intégrée BD TOPO — IGN Bâtiments (hauteur, usage), voirie, équipements Éditions trimestrielles Intégrée BD TOPO, bâtiments résidentiels du centre élargi — IGN Usage, hauteur et emprise, pour répartir les ménages dans les bâtiments Édition courante Intégrée Fond de carte vectoriel OpenStreetMap — contributeurs OpenStreetMap Voirie, eau, parcs, littoral dessinés dans l\u0026rsquo;application Courant Intégrée 9 autres — par ex. cadastre Etalab, Base Adresse Nationale, BD ORTHO (IGN), PLU (Géoportail de l\u0026rsquo;Urbanisme), risques naturels (Géorisques) Cataloguées L\u0026rsquo;application « Cœur de ville » L\u0026rsquo;entrepôt s\u0026rsquo;explore dans une application de bureau (Electron, React, ECharts, Leaflet sur OpenStreetMap, DuckDB lisant une copie de l\u0026rsquo;entrepôt). Elle est organisée autour de quelques questions — qui est là, quand, qu\u0026rsquo;est-ce qui attire, le stationnement suffit-il, qui dépend des transports collectifs, le centre gagne-t-il ou perd-il — avec une carte toujours au même endroit, un sélecteur commun jour × créneau, et chaque chiffre accompagné de sa source et de son statut.\nSynthèse — le centre en un coup d\u0026rsquo;œil : rapport jour/nuit, pression de stationnement, commerces 2016 → 2026, pauvreté, prochaine grosse journée d\u0026rsquo;escale, présence au carreau de 200 m et rythme de la journée des résidents, salariés, scolaires et touristes.\nFlux et moments de vie — la présence par carreau pour tout jour et tout créneau, lisible en animation sur la semaine, avec la courbe journalière empilée par population.\nPôles d\u0026rsquo;attractivité — les établissements par famille (répertoire Sirene et OpenStreetMap), les carreaux les plus attractifs au moment choisi et la part d\u0026rsquo;établissements ouverts heure par heure.\nZoom sur un îlot — la façade de la rue numéro par numéro, les établissements actifs et fermés depuis 2016, et l\u0026rsquo;évolution du secteur comparée à l\u0026rsquo;ensemble du centre.\nÉvolution 2016–2026 — l\u0026rsquo;attractivité par carreau avec un curseur d\u0026rsquo;années, les créations et fermetures, les foyers fiscaux et d\u0026rsquo;autres signaux croisés sur la même grille.\nStationnement — l\u0026rsquo;offre reconstruite rue par rue et le taux d\u0026rsquo;occupation théorique par carreau et par créneau ; chaque hypothèse (longueur de place, largeur de voie, part modale…) est un curseur et le résultat est recalculé en SQL.\nPression de stationnement — mardi, 9-12 h : voitures des résidents et des salariés rapportées aux places publiques à 300 m à pied, carreau par carreau. Le tableau de la semaine montre un taux d\u0026rsquo;occupation théorique supérieur à 1 les matinées de semaine, alors que les soirées et le week-end restent nettement en dessous.\nEscales et événements — le calendrier annuel des escales avec les jours fériés et les vacances scolaires, les navires d\u0026rsquo;une journée et l\u0026rsquo;estimation des croisiéristes à terre heure par heure.\nSources et hypothèses — le catalogue derrière chaque chiffre (filtrable par statut), les paramètres de modélisation avec leur justification et les acquisitions archivées.\nRésultats Le projet a démarré en octobre 2026 et en est à un stade précoce, non calé (application v0.6.0). Tous les chiffres relatifs au centre-ville dépendent d\u0026rsquo;un périmètre provisoire (voir ci-dessous). Chaque résultat ci-dessous précise les sources qu\u0026rsquo;il croise : aucun ne pourrait être obtenu à partir d\u0026rsquo;un seul jeu de données.\nCatalogue. 120 sources sont cataloguées, dont 51 intégrées. Entrepôt (première construction). 117 161 entités, environ 25 000 mesures et 1 278 indicateurs, avec les 6 invariants validés. Déclin commercial et résidents (mesuré, registres × recensement × données fiscales). Le nombre d\u0026rsquo;établissements actifs d\u0026rsquo;équipement de la personne (Sirene) est passé de 498 (2016) à 363 (2026), soit une baisse de 27 %, et la part du centre-ville dans la commune pour ce secteur de 75,5 % à 64,7 %. Sur la même période, la population des IRIS du centre-ville (recensement) est passée de 13 444 (2016) à 12 898 (2022), et la vacance des logements de 24,9 % à 27,6 %. 47 % des ménages du centre-ville vivent sous le seuil de pauvreté, contre 30 % pour la commune (Filosofi 2021). Lues ensemble, ces trois sources montrent un centre qui perd en même temps des commerces, des habitants et du pouvoir d\u0026rsquo;achat. Rythme jour/nuit (modélisé, six sources croisées). Environ 3 700 personnes sont présentes la nuit et 11 200 le matin, soit un rapport de 3,0. Les résidents de nuit viennent de Filosofi carroyé 200 m réparti dans les bâtiments BD TOPO ; les salariés de jour, des tranches d\u0026rsquo;effectif Sirene ; les élèves, de l\u0026rsquo;annuaire de l\u0026rsquo;éducation ; les touristes, de la capacité des hébergements classés. Le créneau du matin est ajusté sur le profil horaire du NO₂ aux stations trafic. Vitesse observée des bus et modèle (GTFS-RT × graphe routier × enquêtes de mobilité). Sur une journée complète, les bus roulaient à 12,7 km/h à 5 h, puis à 7 à 8 km/h en journée et à 10,6 km/h à 19 h. Le modèle d\u0026rsquo;affectation, construit à partir des routes BD TOPO, des navettes MOBPRO, des profils de déplacements EMP et des équipements BPE, prévoit un ralentissement de 20 % aux heures de pointe, alors que les bus en montrent 45 %. La mesure révèle ce que le modèle ne voit pas. Contrôle croisière (escales × capacités des navires × effectifs publiés). Les croisiéristes à terre sont modélisés à partir du calendrier des escales et des capacités des navires (CruiseMapper). Pour la seule journée d\u0026rsquo;escale documentée (24 avril 2026), les estimations se sont situées à environ 1 à 2 % des effectifs de passagers publiés dans la presse (3 075 contre 3 112, et 1 995 contre 1 969). Le taux de remplissage du modèle a été fixé sur cette même journée : il s\u0026rsquo;agit donc d\u0026rsquo;un contrôle de cohérence, pas d\u0026rsquo;une validation indépendante. Limites \u0026amp; suite D1 : le périmètre du centre-ville est provisoire. Il s\u0026rsquo;agit d\u0026rsquo;un rectangle autour du noyau historique, complété d\u0026rsquo;une zone élargie de 1 km, utilisé dans l\u0026rsquo;attente d\u0026rsquo;un périmètre officiel. Tous les chiffres relatifs au centre-ville en dépendent. Aucune donnée de comptage piéton, de fréquentation ou de comptage routier n\u0026rsquo;est ouverte. Les rythmes horaires, les poids d\u0026rsquo;attractivité et les hypothèses de stationnement ne sont pas encore calés. Les seuls contrôles mesurés à ce stade sont le NO₂ horaire aux stations trafic et les vitesses observées des bus. Le stock d\u0026rsquo;établissements 2016–2026 est reconstitué uniquement à partir des dates de création et de fermeture. Prochaines étapes : accumuler plusieurs mois de données GTFS-RT pour mesurer la congestion, solliciter des données d\u0026rsquo;enquête et de comptage, et caler la présence sur des comptages de terrain. Stack technique Python · DuckDB (spatial, httpfs) · Parquet · SQL · GTFS / GTFS-RT · pytest · ruff · Electron · React · TypeScript · ECharts · Leaflet · GitHub Actions\n","date":"2026-10-01T00:00:00Z","permalink":"/fr/research/urban-flows-fort-de-france/","title":"Points d'intérêt et flux urbains dans le centre-ville de Fort-de-France à partir de données ouvertes"},{"content":"Contexte Les traces numériques personnelles (messageries, courriels, photos, écoutes musicales, notes, agenda, exports de santé, dépôts de code) comptent parmi les données les plus sensibles qu\u0026rsquo;une personne possède, mais aussi parmi les plus riches pour étudier le comportement — et le ressenti — dans la durée. Les confier à un LLM dans le cloud n\u0026rsquo;est pas acceptable : tout fonctionne donc sur un unique ordinateur de bureau Apple silicon (M4, 32 Go de mémoire unifiée), et aucune donnée ne quitte la machine.\nL\u0026rsquo;objectif est un agent qui réponde à des questions sur sa propre vie tout en maintenant une séparation stricte entre ce qui est observé, ce qui est calculé, ce qui est supposé par un modèle et ce qui est accepté comme vrai par son propriétaire.\nCe qui est original Les agents locaux sur des fichiers personnels ne sont pas nouveaux. Deux aspects de ce projet le sont.\n1. Un graphe de sens au-dessus d\u0026rsquo;une couche de mesure. La connaissance est organisée à deux niveaux. Un observatoire stocke faits et signaux au format long (élément, dimension, valeur, confiance, modèle, version). Au-dessus, un graphe de sens stocke ce que ces signaux signifient : des relations (réifiées, pour qu\u0026rsquo;une relation puisse évoluer et se mesurer), des épisodes affectifs (qui a ressenti quoi, quand, avec quelle intensité, par quelle modalité), des thèmes, des chapitres de vie et des vérités — des énoncés assortis de preuves qui les étayent et de preuves qui les contredisent, que seul le propriétaire peut valider. Chaque nœud et chaque arête porte sa provenance jusqu\u0026rsquo;à l\u0026rsquo;élément source, ainsi qu\u0026rsquo;une origine classée par degré de confiance (humain \u0026gt; déclaré \u0026gt; structurel \u0026gt; règle/calcul \u0026gt; éditeur \u0026gt; modèle \u0026gt; inféré).\n2. Des émotions mesurées à travers les modalités, selon des dimensions atypiques. Le même vocabulaire fixe de 53 émotions (fondé sur Plutchik, chacune dotée de coordonnées de valence et d\u0026rsquo;éveil) s\u0026rsquo;applique aux messages (LLM local), à la voix (cinq couches acoustiques et multimodales fusionnées avec la transcription, avec un signalement explicite du désaccord entre texte et voix) et aux photos (mesures déterministes de couleur et de lumière, plongements SigLIP, signaux de visage traités comme des indices faibles). Ces mesures s\u0026rsquo;inscrivent dans un catalogue de 929 dimensions réparties en 88 groupes, qui va bien au-delà des métadonnées habituelles. Quelques-unes de ses entrées les moins courantes :\nmodalité dimension définition photo température de couleur équilibre moyen rouge–bleu de l\u0026rsquo;image (chaud ou froid) photo colorfulness métrique de couleurs opposées de Hasler \u0026amp; Süsstrunk (2003) photo heure dorée / heure bleue élévation du soleil calculée hors ligne à partir de la date et de la position photo taille du visage part de l\u0026rsquo;image occupée par un visage (indice de proximité) voix jitter, shimmer, rapport harmoniques/bruit prosodie openSMILE eGeMAPS voix rires, pleurs, soupirs détection d\u0026rsquo;événements sonores (classes AudioSet) voix désaccord texte/voix valence de la voix et valence de la transcription écartées d\u0026rsquo;au moins 0,6 message valence, éveil, ton par participant, contraints à la grille fixe message ponctuation expressive, palette d\u0026rsquo;emojis mesures déterministes du texte relation asymétrie de latence de réponse logarithme du rapport des délais médians de réponse des deux parties relation initiatives conversations ouvertes après 3 h de silence, de chaque côté relation tendance pente de l\u0026rsquo;intensité de la relation sur 90 jours (refroidissement \u0026lt; 0) période nostalgie musicale âge moyen des titres écoutés période création / consommation temps passé sur des outils de création ÷ temps de consommation Des signaux au sens flowchart LR PH[\"Photo\"] --\u003e PM[\"Mesureslumière · contraste · température de couleurcolorfulness · palette · netteté\"] PH --\u003e PS[\"Plongement SigLIP(similarité image ↔ texte)\"] PH --\u003e PF[\"Signaux de visage de l'éditeursourire · expression · regard · taille du visage\"] VN[\"Note vocale\"] --\u003e VT[\"Transcription Whisper\"] VN --\u003e VL[\"Couches acoustiquesvalence/éveil/dominance · catégoriesévénements sonores · prosodie · LLM audio\"] VT --\u003e VX[\"Émotion du texte de la transcription\"] VL --\u003e VF[\"Fusion pondéréeconfiance = accordsignalement du désaccord texte/voix\"] VX --\u003e VF MS[\"Messages(pseudonymisés : Moi, P1, P2)\"] --\u003e ML[\"LLM local, grille fixeémotion · intensité · valenceéveil · ton · sujets\"] PM --\u003e OB[(\"Observatoire929 dimensions\")] PS --\u003e OB PF --\u003e OB VF --\u003e OB ML --\u003e OB OB -- \"émotion suffisamment sûre\" --\u003e AFF[\"Épisode affectif (AFF)qui · émotion · quand · intensité · modalité\"] PF -. \"indice faible, confiance ≤ 0,4\" .-\u003e AFF ML -- \"sujets\" --\u003e THM[\"Thèmes\"] OB -- \"agrégats\" --\u003e AG[\"Indicateurs par jour / périodevalence · lumière · palette\"] AFF --\u003e G[\"Graphe de sensrelations · épisodes · thèmes · chapitres · vérités(tous proposés)\"] THM --\u003e G AG --\u003e G G --\u003e HV((\"Propriétairevalider · rejeter · corriger\"))Chaque épisode affectif est un nœud relié à la personne qui l\u0026rsquo;a ressenti, à l\u0026rsquo;émotion du vocabulaire fixe et — lorsqu\u0026rsquo;il existe — à la conversation ou au moment où il s\u0026rsquo;est produit. Des règles d\u0026rsquo;inférence font ensuite remonter l\u0026rsquo;affect (par exemple l\u0026rsquo;affect d\u0026rsquo;un chapitre ou d\u0026rsquo;une routine), et les corrélations fortes entre agrégats peuvent devenir des vérités proposées, avec leurs mesures pour preuves.\nLa mesure des émotions en détail Vocabulaire. La grille est fixe et versionnée : les 8 émotions primaires de Plutchik à 3 intensités, ses 8 dyades primaires, plus des émotions sociales et réflexives utiles à une vie (gratitude, tendresse, fierté, honte, solitude, nostalgie, émerveillement, apaisement, épuisement…), soit 53 au total. Chacune porte des coordonnées de départ dans le modèle circomplexe de Russell — valence dans [−1, 1], éveil dans [0, 1] — destinées à être étalonnées ensuite sur les validations du propriétaire. Les oppositions de Plutchik sont encodées, et les étiquettes d\u0026rsquo;humeur de l\u0026rsquo;application Santé sont rattachées à la grille.\nMessages. Un LLM local (Qwen3-30B-A3B) lit chaque conversation, les participants y étant remplacés par « Moi », « P1 », « P2 », les messages présentés comme des données auxquelles il ne doit pas obéir, et les médias réduits à des repères tels que « [vocal 23 s] ». La sortie est contrainte par un schéma JSON : pour chaque participant, l\u0026rsquo;émotion dominante prise dans la grille (ou aucune), l\u0026rsquo;intensité, la valence, l\u0026rsquo;éveil, un ton choisi dans une liste fermée de 19, et une confiance ; plus 1 à 3 sujets qui deviennent des thèmes. Les longues conversations sont réduites à leur début et à leur fin ; les courtes sont regroupées par dix dans un même appel. Un épisode affectif n\u0026rsquo;est proposé que si la confiance atteint au moins 0,3.\nVoix. Chaque enregistrement est converti en mono 16 kHz puis passe par :\nWhisper large-v3-turbo (MLX) pour la transcription ; un modèle wav2vec2 dimensionnel donnant valence, éveil et dominance sur des fenêtres de 15 s, pondérées par leur durée, ainsi que la variabilité de l\u0026rsquo;éveil ; emotion2vec+ large pour l\u0026rsquo;émotion catégorielle, rattachée à la grille (retenue à partir de 0,4) ; un classifieur AST AudioSet pour les rires, pleurs, soupirs, cris, chuchotements, la musique et l\u0026rsquo;ambiance ; la prosodie openSMILE eGeMAPS : hauteur (en demi-tons) et sa variabilité, intensité sonore, jitter, shimmer, rapport harmoniques/bruit, segments voisés par seconde, durée moyenne des pauses ; Qwen2.5-Omni-7B (llama.cpp, Metal), qui écoute l\u0026rsquo;audio et renvoie une émotion de la grille, une valence et de brefs indices acoustiques ; le modèle d\u0026rsquo;émotion du texte décrit ci-dessus, appliqué à la transcription. Les avis catégoriels (catégories vocales, LLM audio, transcription) sont combinés par un vote pondéré (poids 1,0, 1,0 et 0,8) ; la valence est une moyenne pondérée du modèle dimensionnel, du LLM audio et de la transcription. La confiance correspond à l\u0026rsquo;accord entre les couches : une source d\u0026rsquo;accord donne 0,45, deux donnent 0,65, trois donnent 0,85, moins 0,1 par source en désaccord. Lorsque la voix et les mots divergent d\u0026rsquo;au moins 0,6 en valence (un « ça va » dit tristement), un désaccord texte/voix est signalé au lieu d\u0026rsquo;être noyé dans une moyenne. Les scores de rires et de pleurs sont conservés à côté.\nPhotos. Sur des miniatures de 256 px, sans aucun modèle : luminosité, contraste, saturation, température de couleur, colorfulness, netteté (variance du laplacien) et palette de 5 couleurs avec teinte dominante nommée. Les plongements SigLIP so400m rendent la photothèque interrogeable en texte. Les attributs de visage calculés par l\u0026rsquo;éditeur (sourire, type de sourire, expression, regard, état des yeux, taille du visage) sont lus comme des signaux, mais le schéma pose qu\u0026rsquo;un sourire photographié n\u0026rsquo;est pas une joie ressentie : la modalité visage est un indice faible, dont la confiance est plafonnée à 0,4. L\u0026rsquo;humeur musicale est traitée de la même façon : l\u0026rsquo;humeur d\u0026rsquo;un morceau n\u0026rsquo;est jamais, à elle seule, une preuve de l\u0026rsquo;humeur de l\u0026rsquo;auditeur. À l\u0026rsquo;échelle d\u0026rsquo;une période, la valence est fusionnée selon une priorité fixe : déclarée \u0026gt; voix \u0026gt; texte \u0026gt; visage.\nValidation humaine. Chaque épisode, thème, chapitre ou vérité est émis avec le statut proposed. La PWA présente une file de validation — les épisodes affectifs classés par confiance, accompagnés de leur preuve (la conversation ou l\u0026rsquo;enregistrement d\u0026rsquo;origine) — et le propriétaire valide, rejette ou corrige. Seul cet événement de décision humaine fait passer une proposition à validated, équivalence vérifiée automatiquement. L\u0026rsquo;étape suivante prévue est un petit classifieur personnel sur les caractéristiques emotion2vec, entraîné sur ces validations.\nArchitecture flowchart TB S[\"Sources (instantanés en lecture seule)messageries · courriels · photos · musique · notes · agenda · exports\"] C[\"Connecteursprocessus d'ingestion dédié, seul détenteur de l'accès disque\"] V[\"Coffre (propriétaire seul, 0700)stockage brut adressé par contenu\"] O[\"Observatoirefaits + signaux (SQLite)\"] K[\"Graphe de sensjournal JSONL en ajout seul → repli SQLite + FTS\"] N[\"Chaînes nocturnes / horairesvignettes · mesures · SigLIP · émotions(verrou GPU, un modèle à la fois)\"] M[\"Serveur MCP (stdio, sans port)20 outils en lecture seule / proposition seule\"] H[\"Hermes AgentLLM local via Ollama\"] P[\"PWA (HTTPS + TOTP)discussion · file de validation\"] U((\"Propriétaire\")) S --\u003e C --\u003e V --\u003e O --\u003e K N --\u003e O O --\u003e M K --\u003e M M --\u003e H --\u003e P P -- \"valider / rejeter / corriger\" --\u003e K U -- \"VPN NetBird\" --\u003e PLes données brutes sont capturées sous forme d\u0026rsquo;instantanés (SQLite ouvert en mode=ro\u0026amp;immutable=1) et ne sont jamais modifiées ; tout ce qui en dérive réside dans un coffre distinct, accessible au seul propriétaire, et le dépôt de code ne contient aucune donnée. Le graphe de sens repose sur le module de base de connaissances de la bibliothèque d\u0026rsquo;atomes : un journal d\u0026rsquo;événements JSONL en ajout seul, validé par schéma et replié dans un index SQLite jetable.\nLe schéma est lui-même une donnée, vérifiée mécaniquement : 27 types de nœuds et 50 prédicats, 9 origines de provenance, 31 types de localisateurs qui rattachent chaque assertion à son élément source, le vocabulaire de 53 émotions, 17 règles d\u0026rsquo;inférence et 42 sources derrière les 929 dimensions (610 natives, 126 calculées par les éditeurs, 86 agrégats, 74 mesures déterministes, 29 interprétations de modèles).\nModèle de sécurité Le contenu des sources est supposé hostile (injection de prompt dans un message ou un courriel), et le modèle peut halluciner ou détourner les outils. Les défenses sont structurelles :\nAucune capacité ambiante. Le framework d\u0026rsquo;agent (Hermes Agent) a 20 ensembles d\u0026rsquo;outils intégrés désactivés (terminal, fichiers, exécution de code, web, navigateur, délégation, mémoire, voix dans le cloud…) ; aucun fournisseur cloud, aucune vérification de mise à jour ni connexion externe ; le seul point d\u0026rsquo;accès au modèle est un serveur Ollama en boucle locale. Une interface unique et étroite. Les données ne sont accessibles que par un serveur MCP local via stdio, avec schémas fermés, arguments validés, troncature explicite et journal d\u0026rsquo;accès sans contenu. Les outils peuvent proposer, jamais décider. Séparation des privilèges et pseudonymisation. Seule l\u0026rsquo;ingestion dispose de l\u0026rsquo;accès complet au disque ; l\u0026rsquo;analyse n\u0026rsquo;a pas de réseau. Les tiers sont des codes opaques, et un nom réel dans un identifiant est rejeté par le schéma. Niveaux de sensibilité (0–3) par élément, avec un plafond plus bas pour les sessions à distance ; accès à distance uniquement par VPN NetBird, TOTP et cookies de session stricts. Exclusions éthiques : l\u0026rsquo;origine ethnique, la couleur de peau et le genre inférés par les éditeurs ne sont jamais lus. Modèles Toute l\u0026rsquo;inférence est locale ; un seul grand modèle est chargé à la fois, sous un verrou GPU partagé.\ntâche modèle environnement d\u0026rsquo;exécution agent (usage d\u0026rsquo;outils, contexte ≥ 64k) gpt-oss:20b, qwen3:8b en repli Ollama émotions du texte, émotions des transcriptions vocales Qwen3-30B-A3B-Instruct-2507 (Q4) Ollama plongements texte / image bge-m3 · SigLIP so400m Ollama · PyTorch MPS lecture d\u0026rsquo;images qwen3-vl:8b Ollama transcription de la parole Whisper large-v3-turbo MLX émotion vocale (5 couches) wav2vec2 dimensionnel · emotion2vec+ · AST · openSMILE eGeMAPS · Qwen2.5-Omni-7B PyTorch MPS · CPU · llama.cpp (Metal) Chaque modèle est soumis à un test de validation rapide sur des données synthétiques uniquement (une phrase française fictive synthétisée par une TTS locale, puis passée dans toute la chaîne audio).\nÉvaluation \u0026amp; résultats Qualité des réponses de l\u0026rsquo;agent. Un banc d\u0026rsquo;essai de 16 questions (dont 2 questions pièges), avec une vérité terrain calculée en appelant directement les outils, évalue le choix des outils, la fidélité numérique (chaque nombre de la réponse doit figurer dans les sorties d\u0026rsquo;outils de ce tour), l\u0026rsquo;exactitude, la gestion des pièges et le signalement des périodes partielles : 73 % → 100 % après des corrections des descriptions d\u0026rsquo;outils, de la validation des arguments et de la configuration. Correction des erreurs côté serveur. Avec une interface réduite à 8 outils, les questions simples sont passées de 76 % à 90 % et les questions croisant plusieurs sources de 73 % à 90 % ; 20 questions délibérément inhabituelles ont obtenu 89 % et mis au jour des échecs silencieux renvoyant zéro, corrigés depuis. Contexte et latence. Descriptions d\u0026rsquo;outils réduites de 23,5 k à 9,5 k caractères ; une requête d\u0026rsquo;agrégation lourde passée de 172 s à 0,1 s ; toutes les requêtes lourdes du banc d\u0026rsquo;essai en ≤ 0,3 s. Banc d\u0026rsquo;essai d\u0026rsquo;exploration croisée. 60 scénarios écrits uniquement avec des valeurs fictives, chacun doté d\u0026rsquo;un oracle ; les oracles passent 61/61, sans aucune fuite aux plafonds de sensibilité à distance 1 et 2. Vérification. 56 contrôles de schéma nommés au vert ; 631 colonnes natives/éditeurs confirmées par rapport aux structures réelles des bases ; 1 235 tests unitaires Python, 15 fichiers de tests JavaScript et 110 tests de qualité sur données réelles qui ne rapportent que des comptages. Limites \u0026amp; suite Les jeux d\u0026rsquo;évaluation sont restreints et rédigés par le concepteur du système ; ils mesurent la fidélité et les régressions plutôt que la capacité générale. Les sorties émotionnelles sont des hypothèses : les coordonnées de valence et d\u0026rsquo;éveil du vocabulaire sont des valeurs de départ, et le calibrage personnel de l\u0026rsquo;émotion vocale à partir d\u0026rsquo;exemples validés reste à réaliser, de même que le modèle d\u0026rsquo;agent cible, plus grand. Les réponses de l\u0026rsquo;agent prennent plusieurs dizaines de secondes avec un modèle de 20B.\nStack technique Python · SQLite / FTS5 · Ollama · llama.cpp (Metal) · MLX · PyTorch MPS · Hermes Agent · MCP · SigLIP · Whisper · emotion2vec · openSMILE · NetBird · PWA · launchd\n","date":"2026-10-01T00:00:00Z","permalink":"/fr/research/local-ai-agent/","title":"Un agent IA entièrement local, avec graphe de sens et mesure multimodale des émotions"},{"content":"Contexte Des systèmes de production pour le rapprochement documentaire et l\u0026rsquo;OCR, développés pour des clients tels qu\u0026rsquo;un grossiste distributeur et un cabinet d\u0026rsquo;expertise comptable, ont laissé plusieurs bases de code résolvant chacune les mêmes sous-problèmes (routage des pages, réglage de l\u0026rsquo;OCR, extraction par LLM, comparaison de champs) avec leurs propres bogues. La bibliothèque d\u0026rsquo;atomes les consolide en un seul paquet. Sa question centrale est celle qui sous-tendait les systèmes d\u0026rsquo;origine : peut-on automatiser un contrôle documentaire de sorte qu\u0026rsquo;un humain puisse auditer et contester chaque verdict ? Extraire un champ ne suffit pas. Le système doit indiquer si deux documents concordent, pourquoi, et sur la base de quels éléments.\nApproche Tout est construit à partir d\u0026rsquo;atomes. Un atome a une seule responsabilité, des entrées et sorties typées, aucun état global et des dépendances injectées (client LLM, moteur OCR, stockage). Une chaîne de traitement est une composition d\u0026rsquo;atomes, soit écrite en code, soit déclarée sous forme de recette YAML validée au chargement, avant toute exécution.\nflowchart TB A[\"Documents d'entrée (PDF, numérisations, CSV, courriels)\"] --\u003e B{\"Routage des pages : texte natif ou OCR ?\"} B -- \"natif\" --\u003e C[\"Texte natif positionné\"] B -- \"numérisation\" --\u003e D[\"PaddleOCR (réglages de production)\"] C --\u003e E[\"Segmentation \u0026 classification\"] D --\u003e E E --\u003e F[\"Extraction JSON par LLM + vérification d'ancrage verbatim\"] F --\u003e G[\"Rapprochement inter-documents (facture / bon de livraison / commande)\"] G --\u003e H[\"Verdict tri-état + motif nommé + trace\"] H --\u003e I[\"Rapport / revue humaine\"]Le catalogue Les 459 atomes sont regroupés en 32 familles, un paquet Python chacune, rangées le long de la chaîne de traitement : capter le monde, le comprendre, rapprocher et décider, restituer, puis exploiter en production. Deux paquets supplémentaires les assemblent : steps (77 étapes nommées et paramétrées) et recipes (chargement et validation des recettes YAML).\nSérie Famille Atomes Rôle Socle core 25 types pivots, chaîne de traitement, configuration, résilience (reprises, limites de débit), fichiers, concurrence Capter connect 40 HTTP résilient, boîtes aux lettres (Graph, IMAP), SFTP, OneDrive, source ERP en lecture seule, données ouvertes, piste d\u0026rsquo;audit google 24 Gmail, Sheets, Drive, Apps Script, avec exécution résiliente web 17 robots web indépendants du pilote (Selenium, Playwright) : attentes, squelette à reprise, formulaires pdf 9 texte natif positionné, décision d\u0026rsquo;OCR, rendu, pages, doublons ocr 9 PaddleOCR avec réglages de production, EasyOCR layout 3 géométrie de page : lignes, colonnes, redressement, rendu monospace audio 16 transcription par morceaux, post-traitement des segments, recalage micro ↔ écran vision 32 flux vidéo / RTSP, détection, suivi, profondeur, segmentation, calibration vlm 10 lecture d\u0026rsquo;écran par modèle de vision-langage : détection de changement, localisation de libellés geo 11 mesures géodésiques, position combinée de relevés GPS, filtrage par distance aux lignes, SQL spatial calendar 4 jours fériés, jours et horaires ouvrés Comprendre text 32 nombres et montants, dates, normalisation, champs par motifs, identifiants segment 7 pages → documents logiques, numéros de pièce typés, nature de page classify 12 classement par nom de fichier, expéditeur, motifs pondérés, TF-IDF, visuel, LLM, cascades llm 24 contrat indépendant du fournisseur, fournisseurs, pool, prompts, extraction structurée anchor 5 champs et tableaux situés par rapport aux libellés imprimés, texte natif ou OCR kb 8 base de connaissances tracée : journal d\u0026rsquo;événements validé, replié en index SQLite Rapprocher match 25 EAN/GTIN, index, score multicritère, affectation optimale, résolution d\u0026rsquo;entités compare 9 comparateurs tri-états et explicables de champs, d\u0026rsquo;enregistrements et d\u0026rsquo;ensembles check 9 contrôles génériques tri-états : totaux, TVA, balance, complétude, vraisemblance reconcile 12 appariement d\u0026rsquo;ensembles, chaînes commande → livraison → facture, N-voies, lettrage, rapprochement bancaire validate 14 moteur de règles, identifiants, cohérence des montants, verdicts LLM corrigés, décision finale rules 8 langage de conditions sûr, tables « premier match » explicables, escalade, machines à états events 11 événements horodatés : fenêtres, veille des événements attendus, sessions, transitions de statut analytics 18 analyses supply chain sans pandas : demande, ruptures, taux de service, stock de sécurité Restituer export 8 CSV pour Excel FR, classeurs Excel partagés, rapports HTML / Markdown / PDF report 6 écarts persistables, synthèses, file de revue render 12 livrables HTML : diagrammes Mermaid pré-rendus, graphiques ECharts, cartes GeoJSON diagram 6 diagrammes de processus : lecture draw.io / BPMN JSON, rendu Mermaid et BPMN XML Exploiter ops 26 haute disponibilité (battements, élection), démon à déclencheurs horaires, surveillance, contrôles préalables qa 7 non-régression rédactionnelle (fichiers dorés), rejeu de simulations, accord inter-annotateurs Recettes nommées Chacune des 17 recettes est une liste YAML d\u0026rsquo;étapes nommées \u0026lt;famille\u0026gt;.\u0026lt;atome\u0026gt;. Trois exemples :\ninvoice_multi_doc : un lot de PDF multidocuments devient un ensemble de documents logiques contrôlés. io.collect → pdf.read → segment.documents → classify.documents → llm.extract → validate.ids → validate.amounts → validate.decide → export.csv → google.sheets.upsert → connect.notify. Chaque document finit valide, à vérifier ou invalide. doc_reconciliation : un dossier de factures, d\u0026rsquo;avoirs et de bons de livraison, contrôlé par rapport aux commandes. L\u0026rsquo;extraction LLM gardée (llm.extract_docs) est recoupée avec une extraction par motifs (extract.regex, compare.extractions, reconcile.fields), puis viennent check.document et check.completeness, les lignes face à la commande (compare.reference), la chaîne commande → livraison → facture (reconcile.nway), et enfin un fichier d\u0026rsquo;écarts et une file de revue (report.discrepancies, report.review). 17 étapes. meeting_transcript : un enregistrement de réunion devient une transcription horodatée avec locuteurs. audio.decode → audio.vad → audio.transcribe → audio.diarize → audio.speakers → audio.segments → export.csv → export.transcript → connect.notify. Les autres sont notamment delivery_vs_order, ledger_reconciliation, invoice_dedup, article_base_cleaning, stock_policy, mail_to_sheet, draft_mails, pdf_text_extract, rubric_eval, screen_session, camera_flow et process_from_transcript.\nL\u0026rsquo;Atlas L\u0026rsquo;Atlas est une page HTML unique, consultable hors ligne, générée à partir du code lui-même (arbres syntaxiques et YAML), sans aucune donnée saisie à la main. Il dessine le catalogue comme un tableau périodique : chaque famille est un élément doté d\u0026rsquo;un symbole, chaque module un atome, chaque recette une molécule. Il signale aussi les atomes sans documentation, sans test ou sans exemple d\u0026rsquo;usage.\nLa série « Capter » du tableau périodique. Chaque case est une famille, avec son symbole, son nombre de modules et sa taille en milliers de lignes ; chaque tuile en dessous est un atome.\nLa série « Rapprocher » : les familles qui apparient, comparent, contrôlent et décident.\nLa fiche d\u0026rsquo;un atome (compare.fields) : à quoi il sert, d\u0026rsquo;après sa docstring, puis chaque nom public avec sa signature complète.\nLa recette invoice_multi_doc en molécule : 11 étapes, les clés de contexte qui les relient et les services requis (en pointillé lorsqu\u0026rsquo;ils sont facultatifs).\nMéthodes Résultats tri-états. Chaque comparaison renvoie ok ∈ {True, False, None} (conforme / écart / non concluant) avec un code de motif nommé et une trace. Une valeur manquante ou illisible compte comme non concluante, jamais comme une anomalie. Les résultats non concluants sont tout de même comptabilisés, et non écartés en silence. Routage hybride texte natif/OCR. Chaque page PDF est classée comme native, OCR ou vide, selon la quantité de texte natif qu\u0026rsquo;elle contient et la part de ce texte couverte par des images. L\u0026rsquo;OCR n\u0026rsquo;est exécuté que là où il est nécessaire. Extraction LLM ancrée. L\u0026rsquo;extraction JSON structurée est validée par rapport à des schémas Pydantic. Chaque valeur extraite est ensuite vérifiée mot pour mot dans le texte source, de sorte que les valeurs altérées ou inventées sont signalées. Rapprochement inter-documents. Factures, bons de livraison et commandes sont comparés ligne à ligne à l\u0026rsquo;aide de tolérances nommées et de règles de dominance. Par exemple, un montant de ligne concordant peut l\u0026rsquo;emporter sur un écart de prix. Provenance. Chaque atome porté comporte un en-tête Provenance: et une entrée qui le relie à repo@commit:path:lines dans le code de production d\u0026rsquo;origine. Les bogues découverts lors du portage ont été corrigés, et chaque correction est couverte par un test de non-régression. Architecture contrôlée. Le découpage en couches est vérifié par 30 contrats d\u0026rsquo;import : un atome n\u0026rsquo;importe que le paquet core. Un typage strict, un seuil de couverture ≥ 80 % et une vérification de l\u0026rsquo;absence de noms de clients dans le code source sont également imposés. Abstraction du matériel. Les atomes de vision et d\u0026rsquo;audio ciblent cuda, mps ou cpu via un seul paramètre. Évaluation de bout en bout. Les tests s\u0026rsquo;exécutent avec de vrais moteurs (PaddleOCR, Ollama qwen3:8b et qwen3-vl:8b) sur des données à vérité terrain connue. Chaque métrique est consignée face à un seuil dans un rapport JSON/HTML. Les métriques qui n\u0026rsquo;atteignent pas leur seuil sont conservées et affichées comme en échec. Résultats Base de code (arborescence actuelle) : 459 modules d\u0026rsquo;atomes répartis en 32 familles, 77 étapes paramétrées, 17 recettes YAML, 30 contrats d\u0026rsquo;import. La suite collecte 2 959 tests unitaires et de recettes, plus 109 tests de bout en bout exécutés séparément. Les 17 recettes disposent toutes d\u0026rsquo;au moins un test de bout en bout, et 34 des 35 éléments de l\u0026rsquo;Atlas sont testés de bout en bout.\nScores de bout en bout sélectionnés (documents synthétiques à vérité terrain connue, modèles 8B locaux) :\nTâche Moteur Mesure Rapprochement facture + bon de livraison / commande qwen3:8b types de documents et champs 14/14 ; écarts attendus 5/5 ; 0 faux écart sur le cas conforme Extraction JSON par LLM (4 factures natives) qwen3:8b JSON valide 4/4 ; champs exacts 28/28 ; toutes les valeurs volontairement altérées détectées par l\u0026rsquo;ancrage OCR sur une étiquette photographiée PaddleOCR rappel des mots 0,94 sur la photo brute ; un défaut de rehaussement du contraste (0,65–0,71) a été identifié et corrigé (0,88–0,94) Reconstruction de tableaux à partir de l\u0026rsquo;OCR PaddleOCR 100 % de cellules exactes (police proportionnelle), 95 % (chasse fixe) Limites \u0026amp; suite L\u0026rsquo;ancrage verbatim ne peut pas détecter une valeur présente dans le document mais placée dans le mauvais champ : un champ absent a été rempli à tort dans 1 cas sur 8. Le modèle 8B a jugé un écart de quantité de +50 % comme un écart « mineur », contrairement à la consigne. Les verdicts du LLM sont donc normalisés et maintenus en aval de règles déterministes. Les scores proviennent principalement de données synthétiques. Un jeu de test sur documents réels est en cours de constitution en dehors du dépôt, et seuls les cas ayant fait l\u0026rsquo;objet d\u0026rsquo;une revue sont notés. Prochaines étapes : mesurer le taux de rapprochement automatique et le taux de faux positifs sur des données de production. Stack technique Python · Pydantic · PyYAML · PaddleOCR · Ollama (qwen3:8b, qwen3-vl:8b) · Mistral / Anthropic / OpenAI APIs · pytest · mypy · import-linter · ruff\n","date":"2026-09-01T00:00:00Z","permalink":"/fr/research/processing-atoms/","title":"Atomes de traitement explicables pour documents et données"},{"content":"Contexte Les médias numériques grand public se dégradent à l\u0026rsquo;échelle de quelques années. Les SSD non alimentés perdent leur charge, les disques optiques se délaminent, les formats tombent en désuétude et les comptes sont fermés. Le papier peut durer des siècles, ne nécessite aucune électricité et peut être vérifié à l\u0026rsquo;œil nu. La question est de savoir quelle quantité d\u0026rsquo;information une feuille A4 ordinaire peut contenir si elle doit encore pouvoir être relue de façon fiable avec un scanner à plat standard, sans matériel spécialisé.\nLe problème est difficile car le canal impression-numérisation est bruité de plusieurs manières à la fois. Le toner s\u0026rsquo;étale et forme des amas, la densité varie sur la page, et les scanners introduisent rotation, mise à l\u0026rsquo;échelle anisotrope, entraînement irrégulier du papier, flou, vignettage et gamma. Le papier se déforme aussi de façon non linéaire : à la densité visée, un étirement de 0,2 % décale la grille d\u0026rsquo;environ trois cellules. Les codes 2D courants comme QR et DataMatrix sont conçus pour la robustesse plutôt que pour la densité. Une archive à long terme doit en outre rester décodable lorsque les logiciels actuels auront disparu.\nApproche flowchart TB A[\"Médias sources : photo, vidéo, voix, texte\"] --\u003e B[\"Réduction conservatrice des formatsJPEG baseline · AVI MJPEG/PCM · WAV PCM · UTF-8\"] B --\u003e C[\"Archive : tar + zlib + SHA-256\"] C --\u003e D[\"Code à effacement inter-pagesMDS de Cauchy sur GF(256) : K pages quelconques parmi N\"] D --\u003e E[\"Reed–Solomon + CRC-32 par blocentrelacement sur la page, en-tête triplé\"] E --\u003e F[\"Rendu de cellules multiniveauxPDF A4 1 bit à 1200 dpi\"] F --\u003e G[\"Impression → numérisation(canal simulé)\"] G --\u003e H[\"Repères → homographie → marqueurs d'alignement locaux\"] H --\u003e I[\"Calibration des niveaux de gris à partir de la page elle-même\"] I --\u003e J[\"Décodage RS/CRC → décodage d'effacement → contrôle SHA-256\"] J --\u003e K[\"Fichiers identiques à l'octet près, ou récupération partielle\"] F -.-\u003e L[\"Annexe imprimée : spécification du format + source du décodeur en OCR-B avec CRC-16 par ligne\"] L -.-\u003e J À gauche : la page 1 sur 10 de l\u0026rsquo;archive photo, telle qu\u0026rsquo;envoyée à l\u0026rsquo;imprimante (A4, 1200 dpi, une grille de 1 145 × 1 576 cellules), réduite. À droite : le coin supérieur gauche encadré, à la résolution de l\u0026rsquo;imprimante (environ 10 × 9 mm, chaque point d\u0026rsquo;imprimante dessiné en 2 × 2 pixels) : le repère d\u0026rsquo;angle plein, le début du bandeau d\u0026rsquo;en-tête et les premières cellules de données. Chaque cellule mesure 8 × 8 points (0,169 mm) et son nombre de points encrés code l\u0026rsquo;un des 4 niveaux. Le carré situé au coin de la grille est un marqueur d\u0026rsquo;alignement.\nUne page de l\u0026rsquo;annexe imprimée (page 11 sur 30) : le début de cdx_read.py (360 lignes), composé en OCR-B. Chaque ligne porte son numéro et son CRC-16 : une ligne mal relue par l\u0026rsquo;OCR peut ainsi être repérée et vérifiée à la main.\nMéthodes Cellules multiniveaux plutôt que modules binaires. Chaque cellule porte 2 bits. Les cellules sont dessinées sous forme de points groupés à la résolution native de l\u0026rsquo;imprimante, de sorte que le pilote n\u0026rsquo;effectue aucun tramage et ne produit aucun moiré. Récupération de la géométrie par étapes. Quatre repères d\u0026rsquo;angle, dont l\u0026rsquo;un est creux pour fixer l\u0026rsquo;orientation, donnent une homographie globale. Des marqueurs d\u0026rsquo;alignement répartis sur la page absorbent ensuite l\u0026rsquo;étirement local et non linéaire du papier. Lecteur auto-calibré. Le décodeur estime les niveaux de gris imprimés et l\u0026rsquo;ombrage spatial à partir de structures de calibration présentes sur chaque page ; il ne dépend donc pas des réglages de points de l\u0026rsquo;imprimante. Contrôle d\u0026rsquo;erreurs à deux niveaux, un code produit. Reed–Solomon et CRC-32 à l\u0026rsquo;intérieur de chaque page corrigent les erreurs aléatoires et en rafale, comme les taches et les rayures. Un code à effacement MDS de Cauchy entre les pages, décodé bloc par bloc, permet à K pages quelconques parmi N de reconstruire une archive. Dégradation progressive. Si le contrôle SHA-256 échoue, le décodeur extrait malgré tout chaque fichier complet situé avant la zone endommagée. Archive autodescriptive. Une annexe imprimée contient la spécification du format, une procédure de lecture et le code source complet du décodeur en OCR-B, avec un numéro de ligne et un CRC-16 sur chaque ligne. Le décodeur ne nécessite que NumPy, Pillow et reedsolo. Le texte utilise DEFLATE (zlib), qui peut être réimplémenté en quelques centaines de lignes, plutôt que LZMA, plus performant. Prototype antérieur (codex_proto/). Cette version explorait plusieurs supports physiques : papier, acier inoxydable gravé au laser, plaques en taille-douce et images de microfilm. Elle utilisait des cellules de 2 à 16 niveaux, des pages de parité de type fontaine, des lecteurs de niveaux de gris à base de MLP, un calculateur optique imprimé pour la lecture des microfilms, ainsi qu\u0026rsquo;une réduction des médias avec pertes (codage paramétrique de la voix, codage des photos par résidus d\u0026rsquo;ondelettes). Résultats Tous les chiffres ci-dessous proviennent uniquement de simulations. Le logiciel modélise les défauts laser (flou du spot, grain du toner, engraissement du point, effet de bandes, densité non uniforme, papier texturé), les défauts du scanner (rotation de ±1,2°, échelle x/y de ±0,3 %, oscillation de l\u0026rsquo;entraînement, flou, vignettage, bruit, gamma 2,2), des taches de café, des rayures et une page volontairement perdue par archive. Aucun essai physique d\u0026rsquo;impression et de numérisation n\u0026rsquo;a encore été réalisé.\nCharge utile nette : 383 469 octets par page A4, soit environ 59 bits/mm². De bout en bout : 46 pages sur 50 ont été numérisées et les 4 archives sur 4 ont été restaurées à l\u0026rsquo;identique, octet pour octet (photo, vidéo, voix, texte). Aucun mot de code Reed–Solomon n\u0026rsquo;a échoué et aucun bloc inter-pages n\u0026rsquo;a été perdu. Taux d\u0026rsquo;erreur : les pages propres ont nécessité la correction d\u0026rsquo;environ 0,007–0,008 % des octets. Les pages tachées et/ou rayées en ont nécessité au plus 0,90 %. Taille des archives : photo 2,86 Mo → 10 pages (8 de données + 2 de parité) ; vidéo (800×600, 24 s, MJPEG + PCM 16 kHz) 8,30 Mo → 25 pages ; voix 0,91 Mo → 5 pages ; texte 5,58 Mo → 10 pages. Texte : les Mémoires d\u0026rsquo;outre-tombe, dans le domaine public (5,43 millions de caractères), occuperaient 1 357 pages A4 composées. Encodées, elles tiennent sur 6 pages de données, soit un rapport d\u0026rsquo;environ 226. zlib compresse cette prose d\u0026rsquo;un facteur 2,62 et LZMA d\u0026rsquo;un facteur 3,58. Récupération partielle : une archive tronquée au quart de sa longueur a encore restitué 1,42 Mo des 5,58 Mo de texte. Robustesse du décodeur : le décodeur a également fonctionné sur des numérisations tournées de 90° et 180°, sur des numérisations à 600 dpi et sur des numérisations JPEG (q92). Taille du décodeur : 731 lignes de Python pour les modules du décodeur imprimé. La même zone de la page photo (380 × 300 points, environ 8 × 6,4 mm), agrandie. À gauche : telle qu\u0026rsquo;encodée. À droite : après le canal impression-numérisation simulé, rééchantillonnée sur la grille de la page grâce à l\u0026rsquo;homographie des repères. L\u0026rsquo;étalement du toner, le flou et le bruit adoucissent les cellules, et le bord d\u0026rsquo;une tache de café simulée assombrit la partie gauche. Le lecteur calibre les niveaux de gris localement et distingue donc encore les quatre niveaux. Dans la simulation présentée ci-dessus, les pages tachées ou rayées ont nécessité la correction d\u0026rsquo;au plus 0,90 % des octets.\nL\u0026rsquo;archive vidéo : un plan sous-marin (banc de poissons au-dessus d\u0026rsquo;un récif) servant de séquence de test. En haut : les images originales HEVC 3840 × 2880 à 3,2 s, 12,8 s et 16,0 s, réduites. En bas : les mêmes instants, décodés à partir des numérisations simulées des 25 pages (dont une volontairement perdue). Le canal papier lui-même ne perd rien : l\u0026rsquo;AVI restitué est identique, octet pour octet, à l\u0026rsquo;AVI archivé. Ce qui diffère de l\u0026rsquo;original, c\u0026rsquo;est la réduction faite avant l\u0026rsquo;impression (MJPEG 800 × 600, 12,5 images/s, son mono 16 kHz) pour que 24 s de vidéo tiennent en 8,30 Mo.\nGros plan sur l\u0026rsquo;image à 12,8 s. À gauche : une zone de 1 152 × 864 pixels de l\u0026rsquo;original, réduite. À droite : la zone correspondante de 240 × 180 pixels de l\u0026rsquo;image restituée, agrandie sans lissage. Les poissons et le récif restent reconnaissables. La texture fine et les nuances de couleur sont perdues, et des blocs MJPEG apparaissent. C\u0026rsquo;est le prix à payer pour faire tenir le plan en 25 pages.\nLimites \u0026amp; suite Pas encore d\u0026rsquo;essai physique. Les motifs de points des cellules ont été ajustés en simulation. La prochaine étape est une impression réelle à 1200 dpi avec une numérisation à 1200 dpi, afin de les régler et de mesurer la marge d\u0026rsquo;erreur effective. Jeu de test restreint. La simulation couvre une seule exécution sur quatre archives. Un balayage en fonction de la sévérité des défauts, de la résolution de numérisation et du type de papier reste nécessaire. Propriétés physiques non mesurées. Le vieillissement à long terme du papier et du toner, ainsi que la faisabilité pratique de la relecture OCR du décodeur depuis le papier, n\u0026rsquo;ont pas été mesurés. Dépendance à une police. Le corps de texte de l\u0026rsquo;annexe repose sur une police système. Stack technique Python · NumPy · SciPy · Pillow · reedsolo · ReportLab · soundfile · ffmpeg · Tesseract (OCR-B)\n","date":"2026-09-01T00:00:00Z","permalink":"/fr/research/codex-paper-archive/","title":"Codex — archivage physique haute densité de médias sur papier"},{"content":"Contexte Le conseil en observation des processus produit des logigrammes, des notes d\u0026rsquo;entretien, des enregistrements d\u0026rsquo;écran et des recommandations. Une fois la mission livrée, ce matériau est de fait inerte : la mission suivante repart d\u0026rsquo;une page blanche, même lorsque la réponse avait déjà été trouvée ailleurs. La question de recherche est de savoir comment transformer les livrables, de documents en données typées, sourcées et interrogeables, afin qu\u0026rsquo;un assistant puisse répondre à « où avons-nous déjà vu cela, et qu\u0026rsquo;en avions-nous conclu ? » en citant des preuves vérifiables.\nDeux exigences structurent le travail : la traçabilité (chaque assertion renvoie à sa preuve) et une stricte séparation entre preuve et connaissance (ce qui a été observé n\u0026rsquo;est pas ce qui a été généralisé). La génération augmentée par la recherche (RAG) est rapide à mettre en place, mais cite des passages, pas des assertions vérifiables ; une ontologie formelle est traçable, mais coûteuse. Ce projet explore une voie pragmatique entre les deux.\nApproche flowchart TB A[\"`Sources brutes de mission immuables, hachées`\"] --\u003e B[\"`Journal d'événements en ajout seul source de vérité`\"] B --\u003e C[\"`Base SQLite reconstructible jetable`\"] C --\u003e D[Extraction déterministe] C --\u003e E[\"`Extraction par LLM simple force de proposition`\"] D --\u003e F[\"`Nœuds et arêtes proposés avec provenance`\"] E --\u003e F F --\u003e G{\"`Revue humaine hors MCP`\"} G --\u003e|validé| H[Graphe de connaissances] H --\u003e I[MCP : preuves] H --\u003e J[MCP : connaissances] H --\u003e K[MCP : ontologie] I --\u003e L[Assistant IA] J --\u003e L K --\u003e LLe choix de conception central consiste à scinder l\u0026rsquo;interface en trois serveurs MCP selon le statut épistémique : preuves (observations attestées et sourcées), connaissances (généralisations) et ontologie (le méta-modèle lui-même). Cette séparation empêche un assistant de présenter une généralisation comme une observation.\nflowchart TB subgraph SCHEMA[\"SCHÉMA · nommage\"] ON[\"`serveur ontologie Comment le nomme-t-on ?`\"] end subgraph PROVEN[\"PROUVÉ · observé\"] EV[\"`serveur preuves Qu'a-t-on capté, et où ?`\"] end subgraph GENERAL[\"GÉNÉRALISÉ · conclu\"] KN[\"`serveur connaissances Qu'en conclut-on ? propose, ne valide jamais`\"] end ON -. \"type\" .-\u003e EV EV == \"fonde chaque conclusion\" ==\u003e KN EV --\u003e AI[\"`Assistant IA réponses étiquetées par statut`\"] KN --\u003e AI ON --\u003e AILe graphe est unique ; seules les façades sont séparées. La frontière qui compte passe entre preuves et connaissances : le serveur preuves ne renvoie que ce qui a été observé, et où ; le serveur connaissances renvoie des conclusions qui doivent remonter jusqu\u0026rsquo;à ces preuves, et aucun outil MCP ne peut marquer quoi que ce soit comme validé.\nMéthodes Méta-modèle. Un noyau fixe, complété de profils de mission et d\u0026rsquo;une ontologie versionnée (v0). Chaque nœud porte une origine (structurelle, déterministe, extraite par LLM) et un statut (proposé → validé). Invariants (I1–I6). La provenance est obligatoire sur chaque nœud et chaque arête dérivés ; une recommandation doit pouvoir être rattachée, de proche en proche, à un constat sourcé ; les citations extraites par LLM doivent être des sous-chaînes littérales de leur fragment ; le statut « validé » exige une décision humaine enregistrée. Les sources brutes sont immuables ; la base de données est jetable et reconstruite à partir du journal. Questions de compétence avant l\u0026rsquo;implémentation. Un jeu v0 de 33 questions, typées comme factuelles, agrégées, de traçabilité, de contradiction, temporelles, inter-missions et négatives (requêtes que le système doit refuser, par exemple une fuite entre clients), dans un format exécutable avec réponses attendues et références. Protocole d\u0026rsquo;évaluation. Au moins 30 tâches en langage naturel, notées automatiquement ou par un juge. Les seuils de passage ont été fixés en amont : exactitude ≥ 0,8, citations valides ≥ 0,98, ancrage ≥ 0,95, fuite = 0, médiane ≤ 6 appels d\u0026rsquo;outils par tâche ; chaque question soluble en ≤ 3 appels ; précision de l\u0026rsquo;extraction déterministe ≥ 0,95 par type ; κ inter-annotateurs ≥ 0,7. Phases P0–P6 avec jalons humains. L\u0026rsquo;implémentation est déléguée à une session d\u0026rsquo;agent qui doit s\u0026rsquo;arrêter à chaque jalon et consigner les décisions en suspens. Cartographie d\u0026rsquo;un logiciel en boîte noire. La même méthode a été appliquée à un logiciel commercial de gestion d\u0026rsquo;entreprise, sans lecture de son code source. La cible est un triplet de vérités — utilisateur, logiciel et base de données — reliées par des arêtes prouvées. Onze heuristiques (H1–H11) couvrent l\u0026rsquo;appariement de valeurs, la perturbation inverse et directe, les champs calculés, la visibilité conditionnelle, les différences entre scénarios, la fouille d\u0026rsquo;invariants, le fuzzing des saisies, les a priori sémantiques (jamais considérés comme preuve), le passage de la documentation au test et du symptôme à la règle. Entrées : l\u0026rsquo;arborescence des menus via AT-SPI, un relevé des écrans, le profilage des colonnes et une typologie d\u0026rsquo;événements issue du journal d\u0026rsquo;audit de l\u0026rsquo;application. Une hypothèse n\u0026rsquo;est acceptée qu\u0026rsquo;avec une contre-preuve indépendante ; les cartographies produites par l\u0026rsquo;éditeur sont tenues en quarantaine et servent d\u0026rsquo;oracle de notation. Un extrait illustratif du graphe typé (libellés fictifs) : la préconisation n\u0026rsquo;est recevable que parce que la chaîne qui descend jusqu\u0026rsquo;à un fragment littéral d\u0026rsquo;une source est complète.\nflowchart TB R[\"`Préconisation point de saisie unique`\"] -- répond à --\u003e C[\"`Constat double saisie à la réception`\"] O[\"`Observation « le stock est ressaisi à la main »`\"] -- atteste --\u003e C O -- extrait de --\u003e F[\"`Fragment notes d'entretien, lignes 40–52`\"] F -- cite --\u003e P[\"`Pièce source hachée, immuable`\"] C -- porte sur --\u003e A[\"`Activité réception des marchandises`\"] A -- utilise --\u003e S[\"`Écran formulaire de réception`\"] S -- module de --\u003e Y[\"`Système logiciel de gestion`\"]État d\u0026rsquo;avancement \u0026amp; résultats Il s\u0026rsquo;agit principalement d\u0026rsquo;une conception partiellement implémentée, et non d\u0026rsquo;un système en service.\nPilote (corpus d\u0026rsquo;observation, passe déterministe). 6 195 fichiers (6,92 Go) acquis de manière idempotente ; 13 272 nœuds et 6 022 arêtes extraits en 2,1 s pour un coût LLM nul ; les six invariants au vert sur 57 969 vérifications. Mesure sur jeu de référence. 145 unités d\u0026rsquo;annotation et 100 paires de résolution d\u0026rsquo;entités. L\u0026rsquo;annotation humaine était partielle et le second annotateur était un LLM. Accord humain × LLM : κ = 0,72 (logiciel), 0,41 (écran), 0,31 (catégorie), 0,52 (limites de segments). Précision de l\u0026rsquo;extracteur par rapport à la référence humaine : 0,74, 0,43, 0,04, 0,63. Jalon G2 (≥ 0,95) non franchi ; le résultat sur la catégorie traduit un désaccord de définition, et non une erreur de calcul. Cartographie du logiciel. Schéma de 427 tables sans aucune clé étrangère, aucun déclencheur ni aucune vue déclarés (toute la logique est applicative) ; 1 048 entrées de menu (899 feuilles) cartographiées ; 154 des 899 écrans relevés (17 %) ; 2 845 hypothèses de règles ramenées à 1 519 par un filtre LLM local, avec 1 erreur de décision sur un échantillon de 50 éléments revu par l\u0026rsquo;agent superviseur. Un prototype MCP en lecture seule existe ; aucune règle n\u0026rsquo;a encore été prouvée dans le logiciel. Les travaux ont été suspendus après une surcharge de la VM hôte. Mesure sur jeu de référence face aux seuils fixés à l\u0026rsquo;avance : les barres sont les valeurs mesurées par champ, la ligne orange est le seuil. Une seule barre le franchit.\n--- config: xyChart: width: 540 height: 320 themeVariables: xyChart: backgroundColor: \"transparent\" plotColorPalette: \"#3F86B8, #C46A2B\" --- xychart-beta title \"Accord humain × LLM, κ (seuil 0,7)\" x-axis [\"logiciel\", \"écran\", \"catégorie\", \"segments\"] y-axis \"κ\" 0 --\u003e 1 bar [0.72, 0.41, 0.31, 0.52] line [0.7, 0.7, 0.7, 0.7]--- config: xyChart: width: 540 height: 320 themeVariables: xyChart: backgroundColor: \"transparent\" plotColorPalette: \"#3F86B8, #C46A2B\" --- xychart-beta title \"Précision vs référence humaine (seuil 0,95)\" x-axis [\"logiciel\", \"écran\", \"catégorie\", \"segments\"] y-axis \"Précision\" 0 --\u003e 1 bar [0.74, 0.43, 0.04, 0.63] line [0.95, 0.95, 0.95, 0.95]La cartographie du logiciel, en entonnoir : l\u0026rsquo;arborescence des menus est entièrement cartographiée, mais la couverture des écrans et la preuve restent loin derrière, et la chaîne d\u0026rsquo;hypothèses n\u0026rsquo;a encore produit aucune règle prouvée.\n--- config: xyChart: width: 540 height: 360 themeVariables: xyChart: backgroundColor: \"transparent\" plotColorPalette: \"#3F86B8\" --- xychart-beta title \"Cartographie en boîte noire : de l'inventaire à la preuve\" x-axis [\"Entrées menu\", \"Feuilles\", \"Écrans\", \"Hypothèses\", \"Filtrées\", \"Prouvées\"] y-axis \"Nombre\" 0 --\u003e 3000 bar [1048, 899, 154, 2845, 1519, 0]Les serveurs MCP et l\u0026rsquo;évaluation de bout en bout (P4–P5) ne sont pas implémentés.\nLimites \u0026amp; suite Les résultats du pilote sont inférieurs aux seuils et reposent sur une annotation humaine partielle. Prochaines étapes : redéfinir l\u0026rsquo;étiquette de catégorie, constituer une référence entièrement humaine, mesurer à nouveau G1/G2, puis construire les trois serveurs et mener l\u0026rsquo;évaluation préenregistrée. Pour la cartographie du logiciel, les heuristiques de perturbation en écriture attendent une autorisation écrite et une VM dédiée.\nStack technique Python 3.11 · JSONL event log · SQLite · YAML ontology · MCP · AT-SPI · Ollama · pytest\n","date":"2026-09-01T00:00:00Z","permalink":"/fr/research/mission-knowledge-graph/","title":"Graphes de connaissances de mission : des preuves de conseil à une ontologie interrogée via MCP"},{"content":"Contexte Un client soumis à de fortes contraintes de sécurité gère plusieurs centaines de sites et exécute chaque jour quatre processus administratifs récurrents : la maintenance des équipements sur le terrain, le traitement des événements parasites récurrents émis par ces équipements, la rédaction de rapports d\u0026rsquo;intervention pour ses propres clients et la vérification de la bonne réception du contrôle de santé périodique de chaque site. Les données d\u0026rsquo;entrée sont dispersées entre trois systèmes aux modes d\u0026rsquo;accès très différents : des rapports PDF reçus par courriel, un portail web métier sans API publique et des classeurs Excel tenus à la main depuis de nombreuses années.\nL\u0026rsquo;objectif : automatiser ces processus sur un poste de travail de bureau tout en laissant à un opérateur humain le dernier mot sur chaque message adressé aux clients.\nContraintes de conception Aucun modèle de langage à l\u0026rsquo;exécution. Chaque décision découle de règles explicites et chaque phrase d\u0026rsquo;un modèle de texte. La sortie du robot est ainsi reproductible : les mêmes entrées produisent toujours les mêmes brouillons, de sorte qu\u0026rsquo;une nouvelle version peut être comparée mot pour mot à la production, et que toute modification peut être rattachée à une règle ou à une source de données. Aucune donnée client n\u0026rsquo;est transmise à un service de modèle externe. Un modèle vision-langage a été utilisé une seule fois, hors ligne, lors de la conception, pour cartographier des sessions d\u0026rsquo;écran enregistrées d\u0026rsquo;opérateurs ; il ne fait pas partie du système déployé. Des brouillons, pas des envois. Le robot se contente de créer des brouillons Outlook ; l\u0026rsquo;opérateur les relit et les envoie. Un interrupteur d\u0026rsquo;arrêt global impose le mode brouillon quels que soient les réglages propres à chaque processus. Exécution locale, sans nouvelle infrastructure. Python sur un poste Windows, tâches planifiées, dossier partagé sur NAS pour l\u0026rsquo;état et la configuration. Aucun secret en clair. Identifiants et jetons sont stockés dans le Gestionnaire d\u0026rsquo;identifiants Windows (DPAPI) ; la configuration est en YAML, modifiable par l\u0026rsquo;opérateur sans recompilation. Architecture flowchart TB SCHED[\"Passages planifiés (matin / après-midi)\"] --\u003e ING MAIL[\"Boîte aux lettres (Microsoft Graph, lecture)\"] --\u003e ING[\"Ingestion rapports PDF regroupés par jour\"] ING --\u003e PARSE[\"Analyseur PDF (pypdf + expressions régulières)\"] PORTAL[\"Portail web métier connexion Playwright → jeton de session → rejeu des points d'accès JSON\"] --\u003e RULES XLS[\"Classeurs de référence \u0026 d'historique (Excel)\"] --\u003e RULES PARSE --\u003e RULES[\"Moteur de règles 4 processus, règles ordonnées \u0026 exclusions\"] RULES --\u003e TPL[\"Composeur de modèles accords, noms, dates en français\"] TPL --\u003e DRAFTS[\"Brouillons Outlook (Graph, jamais envoyés)\"] RULES --\u003e TRACK[\"Classeurs de suivi (ajout atomique)\"] DRAFTS --\u003e OP([\"L'opérateur relit \u0026 envoie\"]) OP -. \"éléments envoyés : destinataires corrigés\" .-\u003e RULES NAS[(\"NAS : verrous, battements de cœur, journal, registre d'idempotence\")] --- RULES RULES --\u003e HEALTH[\"Alertes de santé webhook + contrôle de l'homme mort\"]Les quatre processus Maintenance des équipements. Les lignes de panne extraites des rapports PDF quotidiens sont confrontées à l\u0026rsquo;historique des piles et des réparations de chaque appareil. Un arbre de décision ordonné (la première correspondance l\u0026rsquo;emporte) choisit entre ignorer, attendre, remplacer la pile, remplacer l\u0026rsquo;appareil ou tester la portée radio, et rédige un ordre d\u0026rsquo;intervention pour le technicien ; chaque appareil d\u0026rsquo;un ordre portant sur plusieurs appareils conserve sa propre décision.\nÉvénements parasites récurrents. Le nombre d\u0026rsquo;événements par site et par appareil sur 24 heures est comparé à des seuils pour détecter les événements parasites récurrents. Les données du portail (un incident confirmé comme réel, un système mis à l\u0026rsquo;arrêt quelques minutes après une salve) priment sur ces comptages ; il en résulte un courriel de sensibilisation au client, un ordre d\u0026rsquo;intervention, ou rien.\nRapports d\u0026rsquo;intervention. Pour chaque intervention sur site, le robot reconstitue une chronologie unique à partir du journal d\u0026rsquo;événements du portail, du journal d\u0026rsquo;appels et des relevés des équipes de terrain, gère les événements à cheval sur minuit et rédige un rapport client accompagné des fichiers médias.\nContrôles de santé périodiques. Les sites dont le contrôle de santé périodique est absent sont identifiés, l\u0026rsquo;état de chaque canal de connectivité est vérifié sur le portail, puis un courriel au client, un ordre d\u0026rsquo;intervention ou une note interne est rédigé.\nRédiger un courriel : des paramètres au brouillon Chaque brouillon est l\u0026rsquo;aboutissement d\u0026rsquo;une longue chaîne de décisions explicites. Comptés dans le code source (octobre 2026), les quatre moteurs de règles comportent 53 issues terminales (chaque endroit où une règle rend une décision), réparties sur 37 types de décision et 13 générateurs de brouillons.\nLe courriel de sensibilisation du processus « événements parasites » en donne la mesure. Un site n\u0026rsquo;y aboutit qu\u0026rsquo;après 14 tests ordonnés au plus dans le moteur de règles (16 issues terminales pour ce seul processus). Le composeur lit ensuite 21 entrées : 17 champs de la fiche de décision du site et de la fiche client, la liste des destinataires, les pièces jointes et deux ressources apprises (les noms de zones du portail et un dictionnaire d\u0026rsquo;orthographe appris dans le classeur d\u0026rsquo;historique de l\u0026rsquo;opérateur lui-même). Entre la décision et le texte final, on compte 108 points de branchement conditionnel (instructions if, expressions conditionnelles et opérandes booléens, comptés sur l\u0026rsquo;arbre syntaxique du composeur et des dix fonctions auxiliaires qu\u0026rsquo;il appelle, avant la mise en forme HTML).\nflowchart TB IN([\"1 · Moteur de règles — 14 tests ordonnés, la première correspondance l'emporte. Entrées : rapports d'événements quotidiens · journal du portail · fiche client · profil appris du site\"]) --\u003e T0 T0[\"Drapeau bloquant sur la fiche du site ?\"] -- oui --\u003e X0[\"Pas de courriel\"] T0 -- non --\u003e T1[\"R6 · incident confirmé comme réel aujourd'hui ?\"] T1 -- oui --\u003e X1[\"Pas de courriel\"] T1 -- non --\u003e T2[\"R17 · événements médias à moins de 30 s entre zones ?\"] T2 -- oui --\u003e X2[\"Arbitrage manuel\"] T2 -- non --\u003e T3[\"R12 · cause externe confirmée par les médias ?\"] T3 -- non --\u003e T4[\"R8 · ≥ 8 événements d'intégrité ?\"] T4 -- oui --\u003e T4b[\"persistants depuis ≥ 3 jours ?\"] T4b -- oui --\u003e X3[\"Ordre d'intervention technicien\"] T4b -- non --\u003e X4[\"En attente\"] T4 -- non --\u003e T5[\"≥ 2 événements d'intégrité, ≥ la moitié de la salve ?\"] T5 -- oui --\u003e X5[\"Pas de courriel\"] T5 -- non --\u003e T6[\"R16 · ≥ 140 événements, sensibilisation ignorée depuis ≥ 4 semaines ? (désactivée par défaut)\"] T6 -- oui --\u003e X6[\"Avis de facturation\"] T6 -- non --\u003e T7[\"R15 · drapeau bâtiment partagé ?\"] T7 -- oui --\u003e X7[\"Courriel de coordination\"] T7 -- non --\u003e T8[\"R5 · week-end + drapeau appareil chroniquement défaillant ?\"] T8 -- oui --\u003e X8[\"Demande de masquage temporaire\"] T8 -- non --\u003e T9[\"R1 · même appareil ≥ 7 événements ?\"] T9 -- non --\u003e T10[\"R2 · ≥ 5 appareils et ≥ 8 événements ?\"] T10 -- non --\u003e T11[\"R4 · ≥ 8 événements, ≥ 50 % entre 5 h et 7 h ?\"] T11 -- non --\u003e T12[\"R3 · ≥ 8 événements, ≥ 60 % entre 12 h et 18 h, ≥ 70 % en 4 h ?\"] T12 -- non --\u003e T13[\"R1bis · total du site ≥ 7 événements ?\"] T13 -- non --\u003e X9[\"Pas de courriel\"] T3 \u0026 T9 \u0026 T10 \u0026 T11 \u0026 T12 \u0026 T13 -- oui --\u003e ADV ADV([\"2 · Composeur — courriel de sensibilisation, identifiant de règle transmis. Nom du client : forme juridique retirée, casse rétablie, sigles conservés\"]) ADV --\u003e SUBJ[\"≥ 30 événements ?\"] SUBJ -- oui --\u003e S1[\"Objet avec préfixe d'urgence\"] SUBJ -- non --\u003e S2[\"Objet simple\"] S1 \u0026 S2 --\u003e GR[\"Cellule contact\"] GR -- \"plusieurs personnes, ou mot de fonction / d'organisation\" --\u003e G1[\"Salutation générique\"] GR -- \"civilité + nom\" --\u003e G2[\"Salutation + civilité normalisée (7 abréviations) + NOM\"] GR -- \"nom seul\" --\u003e G3[\"Salutation + NOM\"] G1 \u0026 G2 \u0026 G3 --\u003e DEV[\"Appareils concernés\"] DEV -- un --\u003e D1[\"Nom de zone du portail s'il est connu, sinon libellé nettoyé + table de jargon + accents appris\"] DEV -- plusieurs --\u003e D2[\"Formule générique + liste de 6 au plus par nombre d'événements, chacun avec son code s'il est connu\"] D1 \u0026 D2 --\u003e HND[\"Système mis en marche ou à l'arrêt à quelques minutes de la salve ? (R1 à R4 seulement)\"] HND -- \"arrêt juste après\" --\u003e C1[\"Erreur de manipulation, formulation A\"] HND -- \"marche juste avant\" --\u003e C2[\"Erreur de manipulation, formulation B\"] HND -- non --\u003e ACT[\"Site en activité ? — toutes les conditions : R1 à R4 ou R1bis · ≥ 2 appareils · ≥ 10 événements · aucune intervention dans la fenêtre · site professionnel · ≥ 90 % dans les heures apprises · capteurs médias seuls : ≥ 90 % système en marche\"] ACT -- oui --\u003e C3[\"Formulation « site en activité »\"] ACT -- non --\u003e RUL[\"Règle déclenchée\"] RUL -- \"R1, R2\" --\u003e C4[\"Cause environnementale générique\"] RUL -- \"R3, R4\" --\u003e C5[\"Cause : passages du personnel\"] RUL -- R12 --\u003e C6[\"Cause externe confirmée par les médias\"] RUL -- R1bis --\u003e C7[\"Cause à rechercher sur place\"] C4 \u0026 C5 --\u003e ATT[\"Médias réellement joints ?\"] ATT -- oui --\u003e A1[\"+ renvoi aux pièces jointes\"] ATT -- non --\u003e FLG A1 \u0026 C1 \u0026 C2 \u0026 C3 \u0026 C6 \u0026 C7 --\u003e FLG[\"Drapeau du site : travaux fréquents ?\"] FLG -- oui --\u003e F1[\"Demande : arrêt avant travaux\"] FLG -- non --\u003e F2[\"Demande : traiter la cause\"] F1 \u0026 F2 --\u003e REC[\"Adresses dans la fiche client ?\"] REC -- oui --\u003e RC1[\"Toutes les adresses trouvées\"] REC -- non --\u003e RC2[\"Boîte interne de repli\"] RC1 \u0026 RC2 --\u003e DRAFT([\"Texte brut → HTML Outlook (dé-repliage, listes, typographie fixe, signature) → dossier des brouillons, jamais envoyé\"]) classDef q stroke-dasharray:4 3,stroke-width:2px; class T0,T1,T2,T3,T4,T4b,T5,T6,T7,T8,T9,T10,T11,T12,T13,SUBJ,GR,DEV,HND,ACT,RUL,ATT,FLG,REC q;L\u0026rsquo;espace de formulation de ce seul courriel : 2 formes d\u0026rsquo;objet, 3 formes de salutation, 2 formes de phrase d\u0026rsquo;ouverture, 7 formulations de cause atteignables (dont deux avec ou sans renvoi aux médias joints), 2 demandes d\u0026rsquo;action et une liste facultative de 2 à 6 appareils. Tous les seuils ci-dessus sont dans la configuration YAML, pas dans le code.\nParamètre Source Effet sur le courriel Nombre d\u0026rsquo;événements sur 24 h rapports quotidiens chiffre de la phrase d\u0026rsquo;ouverture ; à partir de 30, préfixe d\u0026rsquo;urgence dans l\u0026rsquo;objet Règle déclenchée moteur de règles choisit la formulation de la cause ; conditionne les vérifications « erreur de manipulation » et « site en activité » Appareils concernés (nettoyés, dédoublonnés) rapports quotidiens un appareil nommé, ou une formule générique suivie d\u0026rsquo;une liste de 6 lignes au plus, par nombre d\u0026rsquo;événements Code de l\u0026rsquo;appareil sur chaque ligne de rapport rapports quotidiens ajouté entre parenthèses à chaque appareil listé, seulement s\u0026rsquo;il est connu Nom de zone de l\u0026rsquo;appareil principal portail remplace le libellé brut du rapport lorsqu\u0026rsquo;il est disponible Graphies apprises classeur d\u0026rsquo;historique de l\u0026rsquo;opérateur rétablit accents et casse des noms d\u0026rsquo;appareils Cellules civilité et nom du contact fiche client l\u0026rsquo;une des 3 formes de salutation ; plusieurs personnes, une fonction ou un nom d\u0026rsquo;organisation ramènent à la forme générique Raison sociale fiche client forme juridique retirée, casse rétablie en conservant les sigles, utilisée dans l\u0026rsquo;objet et le corps Type de site, heures d\u0026rsquo;ouverture apprises, interventions dans la fenêtre classeur de suivi, journal du portail active ou neutralise la formulation « site en activité » Mise en marche ou à l\u0026rsquo;arrêt autour de la salve journal du portail formulation « erreur de manipulation » (2 variantes), prioritaire sur toute autre cause Drapeaux du site fiche client choix entre les 2 demandes d\u0026rsquo;action Présence de pièces jointes médias du portail renvoi aux pièces jointes, ou rien Adresses des destinataires fiche client toutes les adresses trouvées ; à défaut, une boîte interne de repli Les autres brouillons s\u0026rsquo;appuient sur les mêmes fonctions partagées de rédaction en français : la préposition devant un nom de site s\u0026rsquo;accorde avec son premier nom (6 formes, de « chez » à « à l\u0026rsquo; » et « aux ») ; les titres des rapports s\u0026rsquo;accordent en genre et en nombre ; les dates sont écrites en toutes lettres ; l\u0026rsquo;intitulé « Contact » passe au pluriel dès que plusieurs contacts sont listés ; et une table de 8 entrées traduit le jargon technique des équipements en vocabulaire client.\nIngénierie de la fiabilité Idempotence. Un registre quotidien indexé par site, type de message et empreinte de l\u0026rsquo;objet empêche les brouillons en double ; un registre inter-jours empêche de réémettre un ordre d\u0026rsquo;intervention avant que l\u0026rsquo;intervention précédente n\u0026rsquo;ait eu lieu. Les jours manqués sont rattrapés automatiquement. Concurrence sur un NAS partagé. Fichiers de verrou exclusifs (O_CREAT|O_EXCL) avec une durée de vie pour les verrous orphelins ; deux postes publient des battements de cœur, et le poste secondaire ne prend le relais que lorsque le principal est silencieux depuis deux minutes. Écritures sûres dans les classeurs. Les écritures passent par un fichier temporaire et un remplacement atomique, avec nouvelles tentatives lorsque le classeur est ouvert par un utilisateur ; les lignes insérées décalent les formules de pied de tableau pour que les totaux restent justes. Robustesse réseau. Les appels Graph gèrent le renouvellement des jetons, l\u0026rsquo;en-tête Retry-After des réponses HTTP 429 et le repli progressif sur les erreurs 5xx. Échec explicite. Une enveloppe de plantage, sans dépendance au paquet principal, envoie une alerte expurgée et un signal d\u0026rsquo;homme mort même lorsque les imports échouent ; une sentinelle déclenche une alerte lorsque le portail ne renvoie aucune donnée au lieu de signaler un succès. Évaluation en parallèle (shadow). Une version bac à sable rejoue une journée en lecture seule et compare ses brouillons à ceux de la production. Le critère d\u0026rsquo;acceptation est la part des brouillons que l\u0026rsquo;opérateur envoie sans en modifier un seul mot. Résultats 1 766 tests automatisés dans le dépôt (octobre 2026), reposant sur des adaptateurs simulés de messagerie et de portail, les tests sur systèmes réels étant marqués à part. Un audit du corpus de rapports reçus a montré que 9,5 % des lignes d\u0026rsquo;événements étaient écartées silencieusement, parce que les codes et libellés d\u0026rsquo;événements sont concaténés dans le texte extrait des PDF ; l\u0026rsquo;analyseur a été réécrit pour reconnaître les formes de codes effectivement émises. La mise en cache du classeur d\u0026rsquo;historique des pannes (1,49 Mo, 15 533 lignes) a réduit la durée du processus de maintenance des équipements, sur un rejeu de rapports réels, de 161,1 s à 23,3 s ; le nombre d\u0026rsquo;ouvertures du classeur est passé de 26 à 3. Première comparaison en parallèle sans écart avec la production : 14 brouillons de chaque côté, 14 en commun, 0 manquant, 0 en trop. Stack technique Python 3.11 · Microsoft Graph · MSAL · httpx · Playwright · pypdf · openpyxl · pydantic · keyring · pytest · PyInstaller\n","date":"2026-06-01T00:00:00Z","permalink":"/fr/research/deterministic-rpa/","title":"Automatisation déterministe des processus sous fortes contraintes de sécurité"},{"content":"Contexte Une conférence enregistrée sur plusieurs microphones (intervenants, salle, musique) produit des heures d\u0026rsquo;audio multipiste brut. L\u0026rsquo;essentiel du temps de montage est consacré à repérer la matière — qui parle quand, sur quelle piste, où se trouvent les silences — avant toute coupe.\nLes outils vocaux open source (Whisper et ses dérivés, pyannote, Silero VAD) résolvent bien la transcription et la question « qui a parlé quand », mais s\u0026rsquo;arrêtent au texte. La question traitée ici est de savoir si cette analyse peut être livrée sous la forme d\u0026rsquo;un objet de montage : une timeline multipiste au format AAF, le format d\u0026rsquo;échange que les stations audionumériques ouvrent nativement, avec des pistes qualifiées et les temps morts supprimés.\nAvant → après Un vrai projet traité de bout en bout : une conférence enregistrée sur 16 pistes. Toute la colonne de droite est produite automatiquement, sans aucune coupe manuelle ; les chiffres sont lus dans la base d\u0026rsquo;analyse du projet et dans l\u0026rsquo;AAF livré.\nEntrée (enregistrement brut) Sortie générée (timeline AAF) Pistes 16 × 1 h 32 min 54 s (≈ 24 h 46 min d\u0026rsquo;audio à parcourir) 16 pistes conservées dans l\u0026rsquo;AAF, dont 6 portent des clips Rôles des pistes 4 parole · 2 musique (dont une détectée comme ambiance) · 10 silencieuses 10 pistes silencieuses laissées vides, sans tri manuel Matière 204 régions de parole et 5 passages musicaux détectés 41 clips (37 parole, 4 musique) Coupes — 40 coupes franches entre sources, dont 33 changements de micro Transitions — 0 fondu enchaîné : coupes franches, chaque clip de parole prolongé de 0,3 s Temps morts — 3 trous ≥ 4,5 s supprimés en ripple (36,9 s) ; timeline de 1 h 32 min 17 s En haut : les 16 pistes d\u0026rsquo;entrée sur toute la durée de l\u0026rsquo;enregistrement, colorées selon le rôle et l\u0026rsquo;activité détectés ; les quatre micros de parole sont actifs presque en permanence, car chacun capte aussi ses voisins. En bas : le montage généré, une ligne par piste comme dans l\u0026rsquo;AAF — une seule source est retenue à chaque instant, les repères marquent les 40 changements de source, les zones hachurées du panneau supérieur sont les temps morts supprimés.\nLes clips de parole sont peu nombreux et longs (médiane 79 s, le plus long 10 min 11 s) : le montage suit l\u0026rsquo;intervenant actif au lieu de couper à chaque respiration, et les micro-bascules de moins de 0,8 s sont absorbées par le lissage anti-scintillement. Dix clips durent encore moins de 6 s — de brèves interjections, premier endroit à vérifier lors de la relecture du montage.\nApproche flowchart TB A[\"Enregistrement WAV multipiste\"] --\u003e B[\"Décodage en mono 16 kHz + énergie RMS par 100 ms\"] B --\u003e C[\"Détection d'activité vocale (Silero)\"] C --\u003e D[\"Transcription (Whisper large-v3, par segments)\"] D --\u003e E[\"Alignement forcé des mots (WhisperX / wav2vec2)\"] C --\u003e F[\"Diarisation des locuteurs (pyannote)\"] E --\u003e G[\"Attribution des locuteurs + post-traitement des segments\"] F --\u003e G B --\u003e H[\"Rôle de la piste : parole / musique / silence\"] G --\u003e H H --\u003e I[\"Montage : micro actif par trame de 100 ms\"] I --\u003e J[\"Export AAF (lié aux noms WAV d'origine)\"] I --\u003e K[\"Mixage mono WAV\"]Méthodes Transcription. Whisper large-v3 via faster-whisper (CTranslate2), exécuté sur des segments de longueur fixe dans un processus de travail isolé et persistant : le modèle n\u0026rsquo;est chargé qu\u0026rsquo;une fois, et un plantage natif ne fait perdre qu\u0026rsquo;un segment, signalé plutôt qu\u0026rsquo;ignoré silencieusement. Le décodage utilise une recherche en faisceau avec filtrage Silero VAD, et condition_on_previous_text est désactivé pour limiter les boucles de répétition.\nHorodatage des mots et locuteurs. Les horodatages au niveau du mot proviennent de l\u0026rsquo;alignement forcé de WhisperX (wav2vec2). Les tours de parole proviennent de la diarisation pyannote et sont attribués aux mots par recouvrement temporel.\nPost-traitement. Des filtres purs suppriment les hallucinations connues de Whisper (crédits de sous-titrage types, formules du genre « merci d\u0026rsquo;avoir regardé », segments purement musicaux), les sorties en écriture non latine sur de l\u0026rsquo;audio français et les doublons, puis fusionnent les segments consécutifs d\u0026rsquo;un même locuteur.\nQualification des pistes et montage. Chaque piste est classée en parole, musique ou silence en combinant l\u0026rsquo;énergie par trame, la couverture VAD et des statistiques de transcription. Le montage sélectionne, pour chaque trame de 100 ms, le microphone présentant le meilleur rapport signal sur bruit au-dessus de son propre bruit de fond (ce qui réduit la diaphonie entre micros), applique un lissage anti-papillotement et resserre la timeline en supprimant les temps morts globaux.\nSynchronisation. Les enregistreurs distincts sont alignés en appariant des mots caractéristiques entre transcriptions (médiane robuste des décalages), après un placement grossier fondé sur l\u0026rsquo;horloge et corrigé de la dérive d\u0026rsquo;horloge.\nExport. La liste de montage est écrite sous forme d\u0026rsquo;AAF multipiste avec pyaaf2, en intégrant l\u0026rsquo;audio ou en le référençant.\nDéploiement. Un portail web reçoit les tâches et un nœud de calcul distinct l\u0026rsquo;interroge en HTTPS. Les clients ne téléversent que des copies d\u0026rsquo;analyse compressées accompagnées d\u0026rsquo;un manifeste de leurs fichiers d\u0026rsquo;origine ; l\u0026rsquo;AAF livré référence les noms des WAV d\u0026rsquo;origine, de sorte que le monteur reconnecte localement les sources en pleine qualité et que les originaux ne quittent jamais la machine du client.\nRésultats Banc d\u0026rsquo;essai (bench_stt.py) sur de l\u0026rsquo;audio réel de conférence : fenêtres de parole d\u0026rsquo;une minute sélectionnées par VAD sur quatre pistes de parole, Whisper large-v3 dans tous les cas, ordinateur portable Apple Silicon, mesures à chaud hors chargement du modèle. Aucune transcription de référence n\u0026rsquo;étant disponible, les indicateurs de qualité sont des divergences par rapport à une pseudo-référence (sortie de WhisperX), et non des erreurs absolues.\nChaîne de traitement (CPU) Facteur temps réel openai-whisper 0,43 WhisperX 0,51 WhisperX + alignement forcé 0,54 openai-whisper + horodatage des mots 0,57 faster-whisper (faisceau 5 + VAD) 0,66 faster-whisper + horodatage des mots 0,70 Horodatage des mots : les horodatages natifs s\u0026rsquo;écartent de l\u0026rsquo;alignement forcé d\u0026rsquo;environ 205 ms en médiane (faster-whisper) et d\u0026rsquo;environ 210 ms (openai-whisper) ; l\u0026rsquo;alignement forcé ajoute environ 1,2 s par minute d\u0026rsquo;audio. Divergence des transcriptions : 7 à 11 % de divergence au niveau du mot entre chaînes, essentiellement de la ponctuation, de la segmentation et de la normalisation après inspection manuelle. Répétitions : 1 à 2 % de contenu répété ; aucun passage halluciné observé sur ces extraits. Détection des pistes : les trois pistes de musique ou de silence de l\u0026rsquo;enregistrement à sept pistes ont été identifiées par VAD et écartées automatiquement. Limites \u0026amp; suite La qualité est mesurée par rapport à une pseudo-référence ; un jeu de test transcrit manuellement est nécessaire pour rapporter un véritable taux d\u0026rsquo;erreur sur les mots et un taux d\u0026rsquo;erreur de diarisation. Les extraits du banc d\u0026rsquo;essai sont courts (une minute par piste) et ne comportent qu\u0026rsquo;un seul locuteur par fenêtre : la précision de la diarisation en cas de chevauchement de plusieurs locuteurs n\u0026rsquo;est donc pas encore quantifiée. CTranslate2 n\u0026rsquo;a pas de backend Metal : sur Apple Silicon, faster-whisper et WhisperX s\u0026rsquo;exécutent sur CPU, tandis que CUDA est utilisé lorsqu\u0026rsquo;il est disponible. Le choix du matériel pour chaque étape a été mesuré plutôt que présumé ; une comparaison sous CUDA reste à effectuer. L\u0026rsquo;export AAF cible l\u0026rsquo;import dans Logic Pro ; les autres logiciels de montage n\u0026rsquo;ont pas été testés de manière systématique. Stack technique Python · faster-whisper · CTranslate2 · WhisperX · pyannote.audio · Silero VAD · PyTorch (MPS / CUDA) · ffmpeg · pyaaf2 · SQLite · PHP · MySQL\n","date":"2026-06-01T00:00:00Z","permalink":"/fr/research/speech-to-edit/","title":"De l'enregistrement multipiste à la timeline éditable : transcription, diarisation et export AAF"},{"content":"Contexte Les campagnes de rappel de sécurité supposent d\u0026rsquo;atteindre chaque véhicule concerné, mais courriers et appels téléphoniques laissent une population résiduelle de propriétaires qui ne répondent jamais. Dans les territoires insulaires et ultramarins, le problème est plus aigu : la couverture réseau est inégale, la logistique de terrain s\u0026rsquo;étend sur plusieurs territoires et le registre de qui conduit quoi est incomplet. La question pratique devient alors une question de gestion de flotte : quels véhicules du parc en circulation sont encore concernés, où sont-ils aperçus, et où en est chacun d\u0026rsquo;eux sur le chemin de la réparation ?\nApproche flowchart TB A[\"Liste de rappel(récupération planifiée du fichier ou CSV manuel)\"] --\u003e B[\"Serveur centralimport · versionnage · décodage des noms de modèles\"] B --\u003e|\"diff incrémental\"| C[\"Unités de terrain (ordinateurs portables dans les véhicules des agents)copie locale de la liste de rappel\"] D[\"Flux caméra\"] --\u003e E[\"Détection de plaques + OCR(sur l'appareil, hors ligne)\"] E --\u003e F[\"Correction tenant compte du format+ confirmation par double lecture\"] F --\u003e G{\"Correspondance avecla liste de rappel locale ?\"} G --\u003e|\"non\"| H[\"Écartée — rien n'est stocké\"] G --\u003e|\"oui\"| I[\"Alerte à l'agent+ file d'attente locale\"] I --\u003e|\"synchronisation au retour du réseau\"| B B --\u003e J[\"Tableau de bordunités · tournées · détections · incidents\"] J --\u003e K[\"Processus de contact des propriétairesidentifié → contacté → réparé\"]Méthodes Ingestion et versionnage des données. La liste de rappel est récupérée automatiquement selon un calendrier ou importée manuellement. Chaque import est comparé au précédent à l\u0026rsquo;aide d\u0026rsquo;identifiants stables, versionné par empreinte, et seul le delta est envoyé aux unités de terrain. Les codes de type constructeur sont traduits en noms de modèles lisibles lors de l\u0026rsquo;import.\nCorrespondance malgré le bruit de l\u0026rsquo;OCR. La détection des plaques et la reconnaissance des caractères s\u0026rsquo;exécutent sur l\u0026rsquo;ordinateur portable de terrain avec des modèles ONNX, sans dépendance au réseau. Deux garde-fous réduisent les fausses correspondances : (i) une étape de correction positionnelle exploite la structure connue des formats de plaques nationaux (actuel et ancien) pour lever les confusions classiques de l\u0026rsquo;OCR (O/0, I/1, S/5, B/8, Z/2, G/6), en rejetant toute lecture ambiguë ; (ii) une confirmation par double lecture ne comptabilise une plaque que si elle est lue deux fois dans une courte fenêtre de temps. Une page web pour smartphone offre une solution de secours manuelle (photo ou saisie de la plaque, avec validation de la clé de contrôle du VIN).\nSynchronisation pensée pour le hors-ligne. Les correspondances sont mises en file d\u0026rsquo;attente localement et transmises au serveur central à la connexion suivante, de sorte que les détections survivent à des coupures de plusieurs jours. Les unités envoient un signal de vie (version du logiciel, version de la liste de rappel, compteurs de lectures).\nOpérations de terrain. Les superviseurs planifient des tournées sous forme de points de contrôle ordonnés et géolocalisés sur une carte, les attribuent aux équipes et aux unités, réutilisent des modèles et suivent l\u0026rsquo;avancement. Les agents signalent les incidents avec un niveau de gravité. Un processus de contact consigne le résultat de chaque démarche auprès d\u0026rsquo;un propriétaire, et le tableau de bord en déduit un entonnoir de conversion (identifié → approché → engagé → réparé) avec les tendances hebdomadaires, le délai médian jusqu\u0026rsquo;à la réparation et une ventilation par territoire.\nProtection des données dès la conception. Les plaques qui ne figurent pas sur la liste de rappel ne sont jamais stockées ni transmises ; les enregistrements conservés ont des durées de conservation fixes avec purge automatique ; les actions sont consignées dans un journal d\u0026rsquo;audit ; l\u0026rsquo;accès au tableau de bord repose sur des rôles, y compris des comptes en lecture seule ; les données au repos sont chiffrées. Un registre des traitements a été rédigé parallèlement au code.\nDéploiement \u0026amp; exploitation (DevOps) Le système tourne sur deux types de machines très différents : des ordinateurs portables Windows dans les véhicules des agents, qui peuvent rester hors ligne plusieurs jours, et un serveur par instance. Après les premières semaines de terrain, l\u0026rsquo;essentiel du travail d\u0026rsquo;ingénierie a consisté à rendre les deux côtés faciles à déployer, à superviser et à remettre en service, par une seule personne, sans interrompre le travail de terrain.\nflowchart LR subgraph ADM[\"Poste d'administration\"] GIT[\"Dépôt Gitarbre commité uniquement\"] PROV[\"Script de provisionnementun fichier de configuration par unité\"] BLD[\"Build terrainpaquet PyInstaller + modèles ONNX\"] end subgraph SRV[\"Serveur (VPS Ubuntu LTS)\"] CAD[\"CaddyTLS · HSTS · sans journal d'accès\"] APP[\"Conteneur DockerAPI FastAPI + tableau de bordport en boucle locale uniquement\"] VOL[(\"Volume LUKS2SQLite · photos · archives\")] TIM[\"Timers systemdsupervision · sauvegarde · nettoyage\"] end FLD[\"Portables de terrainSQLite local · boucle de synchronisation\"] OBJ[(\"Stockage objet externesauvegardes chiffrées age\")] CHAT[\"Alertes messageriechangements d'état + bilans quotidiens\"] GIT --\u003e|\"git archive via SSH → script de déploiement\"| APP PROV --\u003e|\"API d'administration\"| APP PROV --\u003e|\"fichier de configuration + LISEZMOI\"| FLD BLD --\u003e|\"archive + installateur en un clic\"| FLD FLD \u003c--\u003e|\"HTTPS : signal de vie · envois · diff des rappels\"| CAD CAD --\u003e APP APP --- VOL TIM --\u003e VOL TIM --\u003e|\"copie chiffrée\"| OBJ TIM --\u003e CHATPortables de terrain : empaquetage, installation et mises à jour Empaquetage. L\u0026rsquo;application de terrain (backend Python, interface React) est figée avec PyInstaller en un exécutable Windows « un dossier » qui embarque les modèles ONNX et la configuration de l\u0026rsquo;OCR : une unité n\u0026rsquo;a besoin ni d\u0026rsquo;une installation Python ni du réseau pour lire les plaques. Des modes intégrés --diag et --selftest vérifient l\u0026rsquo;environnement d\u0026rsquo;exécution embarqué et lisent une image de test sans lancer l\u0026rsquo;interface, ce qui a permis de diagnostiquer les échecs de démarrage directement sur la machine de terrain.\nInstallateur en un clic. Le build est livré sous forme d\u0026rsquo;archive avec un INSTALLER.bat à lancer d\u0026rsquo;un double-clic. Il s\u0026rsquo;élève lui-même en administrateur et exécute un script PowerShell qui retire des fichiers la marque « téléchargé depuis Internet » (sans quoi l\u0026rsquo;environnement embarqué ne se charge pas), désactive la mise en veille USB pour que le dongle GPS ne soit pas suspendu, et installe le fichier de configuration de l\u0026rsquo;unité là où l\u0026rsquo;exécutable le lit. Le script refuse de deviner : si plusieurs fichiers de configuration différents sont présents, il les liste et demande lequel est le nouveau. Une réinitialisation optionnelle efface la base locale lorsqu\u0026rsquo;une unité change de serveur ; elle affiche le serveur cible avant de demander confirmation et avertit que les détections non synchronisées seraient perdues. Le jeton d\u0026rsquo;accès de l\u0026rsquo;unité n\u0026rsquo;est jamais affiché. Une mise à jour suit le même chemin : nouveau build, nouvelle exécution de l\u0026rsquo;installateur.\nProvisionnement. Un script Python qui n\u0026rsquo;utilise que la bibliothèque standard, et tourne donc sur un Windows nu, crée les unités à partir d\u0026rsquo;un fichier CSV via l\u0026rsquo;API d\u0026rsquo;administration du serveur et génère, pour chacune, son fichier de configuration (adresse du serveur, code de l\u0026rsquo;unité, nom affiché, jeton) et un LISEZMOI à remettre avec le portable. La clé d\u0026rsquo;administration est lue dans une variable d\u0026rsquo;environnement ou saisie de manière masquée, jamais passée en argument de ligne de commande.\nVersionnage : logiciel et liste de rappel Version du logiciel. Chaque unité indique la version de son application dans son signal de vie. Le tableau de bord la compare à la version attendue et signale les unités qui restent à mettre à jour.\nVersion de la liste de rappel. La liste de rappel est versionnée par empreinte. À chaque cycle, une unité compare son empreinte locale à celle du serveur : identique, rien à faire ; pas de copie locale, téléchargement complet ; sinon, le serveur ne renvoie que les lignes ajoutées et retirées depuis cette empreinte (et l\u0026rsquo;unité se rabat sur un téléchargement complet si le serveur ne connaît plus sa version). La modification est appliquée en une seule transaction, et l\u0026rsquo;empreinte locale n\u0026rsquo;avance que si tout a été appliqué.\nCette dernière règle vient d\u0026rsquo;un incident de terrain. Une contrainte de la base de données faisait échouer le diff sur une unité, l\u0026rsquo;erreur était absorbée par la boucle de synchronisation, et l\u0026rsquo;unité continuait d\u0026rsquo;envoyer ses signaux de vie alors que sa liste de rappel restait figée pendant plus de deux semaines : elle alertait donc sur des véhicules déjà réparés. La version 1.4.1 a corrigé la cause, ajouté un retour arrière explicite et livré une migration de schéma qui conserve les données existantes. Elle a été testée par une série de 62 tests, qui reproduisait le bug et migrait une base à l\u0026rsquo;ancien schéma. La supervision lève désormais une alerte « synchronisation des rappels figée » lorsqu\u0026rsquo;une unité n\u0026rsquo;a pas reçu une liste publiée au-delà d\u0026rsquo;un délai de grâce.\nSynchronisation incrémentale et résiliente Toutes les cinq minutes, ou à la demande, une unité exécute un cycle de synchronisation composé d\u0026rsquo;étapes indépendantes : signal de vie, envoi des détections (par lots), trace GPS, incidents, mises à jour des points de contrôle, puis récupération de la liste de rappel et des tournées. Les envois passent avant les récupérations, de sorte que les données de terrain partent en premier. Une étape en échec ne bloque plus les autres : dans une version antérieure, le cycle était monolithique, et un signal de vie en échec a un jour retardé les détections de 22 minutes. Les requêtes utilisent des délais d\u0026rsquo;attente courts, les téléchargements des délais plus longs. Le signal de vie transmet la version du logiciel, la version de la liste de rappel, le nombre de détections en attente et les compteurs de lectures, sur lesquels reposent le tableau de bord et la supervision.\nDéploiement du serveur Kit d\u0026rsquo;instance. Chaque déploiement est une instance indépendante, décrite par un court identifiant, sur un serveur virtuel Ubuntu LTS. Un script d\u0026rsquo;amorçage, interactif et relançable sans risque, installe les paquets système, Docker et Caddy depuis leurs dépôts officiels. Il active les mises à jour de sécurité automatiques sans redémarrage automatique, restreint SSH à l\u0026rsquo;authentification par clé, active un pare-feu en refus par défaut et une protection contre la force brute, et vérifie que l\u0026rsquo;enregistrement DNS pointe vers le serveur avant d\u0026rsquo;appliquer la configuration TLS. Les secrets résident dans des fichiers de configuration réservés à root sur le serveur, jamais dans le dépôt.\nConteneur et proxy inverse. Un Dockerfile multi-étapes construit le tableau de bord React avec Node, puis exécute le serveur FastAPI sur une image Python allégée, sous un utilisateur non privilégié. Son contrôle de santé prévoit une période de démarrage de trois minutes, car les modèles de plaques et d\u0026rsquo;OCR sont chargés avant que le serveur n\u0026rsquo;écoute. Le conteneur n\u0026rsquo;est publié que sur l\u0026rsquo;interface de boucle locale. Caddy est le seul point d\u0026rsquo;entrée public : certificat Let\u0026rsquo;s Encrypt automatique, HSTS explicite et aucun journal d\u0026rsquo;accès, car les URL de scan contiennent des plaques. Le journal d\u0026rsquo;accès de l\u0026rsquo;application elle-même est désactivé pour la même raison.\nDéploiement et retour arrière. Le code ne quitte le poste d\u0026rsquo;administration que sous la forme d\u0026rsquo;un git archive d\u0026rsquo;un arbre commité : les modifications non commitées sont listées et ne partent pas, et les fins de ligne sont forcées en LF. Sur le serveur, le nouvel arbre est extrait à côté de l\u0026rsquo;actuel puis permuté, le précédent est conservé, et le commit déployé est consigné. Le script de déploiement se détache ensuite de la session SSH : une connexion coupée n\u0026rsquo;interrompt ni le déploiement ni un retour arrière. Un verrou empêche les déploiements concurrents. Le script construit l\u0026rsquo;image (étiquetée avec son commit), conserve l\u0026rsquo;image précédente comme rollback, recrée le conteneur et attend qu\u0026rsquo;il se déclare en bonne santé. Il abandonne au bout de cinq minutes, ou dès que le conteneur a redémarré deux fois. En cas d\u0026rsquo;échec, il revient automatiquement à l\u0026rsquo;image et à l\u0026rsquo;arbre source précédents, met de côté le code en échec et envoie une alerte. Revenir à n\u0026rsquo;importe quelle version antérieure revient à redéployer ce commit. Un retour arrière d\u0026rsquo;image ne défait pas une migration de schéma : la procédure documentée consiste donc à faire une sauvegarde avant tout déploiement qui modifie le schéma.\nVolume chiffré et redémarrages sûrs Les données du serveur (base, photos de contact, archives des listes de rappel) résident dans un conteneur de fichier LUKS2 monté avec des options restrictives. Sa phrase de passe n\u0026rsquo;est jamais stockée sur la machine : après un redémarrage, une personne déverrouille le volume. Le conteneur redémarre de lui-même, mais le serveur refuse de démarrer tant qu\u0026rsquo;un fichier sentinelle situé sur le volume chiffré est absent. Sans lui, un redémarrage aurait laissé un dossier vide à la place du volume, et l\u0026rsquo;application y aurait créé une base neuve, non chiffrée, et accepté les données de terrain. Cette protection a été vérifiée dans les deux sens sur un conteneur jetable. Un script distinct agrandit le volume pendant qu\u0026rsquo;il est monté.\nSauvegardes et reprise Un timer systemd quotidien prend un instantané cohérent de la base SQLite via son API de sauvegarde, l\u0026rsquo;archive avec les photos et les archives de rappel, et chiffre le résultat avec age vers une clé publique. La clé privée n\u0026rsquo;est affichée qu\u0026rsquo;une fois, à sa création, et conservée hors du serveur. Les sauvegardes sont gardées localement et, en option, copiées vers un stockage objet compatible S3 avec rclone, configuré uniquement par variables d\u0026rsquo;environnement. Un mode de test de restauration déchiffre une sauvegarde dans un dossier temporaire sur le volume chiffré, lance un contrôle d\u0026rsquo;intégrité, compte les lignes par table, puis efface tout. Le mode d\u0026rsquo;application déplace l\u0026rsquo;état courant de côté au lieu de le supprimer. La documentation comprend une reconstruction pas à pas après perte totale du serveur. Le plan de continuité vise un délai de reprise de 4 heures et une perte de données maximale de 24 heures.\nSupervision Un chien de garde s\u0026rsquo;exécute toutes les 15 minutes et ne publie sur un webhook de messagerie que lorsqu\u0026rsquo;un état change (problème, puis « rétabli »). Un bilan plus complet est envoyé deux fois par jour, calé sur les horaires de terrain. Il vérifie que le volume chiffré est monté, le point de santé de l\u0026rsquo;API (avec plusieurs essais, car l\u0026rsquo;import quotidien peut le bloquer environ une minute), l\u0026rsquo;état de santé du conteneur, la lisibilité de la base, l\u0026rsquo;occupation du disque système et du volume chiffré, la taille du journal d\u0026rsquo;écriture anticipée de SQLite, l\u0026rsquo;expiration du certificat TLS, l\u0026rsquo;âge et la taille de la dernière sauvegarde, les unités silencieuses depuis plus de 48 heures (et non 24, car les unités sont éteintes le week-end) et les unités dont la liste de rappel est figée. Un guetteur distinct alerte lorsqu\u0026rsquo;aucun import de liste de rappel n\u0026rsquo;a eu lieu depuis plus de 30 heures. Plusieurs de ces contrôles ont été ajoutés après des incidents réels : le volume chiffré a un jour atteint 90 % sans aucune alerte, car seul le disque système était surveillé. Un timer hebdomadaire nettoie les caches de construction Docker et ne conserve que les images courante et de rollback. Un script dédié tronque le journal SQLite avec une attente de verrou courte, afin que les écritures du terrain ne soient jamais bloquées longtemps.\nRésilience hors ligne Le côté terrain est conçu pour continuer à fonctionner pendant une panne du serveur : lecture des plaques, correspondance avec la copie locale de la liste de rappel, alertes, tournées déjà téléchargées et onglet de statistiques local fonctionnent sans réseau, et la file d\u0026rsquo;attente se vide à la connexion suivante. Seuls le tableau de bord (et la page pour smartphone hébergée sur le serveur) sont indisponibles tant que le serveur est arrêté.\nTests Le dépôt ne comporte pas de chaîne d\u0026rsquo;intégration continue. Les versions sont testées avant leur livraison, et les commits consignent ces exécutions : 12/12 et 6/6 pour les étapes de correction des plaques et de confirmation, 62 tests pour la version 1.4.1. Les comportements qui ne se prêtent pas aux tests unitaires, comme la protection du volume ou un déploiement réel, ont été vérifiés sur des conteneurs jetables et sur le point de santé de la production.\nRésultats Lors des premières opérations de terrain, les agents ont signalé 32 % des détections comme des erreurs de lecture sur environ une semaine. Cette mesure a motivé les étapes de correction positionnelle et de confirmation par double lecture, et les statistiques du tableau de bord excluent désormais les détections marquées comme faux positifs. Les nouvelles étapes ont été livrées avec des tests unitaires : 12/12 pour la correction des plaques et 6/6 pour la confirmation, les réglages et le journal des lectures. Après l\u0026rsquo;extension de la table de correspondance des noms de modèles, une seule ligne de la liste de rappel de production restait sans nom de modèle décodé. Aucun taux de reconnaissance de bout en bout n\u0026rsquo;a encore été mesuré.\nLimites \u0026amp; suite La précision de la reconnaissance n\u0026rsquo;a pas été mesurée sur un banc d\u0026rsquo;essai avec vérité terrain. Les objectifs du cahier des charges (taux de lecture, latence) sont des objectifs de conception, non des résultats. Aucune lecture de plaque à l\u0026rsquo;ancien format n\u0026rsquo;a été observée au départ. Un compteur dédié suit désormais ces lectures de bout en bout, mais le correctif doit encore être vérifié sur le terrain. Une fausse correspondance avec une liste volumineuse coûte toujours du temps aux agents. L\u0026rsquo;étape suivante consiste à calibrer le seuil de confiance et la fenêtre de confirmation sur des vidéos de terrain annotées. Stack technique Python · FastAPI · SQLite · ONNX Runtime · fast-alpr (détecteur de plaques YOLOv9 + OCR) · OpenCV · PaddleOCR · React · TypeScript · Vite · Leaflet · Docker · Caddy · LUKS · systemd · age · rclone · PyInstaller · PowerShell\n","date":"2026-06-01T00:00:00Z","permalink":"/fr/research/fleet-management/","title":"Identification sur le terrain des véhicules concernés par un rappel"},{"content":"Contexte Les sites industriels sont souvent couverts par des caméras fixes dont les images ne sont consultées qu\u0026rsquo;après un incident et ne produisent aucune donnée exploitable. L\u0026rsquo;objectif était de transformer les caméras existantes, ainsi que des prises de vue ponctuelles par drone, en instrument de mesure : pour chaque objet détecté, une position en latitude/longitude et des distances métriques plutôt qu\u0026rsquo;une boîte en pixels.\nLa difficulté tient à trois raisons. Une caméra unique ne donne pas de profondeur, si bien que l\u0026rsquo;échelle de la scène doit être inférée. La méthode de géoréférencement habituelle, une homographie du plan du sol, suppose un sol plat et échoue silencieusement pour les objets surélevés ou les terrains irréguliers. Enfin, la vidéo haute résolution est coûteuse à traiter, et le raccourci courant consistant à réduire l\u0026rsquo;image à 640 px élimine le détail géométrique dont dépendent les positions au sol.\nApproche flowchart TB A[\"Source vidéofichier · RTSP · séquence drone (jusqu'à 3840×2160)\"] --\u003e B[\"Détecteur d'objets en résolution nativedétection · segmentation · pose · OBB\"] A --\u003e C[\"Modèle de profondeur monoculaire métriquecarte de profondeur\"] B --\u003e D[\"Suivi multi-objetsmodèle de mouvement + association\"] B --\u003e E[\"Profondeur par objetpixels du masque, rejet des aberrants\"] C --\u003e E E --\u003e F[\"Lancer de rayonrayon pixel + profondeur métrique + pose caméra\"] F --\u003e G[\"Position WGS84MNT optionnel pour l'altitude du sol\"] E --\u003e H[\"Distances 3Dentre masques · le long des trajectoires\"] D --\u003e H G --\u003e I[\"Stockage SQLitedétections · pistes · trajectoires GPS\"] H --\u003e I I --\u003e J[\"Analyseszones · flux · superposition sur orthophoto\"]Méthodes Détection. Un détecteur de la famille YOLO, en plusieurs tailles de modèle, dans quatre modes (détection, segmentation, pose, boîtes orientées). L\u0026rsquo;inférence s\u0026rsquo;exécute en résolution native, sans imgsz imposé. La segmentation est le mode par défaut, car les masques fournissent des échantillons de profondeur plus propres que les boîtes. Les poids PyTorch, ONNX, TensorRT et CoreML sont acceptés (CUDA et Apple MPS). Profondeur monoculaire. Un modèle de profondeur monoculaire métrique prédit une carte de profondeur, rééchantillonnée à la taille de l\u0026rsquo;image. La profondeur de chaque objet est une estimation robuste sur les pixels de son masque, après rejet des valeurs aberrantes. Une étape de validation compare la profondeur prédite à des zones de référence dont la distance est connue, afin de détecter une dérive de calibration. Géolocalisation par lancer de rayon. Un rayon est lancé depuis le centre de la caméra à travers le pixel de l\u0026rsquo;objet et arrêté à la profondeur métrique de celui-ci. Le point obtenu est converti du repère caméra vers un repère local Nord-Est-Bas, puis en WGS84. Contrairement à une homographie, cette méthode ne suppose pas un sol plat. Un MNT optionnel fournit l\u0026rsquo;altitude du sol. Les positions peuvent être superposées à une orthophoto géoréférencée pour un contrôle visuel. Suivi. Un module de suivi multi-objets sur mesure, avec un modèle de mouvement, une association tenant compte de la confiance et une étape de fusion des pistes qui relie les fragments selon des seuils d\u0026rsquo;intervalle, de cap et de vitesse. Lorsque la profondeur est disponible, chaque piste conserve une trajectoire 3D, dont sont déduites la distance parcourue et la vitesse en m/s. Distances entre objets. Fonction consolidée ultérieurement dans une bibliothèque de vision réutilisable. Deux objets segmentés sont rétroprojetés en 3D, et la distance minimale point à point est retournée. Des masques qui se chevauchent sont considérés comme en contact. Une simulation de Monte-Carlo perturbe la profondeur, la focale et les positions des pixels pour fournir un écart-type et un intervalle à 95 %. L\u0026rsquo;appartenance à une zone repose sur la part du masque située dans la zone, avec hystérésis, plutôt que sur un test du point central. Ingénierie. La configuration permet une répartition sur deux GPU (détection sur un périphérique, estimation de la profondeur sur l\u0026rsquo;autre), la découverte et l\u0026rsquo;enregistrement de flux RTSP, ainsi que le traitement de plusieurs caméras en parallèle. Résultats Mesures effectuées sur une seule NVIDIA RTX 5090. Le banc d\u0026rsquo;essai de détection ne couvre que la détection et le suivi, profondeur désactivée.\nConfiguration Vidéo Débit Sortie Plus gros détecteur, batch 1 3840×2160, 50 fps, 3 301 images 5,1 fps 320 217 détections, 1 941 pistes Plus petit détecteur, batch 1 3840×2160, 50 fps 13,0 fps 158 989 détections, 908 pistes Plus gros détecteur, batch 1 2304×1296, 15 fps, 5 000 images 17,9 fps 73 502 détections, 2 706 pistes Plus petit détecteur, batch 1 2304×1296, 15 fps 39,0 fps 51 890 détections, 1 499 pistes Chaîne complète (détection + profondeur + suivi + stockage) 2304×1296, 300 images 2,02 fps 12,3 détections par image Sur l\u0026rsquo;exécution de la chaîne complète, l\u0026rsquo;estimation de la profondeur a pris 117,6 s sur 148,3 s au total (environ 80 %), et la détection 20,9 s. Le goulot d\u0026rsquo;étranglement est l\u0026rsquo;estimation de la profondeur, et non le détecteur. Sur des vidéos 4K, le plus gros détecteur tourne environ dix fois plus lentement que le temps réel. Cela convient à l\u0026rsquo;usage visé, à savoir l\u0026rsquo;analyse d\u0026rsquo;archives enregistrées et non l\u0026rsquo;alerte en direct.\nLimites \u0026amp; suite Aucune précision de géolocalisation n\u0026rsquo;a encore été mesurée par rapport à une vérité terrain levée. L\u0026rsquo;étape de lancer de rayon a été ajoutée après les mesures de temps ci-dessus ; son coût n\u0026rsquo;y est donc pas inclus. L\u0026rsquo;échelle métrique dépend du modèle de profondeur ainsi que de la pose et des paramètres intrinsèques de la caméra. Les erreurs d\u0026rsquo;inclinaison ou de focale se répercutent directement sur les positions au sol. Le modèle de profondeur prédit à sa propre résolution interne : le détail fin de la profondeur reste limité, même lorsque la détection s\u0026rsquo;exécute en 4K. Suite : une étude de précision avec des cibles levées au GNSS, le profilage de la répartition sur deux GPU, et la mesure de la justesse des intervalles de distance Monte-Carlo sur des objets à écartements connus. Stack technique Python · PyTorch · OpenCV · NumPy · SciPy · pyproj · rasterio · SQLite · CUDA · Apple MPS\n","date":"2026-01-01T00:00:00Z","permalink":"/fr/research/video-geolocation/","title":"Analyse vidéo géolocalisée et mesure des distances entre objets"},{"content":"Contexte Détecter depuis un drone les polluants gazeux et les hydrocarbures, de jour comme de nuit, afin de surveiller les sources de pollution mobiles (navires, engins) dans les zones maritimes et industrielles.\nChaîne de traitement flowchart TB A[\"Drone — thermique/IR + visible\"] --\u003e B[\"Acquisition jour / nuit\"] B --\u003e C[\"Détection de signatures polluantes\"] C --\u003e D[\"Localisation sur cibles en mouvement\"] D --\u003e E[\"Surveillance maritime / industrielle\"]Méthodes Imagerie combinée thermique/infrarouge et spectre visible. Détection et localisation de traces de polluants sur des cibles en mouvement. Fonctionnement en conditions diurnes comme nocturnes. Résultats Détection de fuites de carburant et de rejets d\u0026rsquo;hydrocarbures dans les zones portuaires et les eaux côtières. Capacité de surveillance continue des zones maritimes et industrielles. Stack technique Python · OpenCV · imagerie thermique/IR · drone\n","date":"2024-07-01T00:00:00Z","permalink":"/fr/research/pollutant-detection/","title":"Détection de polluants par drone (jour \u0026 nuit)"},{"content":"Contexte Les échouements de sargasses perturbent les littoraux caribéens. L\u0026rsquo;objectif : détecter tôt les radeaux d\u0026rsquo;algues en mer et prédire où et en quelle quantité ils s\u0026rsquo;échoueront, afin que les communes et les autorités environnementales puissent planifier à l\u0026rsquo;avance le ramassage — et les interventions en mer.\nLe problème : une réflectance brute difficile à lire Sur une image satellitaire multispectrale brute, les sargasses forment un signal faible sur un fond océanique vaste et variable. Les radeaux sont fins, fragmentés et souvent peu contrastés : leurs bords se fondent dans l\u0026rsquo;eau environnante, et la structure d\u0026rsquo;ensemble d\u0026rsquo;une bande — où elle commence, où elle s\u0026rsquo;amincit, où elle se disloque — est difficile à distinguer à l\u0026rsquo;œil comme avec des indices génériques.\nSavoir qu\u0026rsquo;il y a des sargasses ne suffit pas. Pour agir, il faut voir à quoi elles ressemblent.\nContribution principale : un indicateur de contraste original J\u0026rsquo;ai conçu un indicateur de contraste dédié aux sargasses. Plutôt que de simplement signaler des pixels, il est construit pour donner une lecture très nette des données et des formes : radeaux et bandes ressortent franchement de l\u0026rsquo;eau, avec des contours bien définis et une structure interne préservée. (Détails de formulation non publiés pour l\u0026rsquo;instant.)\nCe qu\u0026rsquo;il apporte :\nUne délimitation nette des radeaux et des bandes allongées de sargasses. Une image lisible de l\u0026rsquo;organisation de la masse, et pas seulement de sa position. Une entrée plus propre pour la segmentation, la quantification et la modélisation de la dérive en aval. Pourquoi la forme compte La géométrie des bandes est l\u0026rsquo;information clé pour les opérations :\nDispersion — les sargasses sont-elles concentrées en un radeau dense ou éparpillées en nombreuses petites plaques ? Traîne — la façon dont la bande s\u0026rsquo;étire et s\u0026rsquo;allonge derrière sa tête, qui révèle comment elle est entraînée par les courants et le vent. Orientation et direction de dérive — vers où se dirige la bande, et donc quelles portions de côte sont exposées. C\u0026rsquo;est la lecture de ces formes qui permet de planifier les interventions sur site (où déployer la collecte en mer ou les barrages) et d\u0026rsquo;anticiper les échouements plutôt que de les subir.\nChaîne de traitement flowchart TB A[\"Imagerie satellitaire — multispectrale\"] --\u003e B[\"Masquage nuages / eau\"] B --\u003e C[\"Indicateur de contraste sargasses original\"] C --\u003e D[\"Délimitation des radeaux \u0026 bandes — forme, dispersion, traîne\"] D --\u003e E[\"Quantification en mer\"] E --\u003e F[\"Modèle de dérive / d'échouement\"] F --\u003e G[\"Alertes \u0026 planification des interventions\"]Méthodes Analyse d\u0026rsquo;images satellitaires multispectrales. Indicateur de contraste original pour une lecture nette des radeaux et bandes de sargasses. Analyse de la forme des bandes : dispersion, allongement/traîne, orientation. Détection des radeaux et quantification de leur surface en mer. Modélisation prédictive de la dérive et des échouements pour anticiper les zones d\u0026rsquo;arrivée et les volumes. Résultats Cartes claires et lisibles des radeaux et bandes de sargasses en mer. Capacité d\u0026rsquo;alerte précoce pour les communes littorales. Prévisions quantitatives des échouements au service d\u0026rsquo;une planification proactive du ramassage et des interventions. Visuels et compléments à venir.\nStack technique Python · imagerie satellitaire · analyse spectrale · modélisation prédictive\n","date":"2024-06-01T00:00:00Z","permalink":"/fr/research/sargassum-detection/","title":"Détection des sargasses par satellite \u0026 prédiction des échouements"},{"content":"Contexte Surveillance non destructive de l\u0026rsquo;état des ponts, bâtiments et infrastructures. L\u0026rsquo;enjeu n\u0026rsquo;est pas seulement de détecter les fissures, mais de les classer selon leur ouverture — sans contact ni échafaudage.\nC\u0026rsquo;est l\u0026rsquo;ouverture qui compte pour l\u0026rsquo;inspection : selon la largeur d\u0026rsquo;une fissure, la méthode de réparation (de remplissage) n\u0026rsquo;est pas la même. Un système d\u0026rsquo;inspection doit donc être très précis, car une mauvaise classe d\u0026rsquo;ouverture conduit à une mauvaise prescription de réparation.\nQuatre classes d\u0026rsquo;ouverture Classe Ouverture Conséquence 1 \u0026lt; 0,3 mm Fissures les plus fines — souvent plus étroites qu\u0026rsquo;un pixel ; réparation spécifique 2 0,3 – 0,7 mm Méthode de réparation différente 3 0,7 – 1 mm Méthode de réparation différente 4 ≥ 1 mm Méthode de réparation différente Chaque classe appelle sa propre méthode de remplissage ou de réparation : la classification conditionne donc directement la décision de maintenance.\nLe défi du sous-pixel La principale difficulté est de descendre sous la taille du pixel. Une fissure de 0,3 mm ne couvre même pas un pixel entier aux résolutions d\u0026rsquo;inspection courantes — et le système doit pourtant la détecter, même lorsque la résolution au sol est un peu plus grossière que 0,3 mm.\nPourquoi est-ce possible ? Une fissure plus fine qu\u0026rsquo;un pixel ne disparaît pas : elle occupe une partie des pixels qu\u0026rsquo;elle traverse et modifie légèrement leur intensité par rapport à la surface environnante. Pris isolément, ce signal de pixel partiel est faible ; mais une fissure est un élément continu et allongé : le même contraste ténu se répète de façon cohérente sur de nombreux pixels voisins. C\u0026rsquo;est en exploitant ce contraste et cette continuité qu\u0026rsquo;on peut détecter la fissure — et estimer son ouverture — au-delà de la résolution nominale de l\u0026rsquo;image.\nAcquisition : drone et smartphone Photographie par drone — acquisition haute résolution des surfaces des ouvrages, pour les structures étendues ou difficiles d\u0026rsquo;accès. Photographie au smartphone — l\u0026rsquo;approche fonctionne aussi sur des images prises au téléphone portable, ce que j\u0026rsquo;ai testé, ce qui permet une inspection rapprochée avec un équipement courant. Chaîne de traitement flowchart TB A[\"Prise de vue — drone ou smartphone\"] --\u003e B[\"Découpage en tuiles \u0026 calibration\"] B --\u003e C[\"Segmentation des fissures — CV / DL\"] C --\u003e D[\"Estimation sous-pixel de l'ouverture\"] D --\u003e E[\"Classification de l'ouverture — 4 classes\"] E --\u003e F[\"Carte des défauts \u0026 rapport d'inspection\"]Méthodes Acquisition haute résolution des surfaces des ouvrages par drone ou smartphone. Segmentation des fissures par vision par ordinateur / apprentissage profond sur béton et maçonnerie. Calibration métrique et analyse sous-pixel pour l\u0026rsquo;estimation de l\u0026rsquo;ouverture des fissures. Classification en quatre classes d\u0026rsquo;ouverture associées aux méthodes de réparation. Résultats Inspection non destructive et reproductible des ouvrages de génie civil. Cartes de défauts géolocalisées pour hiérarchiser les interventions de maintenance. Modèles et visuels à venir.\nStack technique Python · OpenCV · apprentissage profond · drone RVB haute résolution · imagerie smartphone · photogrammétrie\n","date":"2024-03-01T00:00:00Z","permalink":"/fr/research/crack-detection/","title":"Détection de fissures submillimétriques sur ouvrages de génie civil"}]