<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recherche &amp; R&amp;D on Boris Dupoux</title><link>https://borisdupoux.com/fr/research/</link><description>Recent content in Recherche &amp; R&amp;D on Boris Dupoux</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Thu, 01 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://borisdupoux.com/fr/research/index.xml" rel="self" type="application/rss+xml"/><item><title>De la vidéo tournée à la main à la photogrammétrie et au Gaussian Splatting</title><link>https://borisdupoux.com/fr/research/photogrammetry-splatting/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/photogrammetry-splatting/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les sites intérieurs sont souvent documentés avec une caméra sur stabilisateur
tenue à la main plutôt qu&amp;rsquo;avec un scanner de qualité topographique. L&amp;rsquo;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&amp;rsquo;exécute nativement sous Windows sur une RTX 5090 (Blackwell, sm_120)
&lt;strong&gt;partagée avec d&amp;rsquo;autres charges GPU de longue durée&lt;/strong&gt; ; elle ne doit donc jamais les préempter.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["inbox/projet/vidéos + fichier GO"] --&gt; B["Extraction d'images clés&lt;br/&gt;recouvrement par flot optique + netteté"]
 B --&gt; C["SfM COLMAP 4.2.1&lt;br/&gt;SIFT, mapper global"]
 C --&gt; D{"Contrôle qualité : enregistrement, reprojection,&lt;br/&gt;continuité de trajectoire"}
 D -- échec --&gt; C2["Repli : mapper incrémental"] --&gt; D
 D -- succès --&gt; E["OpenMVS 2.4 (build sm_120)&lt;br/&gt;densification, maillage, raffinement, texture"]
 E --&gt; F["Alignement ortho&lt;br/&gt;gravité, sol par RANSAC, lacet Manhattan"]
 F --&gt; G["Rendus Blender&lt;br/&gt;orthos, axonométries, orbite"]
 E --&gt; H["Entraînement gsplat&lt;br/&gt;stratégie MCMC ou par défaut"]
 G --&gt; I["Exports web&lt;br/&gt;Potree, GLB, SOG"]
 H --&gt; I
 I --&gt; J["outbox : livrables, report.json, STATUS"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sélection d&amp;rsquo;images clés guidée par le recouvrement.&lt;/strong&gt; 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&amp;rsquo;une limite de temps est atteinte. Le candidat le plus net (variance du laplacien)
est celui retenu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SfM avec contrôle qualité explicite.&lt;/strong&gt; 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&amp;rsquo;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&amp;rsquo;étape échoue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fiabilisation du MVS.&lt;/strong&gt; Le binaire Windows officiel d&amp;rsquo;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&amp;rsquo;il diverge,
et le nivellement des coutures (qui noircissait des faces) est désactivé.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orthovues prêtes pour la métrique.&lt;/strong&gt; L&amp;rsquo;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&amp;rsquo;échelle. La transformation 4×4 est conservée afin d&amp;rsquo;être réappliquée au
maillage et au splat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gaussian Splatting.&lt;/strong&gt; gsplat 1.6.0 a été compilé pour sm_120 avec CUDA 13 sous
MSVC, ce qui a nécessité des correctifs locaux. L&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exploitation.&lt;/strong&gt; Les projets démarrent en mode dossier surveillé dès qu&amp;rsquo;un fichier GO
apparaît. Les étapes peuvent être reprises ou refaites. Une garde GPU attend qu&amp;rsquo;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 &lt;code&gt;report.json&lt;/code&gt;.
Un contrôle qualité dégradé produit un statut &lt;code&gt;DONE_WITH_ALERTS&lt;/code&gt; plutôt qu&amp;rsquo;un succès silencieux.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Emplacement&lt;/th&gt;
					&lt;th&gt;Images&lt;/th&gt;
					&lt;th&gt;SfM enregistrées / points / reproj.&lt;/th&gt;
					&lt;th&gt;Nuage dense&lt;/th&gt;
					&lt;th&gt;PSNR / SSIM du splat&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;116&lt;/td&gt;
					&lt;td&gt;116/116 · 21 458 · 1,49 px&lt;/td&gt;
					&lt;td&gt;1,40 M&lt;/td&gt;
					&lt;td&gt;23,2 / 0,86&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;103&lt;/td&gt;
					&lt;td&gt;103/103 · 18 972 · 1,75 px&lt;/td&gt;
					&lt;td&gt;1,23 M&lt;/td&gt;
					&lt;td&gt;20,6 / 0,81&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;47&lt;/td&gt;
					&lt;td&gt;47/47 · 13 167 · 1,17 px&lt;/td&gt;
					&lt;td&gt;1,26 M&lt;/td&gt;
					&lt;td&gt;23,1 / 0,86&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;121&lt;/td&gt;
					&lt;td&gt;121/121 · 11 970 · 1,34 px&lt;/td&gt;
					&lt;td&gt;1,99 M&lt;/td&gt;
					&lt;td&gt;21,9 / 0,85 (stratégie par défaut)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;64&lt;/td&gt;
					&lt;td&gt;64/64 · 12 106 · 1,48 px&lt;/td&gt;
					&lt;td&gt;0,91 M&lt;/td&gt;
					&lt;td&gt;21,8 / 0,83&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Toutes les images ont été enregistrées pour chaque emplacement. L&amp;rsquo;erreur de reprojection était de 1,17–1,75 px.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;analyse des métadonnées a révélé des vitesses d&amp;rsquo;obturation de 1/50–1/100 s (environ
14 px de flou de bougé en 4K) ainsi qu&amp;rsquo;une sensibilité ISO et une balance des blancs
automatiques. La compensation d&amp;rsquo;exposition de gsplat (&lt;code&gt;ppisp&lt;/code&gt;) n&amp;rsquo;a apporté aucun gain
(PSNR 20,5 contre 20,6). La limite de qualité tient à la captation, pas au solveur.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Un PSNR d&amp;rsquo;à peine plus de 20 reflète le flou de bougé et l&amp;rsquo;exposition automatique. Le
protocole de captation impose désormais une vitesse d&amp;rsquo;obturation de 1/250–1/500 s, une
exposition et une balance des blancs verrouillées, ainsi qu&amp;rsquo;un passage dédié au sol.&lt;/li&gt;
&lt;li&gt;La fusion de vidéos provenant d&amp;rsquo;emplacements différents a provoqué de faux appariements
et un modèle incohérent ; chaque emplacement est donc traité séparément.&lt;/li&gt;
&lt;li&gt;Les sols carrelés sombres et brillants se reconstruisent mal. L&amp;rsquo;alignement Manhattan
n&amp;rsquo;est pas encore fiable en présence de mobilier et de vitrages.&lt;/li&gt;
&lt;li&gt;Les étapes CPU constituent le goulot d&amp;rsquo;étranglement sur une machine virtuelle à 4 vCPU.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python 3.11&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · &lt;code&gt;Open3D&lt;/code&gt; · &lt;code&gt;NumPy&lt;/code&gt; · &lt;code&gt;COLMAP 4.2.1&lt;/code&gt; · &lt;code&gt;OpenMVS 2.4&lt;/code&gt; · &lt;code&gt;gsplat 1.6.0&lt;/code&gt; · &lt;code&gt;PyTorch 2.14 (CUDA 13)&lt;/code&gt; · &lt;code&gt;Blender 5.2&lt;/code&gt; · &lt;code&gt;FFmpeg&lt;/code&gt; · &lt;code&gt;PotreeConverter&lt;/code&gt; · &lt;code&gt;glTF-Transform&lt;/code&gt; · &lt;code&gt;splat-transform&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Points d'intérêt et flux urbains dans le centre-ville de Fort-de-France à partir de données ouvertes</title><link>https://borisdupoux.com/fr/research/urban-flows-fort-de-france/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/urban-flows-fort-de-france/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;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&amp;rsquo;existe ni compteurs piétons publics, ni chiffres ouverts
de fréquentation des transports en commun, ni comptages routiers ouverts à
l&amp;rsquo;échelle du centre-ville. Le projet cherche à savoir jusqu&amp;rsquo;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 &lt;strong&gt;points d&amp;rsquo;intérêt&lt;/strong&gt; (commerces,
administrations, établissements scolaires, santé, culture, portes d&amp;rsquo;entrée) et
de &lt;strong&gt;flux&lt;/strong&gt; (résidents, navetteurs, élèves, visiteurs, croisiéristes,
véhicules, bus) sur un horizon de dix ans (2016–2026).&lt;/p&gt;
&lt;p&gt;Aucune 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&amp;rsquo;escales montrent les navires, pas les croisiéristes à terre.
La démarche consiste donc à &lt;strong&gt;croiser de nombreuses sources hétérogènes&lt;/strong&gt; 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.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;p&gt;La méthode est issue d&amp;rsquo;un précédent projet de base de connaissances que j&amp;rsquo;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&amp;rsquo;elles. Chaque valeur
conserve sa provenance, et un ensemble d&amp;rsquo;invariants est vérifié à chaque
reconstruction.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A[Catalogue des sources&lt;br/&gt;sources.yaml] --&gt; B[Stockage brut immuable&lt;br/&gt;sha256 + manifeste JSONL]
 C[Collecteurs planifiés&lt;br/&gt;Meta tous les 14 jours · GTFS-RT 60 s] --&gt; B
 B --&gt; D[Extracteurs versionnés&lt;br/&gt;Parquet normalisé]
 D --&gt; E[Entrepôt spatial DuckDB&lt;br/&gt;reconstruit, jamais modifié]
 E --&gt; F[Invariants QA I1–I6]
 E --&gt; G[Statistiques&lt;br/&gt;requetes/*.sql]
 E --&gt; H[Application de bureau&lt;br/&gt;carte + sélecteur temporel]
 G --&gt; I[Calage sur&lt;br/&gt;des signaux mesurés]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Acquisition.&lt;/strong&gt; Chaque téléchargement est haché (SHA-256) et consigné dans
un manifeste JSONL, et l&amp;rsquo;acquisition est idempotente. Les fichiers nationaux
de plus de 1 Go (répertoire Sirene des entreprises) sont lus sous forme
d&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sources éphémères.&lt;/strong&gt; Meta Movement Distribution ne conserve que 90 jours
en ligne : une tâche planifiée l&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cadre spatial.&lt;/strong&gt; Les données sont stockées en WGS84 et calculées en
EPSG:5490 sur la grille INSEE de 200 m. Les points d&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modèles.&lt;/strong&gt; 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&amp;rsquo;échelle de l&amp;rsquo;île, avec affectation
BPR, couvre les visiteurs et le trafic de transit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Qualité.&lt;/strong&gt; Six invariants sont vérifiés, de la provenance à l&amp;rsquo;absence de
données personnelles. Les paramètres non confirmés sont consignés dans un
journal des décisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sources-de-données"&gt;&lt;a href="#sources-de-donn%c3%a9es" class="header-anchor"&gt;&lt;/a&gt;Sources de données
&lt;/h2&gt;&lt;p&gt;Le croisement des sources est le cœur du projet. Les registres d&amp;rsquo;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&amp;rsquo;enquête
nationale de mobilité (MOBPRO, MOBSCO, EMP) disent qui se déplace, pourquoi
et quand. Les flux de transport, d&amp;rsquo;accidents et de qualité de l&amp;rsquo;air
(GTFS-RT, BAAC, Madininair) sont les seules traces mesurées du mouvement. Les
calendriers d&amp;rsquo;escales et les capacités des navires apportent une population
qu&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Le catalogue recense &lt;strong&gt;120 sources&lt;/strong&gt; : 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.&lt;/p&gt;
&lt;h3 id="entreprises-emplois-et-équipements"&gt;&lt;a href="#entreprises-emplois-et-%c3%a9quipements" class="header-anchor"&gt;&lt;/a&gt;Entreprises, emplois et équipements
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/fr/datasets/base-sirene-des-entreprises-et-de-leurs-etablissements-siren-siret/" target="_blank" rel="noopener"
 &gt;Base Sirene des entreprises&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Établissements, code d&amp;rsquo;activité (NAF), dates de création et de fermeture, tranches d&amp;rsquo;effectif&lt;/td&gt;
					&lt;td&gt;Historique complet ; stock reconstituable à toute date 2016–2026&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BODACC — DILA&lt;/td&gt;
					&lt;td&gt;Rotation et défaillances des commerces (ventes de fonds, procédures collectives)&lt;/td&gt;
					&lt;td&gt;2016–2026, quotidienne&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/8217525" target="_blank" rel="noopener"
 &gt;Base permanente des équipements (BPE)&lt;/a&gt; géolocalisée — INSEE&lt;/td&gt;
					&lt;td&gt;Commerces, services, santé, administrations, enseignement, sport, tourisme&lt;/td&gt;
					&lt;td&gt;Éditions 2024 et 2025, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://open.urssaf.fr/explore/dataset/etablissements-et-effectifs-salaries-au-niveau-commune-x-ape-last/" target="_blank" rel="noopener"
 &gt;Établissements et effectifs salariés commune × APE&lt;/a&gt; — URSSAF / Acoss&lt;/td&gt;
					&lt;td&gt;Emploi salarié privé par activité&lt;/td&gt;
					&lt;td&gt;2006–2025, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.education.gouv.fr/explore/dataset/fr-en-annuaire-education/" target="_blank" rel="noopener"
 &gt;Annuaire de l&amp;rsquo;éducation et effectifs d&amp;rsquo;élèves&lt;/a&gt; — MENJ / DEPP&lt;/td&gt;
					&lt;td&gt;Écoles, localisation, élèves par rentrée, personnels&lt;/td&gt;
					&lt;td&gt;Effectifs 2016–2025&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;FINESS — DREES / ARS&lt;/td&gt;
					&lt;td&gt;Établissements sanitaires et sociaux, pharmacies&lt;/td&gt;
					&lt;td&gt;Extraction de mai 2026, bimestrielle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://docs.overturemaps.org/guides/places" target="_blank" rel="noopener"
 &gt;Overture Maps (places)&lt;/a&gt; — Overture Maps Foundation&lt;/td&gt;
					&lt;td&gt;Points d&amp;rsquo;intérêt avec score de confiance (couche de comparaison)&lt;/td&gt;
					&lt;td&gt;Extrait figé de la release 2026-09-23, mensuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OpenStreetMap (Overpass) — contributeurs OpenStreetMap&lt;/td&gt;
					&lt;td&gt;Points d&amp;rsquo;intérêt, commerces, voirie, cheminements piétons&lt;/td&gt;
					&lt;td&gt;État courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Monuments historiques (Mérimée / POP) — ministère de la Culture&lt;/td&gt;
					&lt;td&gt;Attracteurs patrimoniaux (cathédrale, bibliothèque Schœlcher, fort Saint-Louis)&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;23 autres&lt;/em&gt; — par ex. Flores, emploi salarié localisé (INSEE), Foursquare Open Source Places, LOCOMVAC, locaux commerciaux vacants (DGFiP), Google Places&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="population-revenus-et-logement"&gt;&lt;a href="#population-revenus-et-logement" class="header-anchor"&gt;&lt;/a&gt;Population, revenus et logement
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/8647014" target="_blank" rel="noopener"
 &gt;Recensement, bases infracommunales IRIS (RP)&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Résidents, âge, CSP, logements (vacance, motorisation), actifs&lt;/td&gt;
					&lt;td&gt;RP 2016 → RP 2022, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/8229323" target="_blank" rel="noopener"
 &gt;Filosofi par IRIS&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Revenus disponibles et déclarés, pauvreté&lt;/td&gt;
					&lt;td&gt;2016–2021, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/fichier/8735162/Filosofi2021_carreaux_200m_csv.zip" target="_blank" rel="noopener"
 &gt;Filosofi carroyé 200 m, fichiers&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Ménages fiscaux, individus, pauvreté, logements sociaux et âges au carreau de 200 m&lt;/td&gt;
					&lt;td&gt;2015, 2017, 2019, 2021&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Filosofi carroyé 200 m, couche WFS Géoplateforme — INSEE&lt;/td&gt;
					&lt;td&gt;Géométries des carreaux&lt;/td&gt;
					&lt;td&gt;Couche 2015&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/536998cba3a729239d20505e" target="_blank" rel="noopener"
 &gt;IRCOM, impôt sur le revenu par commune&lt;/a&gt; — DGFiP&lt;/td&gt;
					&lt;td&gt;Foyers fiscaux, revenus déclarés&lt;/td&gt;
					&lt;td&gt;2016–2024, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.caf.fr/explore/dataset/s_ben_com_f/information/" target="_blank" rel="noopener"
 &gt;Cafdata&lt;/a&gt; — CNAF&lt;/td&gt;
					&lt;td&gt;Allocataires du RSA, des aides au logement et des prestations familiales&lt;/td&gt;
					&lt;td&gt;2020–2024 (2022 manquant), annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/5a561801c751df42d7fca9b6" target="_blank" rel="noopener"
 &gt;Quartiers prioritaires (QPV)&lt;/a&gt; — ANCT / INSEE&lt;/td&gt;
					&lt;td&gt;Géographie prioritaire, qui inclut le centre-ville&lt;/td&gt;
					&lt;td&gt;Contours 2024&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/61816c6e23197bb34835228e" target="_blank" rel="noopener"
 &gt;LOVAC&lt;/a&gt; — Cerema / DGALN&lt;/td&gt;
					&lt;td&gt;Vacance courte et structurelle (≥ 2 ans) du parc privé&lt;/td&gt;
					&lt;td&gt;Éditions 2020–2026, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;RPLS, parc locatif social — SDES&lt;/td&gt;
					&lt;td&gt;Logements sociaux (adresse, surface, loyer, vacance)&lt;/td&gt;
					&lt;td&gt;2023 et 2025&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Sitadel, permis de construire — SDES&lt;/td&gt;
					&lt;td&gt;Logements et locaux autorisés, commencés, démolis&lt;/td&gt;
					&lt;td&gt;2013–2026, mensuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://files.data.gouv.fr/geo-dvf/latest/csv/" target="_blank" rel="noopener"
 &gt;DVF géolocalisées&lt;/a&gt; — DGFiP / Etalab&lt;/td&gt;
					&lt;td&gt;Mutations immobilières (prix, surfaces, locaux commerciaux)&lt;/td&gt;
					&lt;td&gt;2021–2025, fenêtre glissante de 5 ans&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;8 autres&lt;/em&gt; — par ex. fichiers détail du recensement et populations légales (INSEE), DV3F et Fichiers fonciers (Cerema / DGFiP), population carroyée WorldPop / GHSL&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="mobilité-et-transports"&gt;&lt;a href="#mobilit%c3%a9-et-transports" class="header-anchor"&gt;&lt;/a&gt;Mobilité et transports
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/8582949" target="_blank" rel="noopener"
 &gt;Mobilités professionnelles (MOBPRO)&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Navettes domicile → travail entre communes&lt;/td&gt;
					&lt;td&gt;2016–2022, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/8582969" target="_blank" rel="noopener"
 &gt;Mobilités scolaires (MOBSCO)&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Navettes domicile → études entre communes&lt;/td&gt;
					&lt;td&gt;2016–2022, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/donnees-detaillees-de-lenquete-mobilite-des-personnes-2018-2019" target="_blank" rel="noopener"
 &gt;Enquête mobilité des personnes 2018-2019 (EMP)&lt;/a&gt; — SDES&lt;/td&gt;
					&lt;td&gt;Motifs, horaires de départ et de retour, durées d&amp;rsquo;activité, distances&lt;/td&gt;
					&lt;td&gt;2018–2019&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://transport.data.gouv.fr/datasets/gtfs-urbain-de-la-zone-centre" target="_blank" rel="noopener"
 &gt;GTFS, réseau urbain zone Centre&lt;/a&gt; (Mozaïk, BHNS) — Martinique Transport&lt;/td&gt;
					&lt;td&gt;Offre théorique de transports collectifs&lt;/td&gt;
					&lt;td&gt;Archives depuis juin 2023&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;GTFS-RT, collecte continue — Martinique Transport&lt;/td&gt;
					&lt;td&gt;Vitesses observées des bus, bus en service, remplissage déclaré&lt;/td&gt;
					&lt;td&gt;Depuis le 7 octobre 2026 ; 60 s (positions), 10 min (prévisions)&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://transport.data.gouv.fr/datasets/gtfs-du-reseau-maritime-de-martinique" target="_blank" rel="noopener"
 &gt;GTFS, navettes maritimes&lt;/a&gt; — Martinique Transport&lt;/td&gt;
					&lt;td&gt;Navettes débarquant au front de mer&lt;/td&gt;
					&lt;td&gt;Versions depuis août 2024&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/53698f4ca3a729239d2036df/" target="_blank" rel="noopener"
 &gt;Accidents corporels de la circulation (BAAC)&lt;/a&gt; — ONISR&lt;/td&gt;
					&lt;td&gt;Accidents localisés (piétons, véhicules), avec l&amp;rsquo;heure&lt;/td&gt;
					&lt;td&gt;2016–2024 chargés&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.humdata.org/dataset/movement-distribution" target="_blank" rel="noopener"
 &gt;Movement Distribution&lt;/a&gt; — Meta Data for Good / HDX&lt;/td&gt;
					&lt;td&gt;Part des usagers restés à domicile, à moins de 10 km, entre 10 et 100 km, au-delà de 100 km&lt;/td&gt;
					&lt;td&gt;Quotidienne ; fenêtre de 90 jours, archivée tous les 14 jours&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.humdata.org/dataset/movement-range-maps" target="_blank" rel="noopener"
 &gt;Movement Range Maps&lt;/a&gt; — Meta Data for Good / HDX&lt;/td&gt;
					&lt;td&gt;Variation des déplacements, part des usagers restés sur place&lt;/td&gt;
					&lt;td&gt;Mars 2020 → mai 2022, quotidienne (arrêtée)&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BD TOPO, réseau routier principal — IGN&lt;/td&gt;
					&lt;td&gt;Graphe routier de l&amp;rsquo;île pour l&amp;rsquo;affectation du trafic&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BD TOPO, tronçons de route — IGN&lt;/td&gt;
					&lt;td&gt;Largeur de chaussée, voies et sens, pour métrer le stationnement le long des rues&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Parkings OpenStreetMap — contributeurs OpenStreetMap&lt;/td&gt;
					&lt;td&gt;Parkings, type, capacité déclarée&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;18 autres&lt;/em&gt; — 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)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="tourisme-et-croisière"&gt;&lt;a href="#tourisme-et-croisi%c3%a8re" class="header-anchor"&gt;&lt;/a&gt;Tourisme et croisière
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.cruisemapper.com/ports/fort-de-france-port-2382" target="_blank" rel="noopener"
 &gt;Calendrier des escales du port de Fort-de-France&lt;/a&gt; — CruiseMapper&lt;/td&gt;
					&lt;td&gt;Escales navire par navire, avec heures d&amp;rsquo;arrivée et de départ&lt;/td&gt;
					&lt;td&gt;Mars 2026 → mars 2029 ; archivage mensuel, les mois passés disparaissant du site&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.cruisemapper.com/ships" target="_blank" rel="noopener"
 &gt;Fiches navires&lt;/a&gt; — CruiseMapper&lt;/td&gt;
					&lt;td&gt;Capacité passagers, équipage, jauge des navires en escale&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Bilans de saison de croisière — Comité martiniquais du tourisme (CMT), via la presse&lt;/td&gt;
					&lt;td&gt;Croisiéristes et escales par saison, terminaux de croisière&lt;/td&gt;
					&lt;td&gt;Saisons 2024-2025 et 2025-2026&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.humdata.org/dataset/martinique-daily-port-activity-data-and-shipment-estimates" target="_blank" rel="noopener"
 &gt;PortWatch&lt;/a&gt; — FMI / HDX&lt;/td&gt;
					&lt;td&gt;Escales quotidiennes issues de l&amp;rsquo;AIS&lt;/td&gt;
					&lt;td&gt;2019–2026, quotidienne&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/64808a5811da153f1439914c" target="_blank" rel="noopener"
 &gt;Trafic aérien commercial mensuel&lt;/a&gt; — DGAC&lt;/td&gt;
					&lt;td&gt;Arrivées à l&amp;rsquo;aéroport Martinique Aimé Césaire (saisonnalité touristique)&lt;/td&gt;
					&lt;td&gt;1990–2025, mensuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/hebergements-touristiques-classes-en-france/" target="_blank" rel="noopener"
 &gt;Hébergements touristiques classés&lt;/a&gt; — Atout France&lt;/td&gt;
					&lt;td&gt;Hôtels et résidences classés, chambres et capacité&lt;/td&gt;
					&lt;td&gt;Stock courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.insee.fr/fr/statistiques/2021703" target="_blank" rel="noopener"
 &gt;Capacité des communes en hébergement touristique&lt;/a&gt; — INSEE&lt;/td&gt;
					&lt;td&gt;Hôtels par catégorie, campings, résidences, villages vacances&lt;/td&gt;
					&lt;td&gt;2015–2026, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;7 autres&lt;/em&gt; — par ex. DATAtourisme (ADN Tourisme), enquête de fréquentation hôtelière (INSEE), Inside Airbnb / AirDNA, données d&amp;rsquo;escales du port&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="contexte--météo-air-calendrier-sécurité"&gt;&lt;a href="#contexte--m%c3%a9t%c3%a9o-air-calendrier-s%c3%a9curit%c3%a9" class="header-anchor"&gt;&lt;/a&gt;Contexte : météo, air, calendrier, sécurité
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/donnees-climatologiques-de-base-horaires" target="_blank" rel="noopener"
 &gt;Données climatologiques de base&lt;/a&gt; — Météo-France&lt;/td&gt;
					&lt;td&gt;Pluie, température, vent (stations de Fort-de-France Desaix et du Lamentin)&lt;/td&gt;
					&lt;td&gt;2010–2026, horaire / quotidienne&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Qualité de l&amp;rsquo;air — Madininair&lt;/td&gt;
					&lt;td&gt;NO₂ comme indicateur indirect du trafic, ainsi que PM10, PM2,5, O₃ et H₂S des sargasses&lt;/td&gt;
					&lt;td&gt;Horaire ; NO₂ mensuel 2016–2026&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://www.data.gouv.fr/datasets/bases-statistiques-communale-departementale-et-regionale-de-la-delinquance-enregistree-par-la-police-et-la-gendarmerie-nationales" target="_blank" rel="noopener"
 &gt;Base communale de la délinquance enregistrée&lt;/a&gt; — SSMSI&lt;/td&gt;
					&lt;td&gt;Infractions enregistrées&lt;/td&gt;
					&lt;td&gt;2016–2025, annuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Jours fériés en Martinique — DINUM&lt;/td&gt;
					&lt;td&gt;Calendrier, dont le 22 mai&lt;/td&gt;
					&lt;td&gt;2006–2031&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://data.education.gouv.fr/explore/dataset/fr-en-calendrier-scolaire/" target="_blank" rel="noopener"
 &gt;Calendrier scolaire&lt;/a&gt; — MENJ&lt;/td&gt;
					&lt;td&gt;Vacances scolaires, dont celles de Carnaval&lt;/td&gt;
					&lt;td&gt;2017-2018 → 2026-2027&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Pageviews — Wikimedia Foundation&lt;/td&gt;
					&lt;td&gt;Intérêt en ligne pour Fort-de-France, le Carnaval et le patrimoine&lt;/td&gt;
					&lt;td&gt;2016–2026, mensuelle&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;4 autres&lt;/em&gt; — par ex. lumières nocturnes NASA Black Marble, Google Trends / GDELT, agenda des événements (à constituer)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="géographie-et-fonds-de-carte"&gt;&lt;a href="#g%c3%a9ographie-et-fonds-de-carte" class="header-anchor"&gt;&lt;/a&gt;Géographie et fonds de carte
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Apport&lt;/th&gt;
					&lt;th&gt;Période / fréquence&lt;/th&gt;
					&lt;th&gt;Statut&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Périmètres d&amp;rsquo;étude — projet&lt;/td&gt;
					&lt;td&gt;Centre-ville et centre élargi (provisoires, voir D1)&lt;/td&gt;
					&lt;td&gt;Version 0.1&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;API Découpage administratif (geo.api.gouv.fr) — DINUM / IGN / INSEE&lt;/td&gt;
					&lt;td&gt;Contour de la commune et population légale&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Contours IRIS — IGN / INSEE&lt;/td&gt;
					&lt;td&gt;Maille infracommunale du recensement&lt;/td&gt;
					&lt;td&gt;Couche courante&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://cartes.gouv.fr/rechercher-une-donnee/dataset/IGNF_BD-TOPO" target="_blank" rel="noopener"
 &gt;BD TOPO&lt;/a&gt; — IGN&lt;/td&gt;
					&lt;td&gt;Bâtiments (hauteur, usage), voirie, équipements&lt;/td&gt;
					&lt;td&gt;Éditions trimestrielles&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BD TOPO, bâtiments résidentiels du centre élargi — IGN&lt;/td&gt;
					&lt;td&gt;Usage, hauteur et emprise, pour répartir les ménages dans les bâtiments&lt;/td&gt;
					&lt;td&gt;Édition courante&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Fond de carte vectoriel OpenStreetMap — contributeurs OpenStreetMap&lt;/td&gt;
					&lt;td&gt;Voirie, eau, parcs, littoral dessinés dans l&amp;rsquo;application&lt;/td&gt;
					&lt;td&gt;Courant&lt;/td&gt;
					&lt;td&gt;Intégrée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;em&gt;9 autres&lt;/em&gt; — par ex. cadastre Etalab, Base Adresse Nationale, BD ORTHO (IGN), PLU (Géoportail de l&amp;rsquo;Urbanisme), risques naturels (Géorisques)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Cataloguées&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="lapplication--cœur-de-ville-"&gt;&lt;a href="#lapplication--c%c5%93ur-de-ville-" class="header-anchor"&gt;&lt;/a&gt;L&amp;rsquo;application « Cœur de ville »
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;entrepôt s&amp;rsquo;explore dans une application de bureau (Electron, React, ECharts,
Leaflet sur OpenStreetMap, DuckDB lisant une copie de l&amp;rsquo;entrepôt). Elle est organisée
autour de quelques questions — qui est là, quand, qu&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran de synthèse : indicateurs clés, carte de présence en matinée au carreau de 200 m, rythme de la journée par population et flux horaires de voitures" class="gallery-image" data-flex-basis="395px" data-flex-grow="164" height="972" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-synthese.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-synthese_hu_1325b374e6fd7abc.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-synthese.jpg 1600w" width="1600"&gt;
&lt;em&gt;Synthèse — le centre en un coup d&amp;rsquo;œil : rapport jour/nuit, pression de stationnement,
commerces 2016 → 2026, pauvreté, prochaine grosse journée d&amp;rsquo;escale, présence au
carreau de 200 m et rythme de la journée des résidents, salariés, scolaires et touristes.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran des flux : carte animée de la présence par créneau et tableau semaine × créneau" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-flux.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-flux_hu_f9fb52a2d7d7124a.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-flux.jpg 1500w" width="1500"&gt;
&lt;em&gt;Flux 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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran des points d’intérêt : des milliers d’établissements par famille, carreaux les plus attractifs et courbes d’ouverture" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-poles.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-poles_hu_cf9d8514fb9c8d3d.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-poles.jpg 1500w" width="1500"&gt;
&lt;em&gt;Pôles d&amp;rsquo;attractivité — les établissements par famille (répertoire Sirene et
OpenStreetMap), les carreaux les plus attractifs au moment choisi et la part
d&amp;rsquo;établissements ouverts heure par heure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Zoom à la rue : façade numéro par numéro, carte du secteur et évolution base 100" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-ilot-perrinon.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-ilot-perrinon_hu_7d284fe42d9fc670.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-ilot-perrinon.jpg 1500w" width="1500"&gt;
&lt;em&gt;Zoom sur un îlot — la façade de la rue numéro par numéro, les établissements actifs et
fermés depuis 2016, et l&amp;rsquo;évolution du secteur comparée à l&amp;rsquo;ensemble du centre.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran Évolution : score d’attractivité par carreau avec un curseur d’années 2016–2026 et indicateurs associés" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-evolution.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-evolution_hu_1eb289eca6678a0e.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-evolution.jpg 1500w" width="1500"&gt;
&lt;em&gt;Évolution 2016–2026 — l&amp;rsquo;attractivité par carreau avec un curseur d&amp;rsquo;années, les
créations et fermetures, les foyers fiscaux et d&amp;rsquo;autres signaux croisés sur la même
grille.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran Stationnement : taux d’occupation théorique par carreau avec des hypothèses réglables en direct" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-stationnement.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-stationnement_hu_8141213c09f19e60.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-stationnement.jpg 1500w" width="1500"&gt;
&lt;em&gt;Stationnement — l&amp;rsquo;offre reconstruite rue par rue et le taux d&amp;rsquo;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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Pression de stationnement un matin de semaine : carreaux colorés par le taux d’occupation théorique, hypothèses et tableau semaine × créneau" class="gallery-image" data-flex-basis="425px" data-flex-grow="177" height="846" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-pression-parking.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-pression-parking_hu_48b3b457873b0ba9.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-pression-parking.jpg 1500w" width="1500"&gt;
&lt;em&gt;Pression 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&amp;rsquo;occupation théorique supérieur à 1 les matinées de semaine,
alors que les soirées et le week-end restent nettement en dessous.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran Escales et événements : calendrier annuel des escales, navires du jour et croisiéristes à terre par heure" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-escales.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-escales_hu_712bc4be717471d7.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-escales.jpg 1500w" width="1500"&gt;
&lt;em&gt;Escales et événements — le calendrier annuel des escales avec les jours fériés et les
vacances scolaires, les navires d&amp;rsquo;une journée et l&amp;rsquo;estimation des croisiéristes à terre
heure par heure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran Sources et hypothèses : catalogue des sources consultable avec statut d’intégration, paramètres de modélisation et journal des acquisitions" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="1122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/urban-flows-fort-de-france/app-sources.jpg" srcset="https://borisdupoux.com/research/urban-flows-fort-de-france/app-sources_hu_e0417d4e381ce409.jpg 800w, https://borisdupoux.com/research/urban-flows-fort-de-france/app-sources.jpg 1500w" width="1500"&gt;
&lt;em&gt;Sources 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.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;Le projet a démarré en octobre 2026 et en est à un &lt;strong&gt;stade précoce, non
calé&lt;/strong&gt; (application v0.6.0). Tous les chiffres relatifs au centre-ville
dépendent d&amp;rsquo;un périmètre provisoire (voir ci-dessous). Chaque résultat
ci-dessous précise les sources qu&amp;rsquo;il croise : aucun ne pourrait être obtenu à
partir d&amp;rsquo;un seul jeu de données.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Catalogue.&lt;/strong&gt; 120 sources sont cataloguées, dont 51 intégrées.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entrepôt (première construction).&lt;/strong&gt; 117 161 entités, environ 25 000
mesures et 1 278 indicateurs, avec les 6 invariants validés.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Déclin commercial et résidents (mesuré, registres × recensement ×
données fiscales).&lt;/strong&gt; Le nombre d&amp;rsquo;établissements actifs d&amp;rsquo;é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&amp;rsquo;achat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rythme jour/nuit (modélisé, six sources croisées).&lt;/strong&gt; 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&amp;rsquo;effectif
Sirene ; les élèves, de l&amp;rsquo;annuaire de l&amp;rsquo;é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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vitesse observée des bus et modèle (GTFS-RT × graphe routier × enquêtes
de mobilité).&lt;/strong&gt; 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&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contrôle croisière (escales × capacités des navires × effectifs
publiés).&lt;/strong&gt; 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&amp;rsquo;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&amp;rsquo;agit donc d&amp;rsquo;un contrôle de
cohérence, pas d&amp;rsquo;une validation indépendante.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;D1 : le périmètre du centre-ville est provisoire.&lt;/strong&gt; Il s&amp;rsquo;agit d&amp;rsquo;un
rectangle autour du noyau historique, complété d&amp;rsquo;une zone élargie de 1 km,
utilisé dans l&amp;rsquo;attente d&amp;rsquo;un périmètre officiel. Tous les chiffres relatifs
au centre-ville en dépendent.&lt;/li&gt;
&lt;li&gt;Aucune donnée de comptage piéton, de fréquentation ou de comptage routier
n&amp;rsquo;est ouverte. Les rythmes horaires, les poids d&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;Le stock d&amp;rsquo;établissements 2016–2026 est reconstitué uniquement à partir des
dates de création et de fermeture.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prochaines étapes :&lt;/strong&gt; accumuler plusieurs mois de données GTFS-RT pour
mesurer la congestion, solliciter des données d&amp;rsquo;enquête et de comptage, et
caler la présence sur des comptages de terrain.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;DuckDB&lt;/code&gt; (spatial, httpfs) · &lt;code&gt;Parquet&lt;/code&gt; · &lt;code&gt;SQL&lt;/code&gt; · &lt;code&gt;GTFS / GTFS-RT&lt;/code&gt; · &lt;code&gt;pytest&lt;/code&gt; · &lt;code&gt;ruff&lt;/code&gt; · &lt;code&gt;Electron&lt;/code&gt; · &lt;code&gt;React&lt;/code&gt; · &lt;code&gt;TypeScript&lt;/code&gt; · &lt;code&gt;ECharts&lt;/code&gt; · &lt;code&gt;Leaflet&lt;/code&gt; · &lt;code&gt;GitHub Actions&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Un agent IA entièrement local, avec graphe de sens et mesure multimodale des émotions</title><link>https://borisdupoux.com/fr/research/local-ai-agent/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/local-ai-agent/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;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&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;objectif est un agent qui réponde à des questions sur sa propre vie tout en maintenant
une séparation stricte entre ce qui est &lt;em&gt;observé&lt;/em&gt;, ce qui est &lt;em&gt;calculé&lt;/em&gt;, ce qui est
&lt;em&gt;supposé par un modèle&lt;/em&gt; et ce qui est &lt;em&gt;accepté comme vrai par son propriétaire&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="ce-qui-est-original"&gt;&lt;a href="#ce-qui-est-original" class="header-anchor"&gt;&lt;/a&gt;Ce qui est original
&lt;/h2&gt;&lt;p&gt;Les agents locaux sur des fichiers personnels ne sont pas nouveaux. Deux aspects de ce
projet le sont.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Un graphe de sens au-dessus d&amp;rsquo;une couche de mesure.&lt;/strong&gt; La connaissance est organisée
à deux niveaux. Un &lt;em&gt;observatoire&lt;/em&gt; stocke faits et signaux au format long (élément,
dimension, valeur, confiance, modèle, version). Au-dessus, un &lt;strong&gt;graphe de sens&lt;/strong&gt; stocke ce
que ces signaux &lt;em&gt;signifient&lt;/em&gt; : des &lt;strong&gt;relations&lt;/strong&gt; (réifiées, pour qu&amp;rsquo;une relation puisse
évoluer et se mesurer), des &lt;strong&gt;épisodes affectifs&lt;/strong&gt; (qui a ressenti quoi, quand, avec quelle
intensité, par quelle modalité), des &lt;strong&gt;thèmes&lt;/strong&gt;, des &lt;strong&gt;chapitres&lt;/strong&gt; de vie et des
&lt;strong&gt;vérités&lt;/strong&gt; — 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&amp;rsquo;à l&amp;rsquo;élément source, ainsi qu&amp;rsquo;une origine classée par degré de confiance
(humain &amp;gt; déclaré &amp;gt; structurel &amp;gt; règle/calcul &amp;gt; éditeur &amp;gt; modèle &amp;gt; inféré).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Des émotions mesurées à travers les modalités, selon des dimensions atypiques.&lt;/strong&gt; Le
même vocabulaire fixe de &lt;strong&gt;53 émotions&lt;/strong&gt; (fondé sur Plutchik, chacune dotée de coordonnées
de valence et d&amp;rsquo;éveil) s&amp;rsquo;applique aux &lt;strong&gt;messages&lt;/strong&gt; (LLM local), à la &lt;strong&gt;voix&lt;/strong&gt; (cinq couches
acoustiques et multimodales fusionnées avec la transcription, avec un signalement explicite
du &lt;em&gt;désaccord&lt;/em&gt; entre texte et voix) et aux &lt;strong&gt;photos&lt;/strong&gt; (mesures déterministes de couleur et
de lumière, plongements SigLIP, signaux de visage traités comme des indices faibles). Ces
mesures s&amp;rsquo;inscrivent dans un catalogue de &lt;strong&gt;929 dimensions réparties en 88 groupes&lt;/strong&gt;, qui
va bien au-delà des métadonnées habituelles. Quelques-unes de ses entrées les moins
courantes :&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;modalité&lt;/th&gt;
					&lt;th&gt;dimension&lt;/th&gt;
					&lt;th&gt;définition&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;température de couleur&lt;/td&gt;
					&lt;td&gt;équilibre moyen rouge–bleu de l&amp;rsquo;image (chaud ou froid)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;colorfulness&lt;/td&gt;
					&lt;td&gt;métrique de couleurs opposées de Hasler &amp;amp; Süsstrunk (2003)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;heure dorée / heure bleue&lt;/td&gt;
					&lt;td&gt;élévation du soleil calculée hors ligne à partir de la date et de la position&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;photo&lt;/td&gt;
					&lt;td&gt;taille du visage&lt;/td&gt;
					&lt;td&gt;part de l&amp;rsquo;image occupée par un visage (indice de proximité)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voix&lt;/td&gt;
					&lt;td&gt;jitter, shimmer, rapport harmoniques/bruit&lt;/td&gt;
					&lt;td&gt;prosodie openSMILE eGeMAPS&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voix&lt;/td&gt;
					&lt;td&gt;rires, pleurs, soupirs&lt;/td&gt;
					&lt;td&gt;détection d&amp;rsquo;événements sonores (classes AudioSet)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;voix&lt;/td&gt;
					&lt;td&gt;désaccord texte/voix&lt;/td&gt;
					&lt;td&gt;valence de la voix et valence de la transcription écartées d&amp;rsquo;au moins 0,6&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;message&lt;/td&gt;
					&lt;td&gt;valence, éveil, ton&lt;/td&gt;
					&lt;td&gt;par participant, contraints à la grille fixe&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;message&lt;/td&gt;
					&lt;td&gt;ponctuation expressive, palette d&amp;rsquo;emojis&lt;/td&gt;
					&lt;td&gt;mesures déterministes du texte&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;asymétrie de latence de réponse&lt;/td&gt;
					&lt;td&gt;logarithme du rapport des délais médians de réponse des deux parties&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;initiatives&lt;/td&gt;
					&lt;td&gt;conversations ouvertes après 3 h de silence, de chaque côté&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;relation&lt;/td&gt;
					&lt;td&gt;tendance&lt;/td&gt;
					&lt;td&gt;pente de l&amp;rsquo;intensité de la relation sur 90 jours (refroidissement &amp;lt; 0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;période&lt;/td&gt;
					&lt;td&gt;nostalgie musicale&lt;/td&gt;
					&lt;td&gt;âge moyen des titres écoutés&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;période&lt;/td&gt;
					&lt;td&gt;création / consommation&lt;/td&gt;
					&lt;td&gt;temps passé sur des outils de création ÷ temps de consommation&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="des-signaux-au-sens"&gt;&lt;a href="#des-signaux-au-sens" class="header-anchor"&gt;&lt;/a&gt;Des signaux au sens
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 PH["Photo"] --&gt; PM["Mesures&lt;br/&gt;lumière · contraste · température de couleur&lt;br/&gt;colorfulness · palette · netteté"]
 PH --&gt; PS["Plongement SigLIP&lt;br/&gt;(similarité image ↔ texte)"]
 PH --&gt; PF["Signaux de visage de l'éditeur&lt;br/&gt;sourire · expression · regard · taille du visage"]
 VN["Note vocale"] --&gt; VT["Transcription Whisper"]
 VN --&gt; VL["Couches acoustiques&lt;br/&gt;valence/éveil/dominance · catégories&lt;br/&gt;événements sonores · prosodie · LLM audio"]
 VT --&gt; VX["Émotion du texte de la transcription"]
 VL --&gt; VF["Fusion pondérée&lt;br/&gt;confiance = accord&lt;br/&gt;signalement du désaccord texte/voix"]
 VX --&gt; VF
 MS["Messages&lt;br/&gt;(pseudonymisés : Moi, P1, P2)"] --&gt; ML["LLM local, grille fixe&lt;br/&gt;émotion · intensité · valence&lt;br/&gt;éveil · ton · sujets"]
 PM --&gt; OB[("Observatoire&lt;br/&gt;929 dimensions")]
 PS --&gt; OB
 PF --&gt; OB
 VF --&gt; OB
 ML --&gt; OB
 OB -- "émotion suffisamment sûre" --&gt; AFF["Épisode affectif (AFF)&lt;br/&gt;qui · émotion · quand · intensité · modalité"]
 PF -. "indice faible, confiance ≤ 0,4" .-&gt; AFF
 ML -- "sujets" --&gt; THM["Thèmes"]
 OB -- "agrégats" --&gt; AG["Indicateurs par jour / période&lt;br/&gt;valence · lumière · palette"]
 AFF --&gt; G["Graphe de sens&lt;br/&gt;relations · épisodes · thèmes · chapitres · vérités&lt;br/&gt;(tous proposés)"]
 THM --&gt; G
 AG --&gt; G
 G --&gt; HV(("Propriétaire&lt;br/&gt;valider · rejeter · corriger"))&lt;/pre&gt;&lt;p&gt;Chaque épisode affectif est un nœud relié à la personne qui l&amp;rsquo;a ressenti, à l&amp;rsquo;émotion du
vocabulaire fixe et — lorsqu&amp;rsquo;il existe — à la conversation ou au moment où il s&amp;rsquo;est produit.
Des règles d&amp;rsquo;inférence font ensuite remonter l&amp;rsquo;affect (par exemple l&amp;rsquo;affect d&amp;rsquo;un chapitre ou
d&amp;rsquo;une routine), et les corrélations fortes entre agrégats peuvent devenir des vérités
&lt;em&gt;proposées&lt;/em&gt;, avec leurs mesures pour preuves.&lt;/p&gt;
&lt;h2 id="la-mesure-des-émotions-en-détail"&gt;&lt;a href="#la-mesure-des-%c3%a9motions-en-d%c3%a9tail" class="header-anchor"&gt;&lt;/a&gt;La mesure des émotions en détail
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Vocabulaire.&lt;/strong&gt; 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 &lt;strong&gt;53 au total&lt;/strong&gt;. 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&amp;rsquo;humeur de l&amp;rsquo;application Santé sont rattachées à la grille.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Messages.&lt;/strong&gt; 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&amp;rsquo;émotion dominante prise dans la grille (ou aucune), l&amp;rsquo;intensité, la valence, l&amp;rsquo;é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&amp;rsquo;est proposé que
si la confiance atteint au moins 0,3.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Voix.&lt;/strong&gt; Chaque enregistrement est converti en mono 16 kHz puis passe par :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Whisper large-v3-turbo (MLX) pour la transcription ;&lt;/li&gt;
&lt;li&gt;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&amp;rsquo;éveil ;&lt;/li&gt;
&lt;li&gt;emotion2vec+ large pour l&amp;rsquo;émotion catégorielle, rattachée à la grille (retenue à
partir de 0,4) ;&lt;/li&gt;
&lt;li&gt;un classifieur AST AudioSet pour les rires, pleurs, soupirs, cris, chuchotements,
la musique et l&amp;rsquo;ambiance ;&lt;/li&gt;
&lt;li&gt;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 ;&lt;/li&gt;
&lt;li&gt;Qwen2.5-Omni-7B (llama.cpp, Metal), qui écoute l&amp;rsquo;audio et renvoie une émotion de la
grille, une valence et de brefs indices acoustiques ;&lt;/li&gt;
&lt;li&gt;le modèle d&amp;rsquo;émotion du texte décrit ci-dessus, appliqué à la transcription.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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. &lt;strong&gt;La confiance correspond à l&amp;rsquo;accord
entre les couches&lt;/strong&gt; : une source d&amp;rsquo;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&amp;rsquo;au moins
0,6 en valence (un « ça va » dit tristement), un &lt;strong&gt;désaccord texte/voix&lt;/strong&gt; est signalé au
lieu d&amp;rsquo;être noyé dans une moyenne. Les scores de rires et de pleurs sont conservés à côté.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Photos.&lt;/strong&gt; 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&amp;rsquo;éditeur
(sourire, type de sourire, expression, regard, état des yeux, taille du visage) sont lus
comme des signaux, mais le schéma pose qu&amp;rsquo;&lt;em&gt;un sourire photographié n&amp;rsquo;est pas une joie
ressentie&lt;/em&gt; : la modalité visage est un indice faible, dont la confiance est plafonnée à
0,4. L&amp;rsquo;humeur musicale est traitée de la même façon : l&amp;rsquo;humeur d&amp;rsquo;un morceau n&amp;rsquo;est jamais, à
elle seule, une preuve de l&amp;rsquo;humeur de l&amp;rsquo;auditeur. À l&amp;rsquo;échelle d&amp;rsquo;une période, la valence est
fusionnée selon une priorité fixe : déclarée &amp;gt; voix &amp;gt; texte &amp;gt; visage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validation humaine.&lt;/strong&gt; Chaque épisode, thème, chapitre ou vérité est émis avec le statut
&lt;code&gt;proposed&lt;/code&gt;. La PWA présente une file de validation — les épisodes affectifs classés par
confiance, accompagnés de leur preuve (la conversation ou l&amp;rsquo;enregistrement d&amp;rsquo;origine) — et
le propriétaire valide, rejette ou corrige. Seul cet événement de décision humaine fait
passer une proposition à &lt;code&gt;validated&lt;/code&gt;, équivalence vérifiée automatiquement. L&amp;rsquo;étape
suivante prévue est un petit classifieur personnel sur les caractéristiques emotion2vec,
entraîné sur ces validations.&lt;/p&gt;
&lt;h2 id="architecture"&gt;&lt;a href="#architecture" class="header-anchor"&gt;&lt;/a&gt;Architecture
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 S["Sources (instantanés en lecture seule)&lt;br/&gt;messageries · courriels · photos · musique · notes · agenda · exports"]
 C["Connecteurs&lt;br/&gt;processus d'ingestion dédié, seul détenteur de l'accès disque"]
 V["Coffre (propriétaire seul, 0700)&lt;br/&gt;stockage brut adressé par contenu"]
 O["Observatoire&lt;br/&gt;faits + signaux (SQLite)"]
 K["Graphe de sens&lt;br/&gt;journal JSONL en ajout seul → repli SQLite + FTS"]
 N["Chaînes nocturnes / horaires&lt;br/&gt;vignettes · mesures · SigLIP · émotions&lt;br/&gt;(verrou GPU, un modèle à la fois)"]
 M["Serveur MCP (stdio, sans port)&lt;br/&gt;20 outils en lecture seule / proposition seule"]
 H["Hermes Agent&lt;br/&gt;LLM local via Ollama"]
 P["PWA (HTTPS + TOTP)&lt;br/&gt;discussion · file de validation"]
 U(("Propriétaire"))
 S --&gt; C --&gt; V --&gt; O --&gt; K
 N --&gt; O
 O --&gt; M
 K --&gt; M
 M --&gt; H --&gt; P
 P -- "valider / rejeter / corriger" --&gt; K
 U -- "VPN NetBird" --&gt; P&lt;/pre&gt;&lt;p&gt;Les données brutes sont capturées sous forme d&amp;rsquo;instantanés (SQLite ouvert en
&lt;code&gt;mode=ro&amp;amp;immutable=1&lt;/code&gt;) 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&amp;rsquo;atomes : un journal d&amp;rsquo;événements JSONL en ajout seul, validé par schéma et replié dans
un index SQLite jetable.&lt;/p&gt;
&lt;p&gt;Le schéma est lui-même une donnée, vérifiée mécaniquement : &lt;strong&gt;27 types de nœuds et
50 prédicats&lt;/strong&gt;, &lt;strong&gt;9 origines de provenance&lt;/strong&gt;, &lt;strong&gt;31 types de localisateurs&lt;/strong&gt; qui rattachent
chaque assertion à son élément source, le vocabulaire de 53 émotions, &lt;strong&gt;17 règles
d&amp;rsquo;inférence&lt;/strong&gt; et &lt;strong&gt;42 sources&lt;/strong&gt; 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).&lt;/p&gt;
&lt;h2 id="modèle-de-sécurité"&gt;&lt;a href="#mod%c3%a8le-de-s%c3%a9curit%c3%a9" class="header-anchor"&gt;&lt;/a&gt;Modèle de sécurité
&lt;/h2&gt;&lt;p&gt;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 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aucune capacité ambiante.&lt;/strong&gt; Le framework d&amp;rsquo;agent (Hermes Agent) a 20 ensembles
d&amp;rsquo;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&amp;rsquo;accès au modèle est un serveur
Ollama en boucle locale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Une interface unique et étroite.&lt;/strong&gt; 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&amp;rsquo;accès sans contenu. Les outils peuvent &lt;em&gt;proposer&lt;/em&gt;, jamais &lt;em&gt;décider&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Séparation des privilèges et pseudonymisation.&lt;/strong&gt; Seule l&amp;rsquo;ingestion dispose de l&amp;rsquo;accès
complet au disque ; l&amp;rsquo;analyse n&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Niveaux de sensibilité&lt;/strong&gt; (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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exclusions éthiques&lt;/strong&gt; : l&amp;rsquo;origine ethnique, la couleur de peau et le genre inférés par
les éditeurs ne sont jamais lus.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="modèles"&gt;&lt;a href="#mod%c3%a8les" class="header-anchor"&gt;&lt;/a&gt;Modèles
&lt;/h2&gt;&lt;p&gt;Toute l&amp;rsquo;inférence est locale ; un seul grand modèle est chargé à la fois, sous un verrou
GPU partagé.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;tâche&lt;/th&gt;
					&lt;th&gt;modèle&lt;/th&gt;
					&lt;th&gt;environnement d&amp;rsquo;exécution&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;agent (usage d&amp;rsquo;outils, contexte ≥ 64k)&lt;/td&gt;
					&lt;td&gt;gpt-oss:20b, qwen3:8b en repli&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;émotions du texte, émotions des transcriptions vocales&lt;/td&gt;
					&lt;td&gt;Qwen3-30B-A3B-Instruct-2507 (Q4)&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;plongements texte / image&lt;/td&gt;
					&lt;td&gt;bge-m3 · SigLIP so400m&lt;/td&gt;
					&lt;td&gt;Ollama · PyTorch MPS&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;lecture d&amp;rsquo;images&lt;/td&gt;
					&lt;td&gt;qwen3-vl:8b&lt;/td&gt;
					&lt;td&gt;Ollama&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;transcription de la parole&lt;/td&gt;
					&lt;td&gt;Whisper large-v3-turbo&lt;/td&gt;
					&lt;td&gt;MLX&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;émotion vocale (5 couches)&lt;/td&gt;
					&lt;td&gt;wav2vec2 dimensionnel · emotion2vec+ · AST · openSMILE eGeMAPS · Qwen2.5-Omni-7B&lt;/td&gt;
					&lt;td&gt;PyTorch MPS · CPU · llama.cpp (Metal)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;h2 id="évaluation--résultats"&gt;&lt;a href="#%c3%a9valuation--r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Évaluation &amp;amp; résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Qualité des réponses de l&amp;rsquo;agent.&lt;/strong&gt; Un banc d&amp;rsquo;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 &lt;em&gt;fidélité numérique&lt;/em&gt; (chaque nombre de la réponse doit figurer dans
les sorties d&amp;rsquo;outils de ce tour), l&amp;rsquo;exactitude, la gestion des pièges et le signalement
des périodes partielles : &lt;strong&gt;73 % → 100 %&lt;/strong&gt; après des corrections des descriptions
d&amp;rsquo;outils, de la validation des arguments et de la configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correction des erreurs côté serveur.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contexte et latence.&lt;/strong&gt; Descriptions d&amp;rsquo;outils réduites de 23,5 k à 9,5 k caractères ;
une requête d&amp;rsquo;agrégation lourde passée de 172 s à 0,1 s ; toutes les requêtes lourdes du
banc d&amp;rsquo;essai en ≤ 0,3 s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Banc d&amp;rsquo;essai d&amp;rsquo;exploration croisée.&lt;/strong&gt; 60 scénarios écrits uniquement avec des valeurs
fictives, chacun doté d&amp;rsquo;un oracle ; les oracles passent 61/61, sans aucune fuite aux
plafonds de sensibilité à distance 1 et 2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vérification.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;p&gt;Les jeux d&amp;rsquo;é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&amp;rsquo;éveil du vocabulaire sont des valeurs
de départ, et le calibrage personnel de l&amp;rsquo;émotion vocale à partir d&amp;rsquo;exemples validés reste
à réaliser, de même que le modèle d&amp;rsquo;agent cible, plus grand. Les réponses de l&amp;rsquo;agent
prennent plusieurs dizaines de secondes avec un modèle de 20B.&lt;/p&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;SQLite / FTS5&lt;/code&gt; · &lt;code&gt;Ollama&lt;/code&gt; · &lt;code&gt;llama.cpp (Metal)&lt;/code&gt; · &lt;code&gt;MLX&lt;/code&gt; · &lt;code&gt;PyTorch MPS&lt;/code&gt; · &lt;code&gt;Hermes Agent&lt;/code&gt; · &lt;code&gt;MCP&lt;/code&gt; · &lt;code&gt;SigLIP&lt;/code&gt; · &lt;code&gt;Whisper&lt;/code&gt; · &lt;code&gt;emotion2vec&lt;/code&gt; · &lt;code&gt;openSMILE&lt;/code&gt; · &lt;code&gt;NetBird&lt;/code&gt; · &lt;code&gt;PWA&lt;/code&gt; · &lt;code&gt;launchd&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Atomes de traitement explicables pour documents et données</title><link>https://borisdupoux.com/fr/research/processing-atoms/</link><pubDate>Tue, 01 Sep 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/processing-atoms/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Des systèmes de production pour le rapprochement documentaire et l&amp;rsquo;OCR, développés pour
des clients tels qu&amp;rsquo;un grossiste distributeur et un cabinet d&amp;rsquo;expertise comptable, ont
laissé plusieurs bases de code résolvant chacune les mêmes sous-problèmes (routage des
pages, réglage de l&amp;rsquo;OCR, extraction par LLM, comparaison de champs) avec leurs propres
bogues. La bibliothèque d&amp;rsquo;atomes les consolide en un seul paquet. Sa question centrale est
celle qui sous-tendait les systèmes d&amp;rsquo;origine : &lt;strong&gt;peut-on automatiser un contrôle documentaire
de sorte qu&amp;rsquo;un humain puisse auditer et contester chaque verdict ?&lt;/strong&gt; Extraire un champ ne
suffit pas. Le système doit indiquer si deux documents concordent, pourquoi, et sur la base
de quels éléments.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;p&gt;Tout est construit à partir d&amp;rsquo;&lt;strong&gt;atomes&lt;/strong&gt;. 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&amp;rsquo;atomes, soit écrite
en code, soit déclarée sous forme de recette YAML validée au chargement, avant toute exécution.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Documents d'entrée (PDF, numérisations, CSV, courriels)"] --&gt; B{"Routage des pages : texte natif ou OCR ?"}
 B -- "natif" --&gt; C["Texte natif positionné"]
 B -- "numérisation" --&gt; D["PaddleOCR (réglages de production)"]
 C --&gt; E["Segmentation &amp; classification"]
 D --&gt; E
 E --&gt; F["Extraction JSON par LLM + vérification d'ancrage verbatim"]
 F --&gt; G["Rapprochement inter-documents (facture / bon de livraison / commande)"]
 G --&gt; H["Verdict tri-état + motif nommé + trace"]
 H --&gt; I["Rapport / revue humaine"]&lt;/pre&gt;&lt;h2 id="le-catalogue"&gt;&lt;a href="#le-catalogue" class="header-anchor"&gt;&lt;/a&gt;Le catalogue
&lt;/h2&gt;&lt;p&gt;Les 459 atomes sont regroupés en 32 familles, un paquet Python chacune, rangées le long de
la chaîne de traitement : &lt;strong&gt;capter&lt;/strong&gt; le monde, le &lt;strong&gt;comprendre&lt;/strong&gt;, &lt;strong&gt;rapprocher&lt;/strong&gt; et décider,
&lt;strong&gt;restituer&lt;/strong&gt;, puis &lt;strong&gt;exploiter&lt;/strong&gt; en production. Deux paquets supplémentaires les assemblent :
&lt;code&gt;steps&lt;/code&gt; (77 étapes nommées et paramétrées) et &lt;code&gt;recipes&lt;/code&gt; (chargement et validation des recettes YAML).&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Série&lt;/th&gt;
					&lt;th&gt;Famille&lt;/th&gt;
					&lt;th style="text-align: right"&gt;Atomes&lt;/th&gt;
					&lt;th&gt;Rôle&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Socle&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;core&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;25&lt;/td&gt;
					&lt;td&gt;types pivots, chaîne de traitement, configuration, résilience (reprises, limites de débit), fichiers, concurrence&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Capter&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;connect&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;40&lt;/td&gt;
					&lt;td&gt;HTTP résilient, boîtes aux lettres (Graph, IMAP), SFTP, OneDrive, source ERP en lecture seule, données ouvertes, piste d&amp;rsquo;audit&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;google&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;24&lt;/td&gt;
					&lt;td&gt;Gmail, Sheets, Drive, Apps Script, avec exécution résiliente&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;web&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;17&lt;/td&gt;
					&lt;td&gt;robots web indépendants du pilote (Selenium, Playwright) : attentes, squelette à reprise, formulaires&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pdf&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;9&lt;/td&gt;
					&lt;td&gt;texte natif positionné, décision d&amp;rsquo;OCR, rendu, pages, doublons&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ocr&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;9&lt;/td&gt;
					&lt;td&gt;PaddleOCR avec réglages de production, EasyOCR&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;layout&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;3&lt;/td&gt;
					&lt;td&gt;géométrie de page : lignes, colonnes, redressement, rendu monospace&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;audio&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;16&lt;/td&gt;
					&lt;td&gt;transcription par morceaux, post-traitement des segments, recalage micro ↔ écran&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vision&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;32&lt;/td&gt;
					&lt;td&gt;flux vidéo / RTSP, détection, suivi, profondeur, segmentation, calibration&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vlm&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;10&lt;/td&gt;
					&lt;td&gt;lecture d&amp;rsquo;écran par modèle de vision-langage : détection de changement, localisation de libellés&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;geo&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;11&lt;/td&gt;
					&lt;td&gt;mesures géodésiques, position combinée de relevés GPS, filtrage par distance aux lignes, SQL spatial&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;calendar&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;4&lt;/td&gt;
					&lt;td&gt;jours fériés, jours et horaires ouvrés&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Comprendre&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;text&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;32&lt;/td&gt;
					&lt;td&gt;nombres et montants, dates, normalisation, champs par motifs, identifiants&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;segment&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;7&lt;/td&gt;
					&lt;td&gt;pages → documents logiques, numéros de pièce typés, nature de page&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;classify&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;12&lt;/td&gt;
					&lt;td&gt;classement par nom de fichier, expéditeur, motifs pondérés, TF-IDF, visuel, LLM, cascades&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;llm&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;24&lt;/td&gt;
					&lt;td&gt;contrat indépendant du fournisseur, fournisseurs, pool, prompts, extraction structurée&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;anchor&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;5&lt;/td&gt;
					&lt;td&gt;champs et tableaux situés par rapport aux libellés imprimés, texte natif ou OCR&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;kb&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;8&lt;/td&gt;
					&lt;td&gt;base de connaissances tracée : journal d&amp;rsquo;événements validé, replié en index SQLite&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rapprocher&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;match&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;25&lt;/td&gt;
					&lt;td&gt;EAN/GTIN, index, score multicritère, affectation optimale, résolution d&amp;rsquo;entités&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;compare&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;9&lt;/td&gt;
					&lt;td&gt;comparateurs tri-états et explicables de champs, d&amp;rsquo;enregistrements et d&amp;rsquo;ensembles&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;check&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;9&lt;/td&gt;
					&lt;td&gt;contrôles génériques tri-états : totaux, TVA, balance, complétude, vraisemblance&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;reconcile&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;12&lt;/td&gt;
					&lt;td&gt;appariement d&amp;rsquo;ensembles, chaînes commande → livraison → facture, N-voies, lettrage, rapprochement bancaire&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;validate&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;14&lt;/td&gt;
					&lt;td&gt;moteur de règles, identifiants, cohérence des montants, verdicts LLM corrigés, décision finale&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;rules&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;8&lt;/td&gt;
					&lt;td&gt;langage de conditions sûr, tables « premier match » explicables, escalade, machines à états&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;events&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;11&lt;/td&gt;
					&lt;td&gt;événements horodatés : fenêtres, veille des événements attendus, sessions, transitions de statut&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;analytics&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;18&lt;/td&gt;
					&lt;td&gt;analyses supply chain sans pandas : demande, ruptures, taux de service, stock de sécurité&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Restituer&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;export&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;8&lt;/td&gt;
					&lt;td&gt;CSV pour Excel FR, classeurs Excel partagés, rapports HTML / Markdown / PDF&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;report&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;6&lt;/td&gt;
					&lt;td&gt;écarts persistables, synthèses, file de revue&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;render&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;12&lt;/td&gt;
					&lt;td&gt;livrables HTML : diagrammes Mermaid pré-rendus, graphiques ECharts, cartes GeoJSON&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;diagram&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;6&lt;/td&gt;
					&lt;td&gt;diagrammes de processus : lecture draw.io / BPMN JSON, rendu Mermaid et BPMN XML&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Exploiter&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ops&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;26&lt;/td&gt;
					&lt;td&gt;haute disponibilité (battements, élection), démon à déclencheurs horaires, surveillance, contrôles préalables&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;qa&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;7&lt;/td&gt;
					&lt;td&gt;non-régression rédactionnelle (fichiers dorés), rejeu de simulations, accord inter-annotateurs&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="recettes-nommées"&gt;&lt;a href="#recettes-nomm%c3%a9es" class="header-anchor"&gt;&lt;/a&gt;Recettes nommées
&lt;/h3&gt;&lt;p&gt;Chacune des 17 recettes est une liste YAML d&amp;rsquo;étapes nommées &lt;code&gt;&amp;lt;famille&amp;gt;.&amp;lt;atome&amp;gt;&lt;/code&gt;. Trois exemples :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;invoice_multi_doc&lt;/code&gt;&lt;/strong&gt; : un lot de PDF multidocuments devient un ensemble de documents
logiques contrôlés. &lt;code&gt;io.collect&lt;/code&gt; → &lt;code&gt;pdf.read&lt;/code&gt; → &lt;code&gt;segment.documents&lt;/code&gt; → &lt;code&gt;classify.documents&lt;/code&gt; →
&lt;code&gt;llm.extract&lt;/code&gt; → &lt;code&gt;validate.ids&lt;/code&gt; → &lt;code&gt;validate.amounts&lt;/code&gt; → &lt;code&gt;validate.decide&lt;/code&gt; → &lt;code&gt;export.csv&lt;/code&gt;
→ &lt;code&gt;google.sheets.upsert&lt;/code&gt; → &lt;code&gt;connect.notify&lt;/code&gt;. Chaque document finit valide, à vérifier ou invalide.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;doc_reconciliation&lt;/code&gt;&lt;/strong&gt; : un dossier de factures, d&amp;rsquo;avoirs et de bons de livraison,
contrôlé par rapport aux commandes. L&amp;rsquo;extraction LLM gardée (&lt;code&gt;llm.extract_docs&lt;/code&gt;) est
recoupée avec une extraction par motifs (&lt;code&gt;extract.regex&lt;/code&gt;, &lt;code&gt;compare.extractions&lt;/code&gt;,
&lt;code&gt;reconcile.fields&lt;/code&gt;), puis viennent &lt;code&gt;check.document&lt;/code&gt; et &lt;code&gt;check.completeness&lt;/code&gt;, les lignes
face à la commande (&lt;code&gt;compare.reference&lt;/code&gt;), la chaîne commande → livraison → facture
(&lt;code&gt;reconcile.nway&lt;/code&gt;), et enfin un fichier d&amp;rsquo;écarts et une file de revue
(&lt;code&gt;report.discrepancies&lt;/code&gt;, &lt;code&gt;report.review&lt;/code&gt;). 17 étapes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;meeting_transcript&lt;/code&gt;&lt;/strong&gt; : un enregistrement de réunion devient une transcription horodatée
avec locuteurs. &lt;code&gt;audio.decode&lt;/code&gt; → &lt;code&gt;audio.vad&lt;/code&gt; → &lt;code&gt;audio.transcribe&lt;/code&gt; → &lt;code&gt;audio.diarize&lt;/code&gt; →
&lt;code&gt;audio.speakers&lt;/code&gt; → &lt;code&gt;audio.segments&lt;/code&gt; → &lt;code&gt;export.csv&lt;/code&gt; → &lt;code&gt;export.transcript&lt;/code&gt; → &lt;code&gt;connect.notify&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les autres sont notamment &lt;code&gt;delivery_vs_order&lt;/code&gt;, &lt;code&gt;ledger_reconciliation&lt;/code&gt;, &lt;code&gt;invoice_dedup&lt;/code&gt;,
&lt;code&gt;article_base_cleaning&lt;/code&gt;, &lt;code&gt;stock_policy&lt;/code&gt;, &lt;code&gt;mail_to_sheet&lt;/code&gt;, &lt;code&gt;draft_mails&lt;/code&gt;,
&lt;code&gt;pdf_text_extract&lt;/code&gt;, &lt;code&gt;rubric_eval&lt;/code&gt;, &lt;code&gt;screen_session&lt;/code&gt;, &lt;code&gt;camera_flow&lt;/code&gt; et
&lt;code&gt;process_from_transcript&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="latlas"&gt;&lt;a href="#latlas" class="header-anchor"&gt;&lt;/a&gt;L&amp;rsquo;Atlas
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;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&amp;rsquo;un symbole, chaque module
un atome, chaque recette une molécule. Il signale aussi les atomes sans documentation, sans
test ou sans exemple d&amp;rsquo;usage.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Atlas, série « Capter » : un élément par famille (connect, google, web, pdf, ocr, layout, audio, vision, vlm, geo, calendar), avec ses atomes en dessous" class="gallery-image" data-flex-basis="367px" data-flex-grow="153" height="920" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/processing-atoms/atlas-capture-series.png" srcset="https://borisdupoux.com/research/processing-atoms/atlas-capture-series_hu_dfcfb778a533826c.png 800w, https://borisdupoux.com/research/processing-atoms/atlas-capture-series.png 1408w" width="1408"&gt;
&lt;em&gt;La 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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Atlas, série « Rapprocher » : match, compare, check, reconcile, validate, rules, events, analytics" class="gallery-image" data-flex-basis="536px" data-flex-grow="223" height="630" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/processing-atoms/atlas-reconcile-series.png" srcset="https://borisdupoux.com/research/processing-atoms/atlas-reconcile-series_hu_872c082d4171f5de.png 800w, https://borisdupoux.com/research/processing-atoms/atlas-reconcile-series.png 1408w" width="1408"&gt;
&lt;em&gt;La série « Rapprocher » : les familles qui apparient, comparent, contrôlent et décident.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Fiche de l’atome compare.fields dans l’Atlas : rôle, règles de dominance et signature complète" class="gallery-image" data-flex-basis="170px" data-flex-grow="71" height="900" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/processing-atoms/atlas-atom-compare-fields.png" width="640"&gt;
&lt;em&gt;La fiche d&amp;rsquo;un atome (&lt;code&gt;compare.fields&lt;/code&gt;) : à quoi il sert, d&amp;rsquo;après sa docstring, puis chaque nom public avec sa signature complète.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="La recette invoice_multi_doc vue comme une molécule : 11 étapes reliées par les clés de contexte qu’elles se transmettent" class="gallery-image" data-flex-basis="590px" data-flex-grow="246" height="572" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/processing-atoms/atlas-recipe-invoice-multi-doc.png" srcset="https://borisdupoux.com/research/processing-atoms/atlas-recipe-invoice-multi-doc_hu_9f54a6aa2766961a.png 800w, https://borisdupoux.com/research/processing-atoms/atlas-recipe-invoice-multi-doc.png 1408w" width="1408"&gt;
&lt;em&gt;La recette &lt;code&gt;invoice_multi_doc&lt;/code&gt; en molécule : 11 étapes, les clés de contexte qui les relient et les services requis (en pointillé lorsqu&amp;rsquo;ils sont facultatifs).&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Résultats tri-états.&lt;/strong&gt; Chaque comparaison renvoie &lt;code&gt;ok ∈ {True, False, None}&lt;/code&gt;
(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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routage hybride texte natif/OCR.&lt;/strong&gt; Chaque page PDF est classée comme native, OCR ou
vide, selon la quantité de texte natif qu&amp;rsquo;elle contient et la part de ce texte couverte
par des images. L&amp;rsquo;OCR n&amp;rsquo;est exécuté que là où il est nécessaire.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extraction LLM ancrée.&lt;/strong&gt; L&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rapprochement inter-documents.&lt;/strong&gt; Factures, bons de livraison et commandes sont comparés
ligne à ligne à l&amp;rsquo;aide de tolérances nommées et de règles de dominance. Par exemple, un
montant de ligne concordant peut l&amp;rsquo;emporter sur un écart de prix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provenance.&lt;/strong&gt; Chaque atome porté comporte un en-tête &lt;code&gt;Provenance:&lt;/code&gt; et une entrée qui le
relie à &lt;code&gt;repo@commit:path:lines&lt;/code&gt; dans le code de production d&amp;rsquo;origine. Les bogues découverts
lors du portage ont été corrigés, et chaque correction est couverte par un test de non-régression.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture contrôlée.&lt;/strong&gt; Le découpage en couches est vérifié par 30 contrats d&amp;rsquo;import :
un atome n&amp;rsquo;importe que le paquet &lt;code&gt;core&lt;/code&gt;. Un typage strict, un seuil de couverture ≥ 80 % et
une vérification de l&amp;rsquo;absence de noms de clients dans le code source sont également imposés.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abstraction du matériel.&lt;/strong&gt; Les atomes de vision et d&amp;rsquo;audio ciblent &lt;code&gt;cuda&lt;/code&gt;, &lt;code&gt;mps&lt;/code&gt; ou &lt;code&gt;cpu&lt;/code&gt; via un seul paramètre.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Évaluation de bout en bout.&lt;/strong&gt; Les tests s&amp;rsquo;exécutent avec de vrais moteurs (PaddleOCR, Ollama &lt;code&gt;qwen3:8b&lt;/code&gt;
et &lt;code&gt;qwen3-vl:8b&lt;/code&gt;) 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&amp;rsquo;atteignent pas leur seuil sont conservées et
affichées comme en échec.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;Base de code (arborescence actuelle) : 459 modules d&amp;rsquo;atomes répartis en 32 familles, 77 étapes
paramétrées, 17 recettes YAML, 30 contrats d&amp;rsquo;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&amp;rsquo;au moins un test de bout en bout, et 34 des 35 éléments de l&amp;rsquo;Atlas sont testés de bout en bout.&lt;/p&gt;
&lt;p&gt;Scores de bout en bout sélectionnés (documents synthétiques à vérité terrain connue, modèles 8B locaux) :&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Tâche&lt;/th&gt;
					&lt;th&gt;Moteur&lt;/th&gt;
					&lt;th&gt;Mesure&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Rapprochement facture + bon de livraison / commande&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;qwen3:8b&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;types de documents et champs 14/14 ; écarts attendus 5/5 ; 0 faux écart sur le cas conforme&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Extraction JSON par LLM (4 factures natives)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;qwen3:8b&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;JSON valide 4/4 ; champs exacts 28/28 ; toutes les valeurs volontairement altérées détectées par l&amp;rsquo;ancrage&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OCR sur une étiquette photographiée&lt;/td&gt;
					&lt;td&gt;PaddleOCR&lt;/td&gt;
					&lt;td&gt;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)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Reconstruction de tableaux à partir de l&amp;rsquo;OCR&lt;/td&gt;
					&lt;td&gt;PaddleOCR&lt;/td&gt;
					&lt;td&gt;100 % de cellules exactes (police proportionnelle), 95 % (chasse fixe)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;L&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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&amp;rsquo;objet
d&amp;rsquo;une revue sont notés.&lt;/li&gt;
&lt;li&gt;Prochaines étapes : mesurer le taux de rapprochement automatique et le taux de faux positifs
sur des données de production.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;Pydantic&lt;/code&gt; · &lt;code&gt;PyYAML&lt;/code&gt; · &lt;code&gt;PaddleOCR&lt;/code&gt; · &lt;code&gt;Ollama&lt;/code&gt; (&lt;code&gt;qwen3:8b&lt;/code&gt;, &lt;code&gt;qwen3-vl:8b&lt;/code&gt;) · &lt;code&gt;Mistral / Anthropic / OpenAI APIs&lt;/code&gt; · &lt;code&gt;pytest&lt;/code&gt; · &lt;code&gt;mypy&lt;/code&gt; · &lt;code&gt;import-linter&lt;/code&gt; · &lt;code&gt;ruff&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Codex — archivage physique haute densité de médias sur papier</title><link>https://borisdupoux.com/fr/research/codex-paper-archive/</link><pubDate>Tue, 01 Sep 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/codex-paper-archive/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les médias numériques grand public se dégradent à l&amp;rsquo;é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&amp;rsquo;œil nu. La question est de savoir quelle quantité d&amp;rsquo;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é.&lt;/p&gt;
&lt;p&gt;Le problème est difficile car le canal impression-numérisation est bruité de plusieurs manières à la fois. Le toner s&amp;rsquo;étale et forme des amas, la densité varie sur la page, et les scanners introduisent rotation, mise à l&amp;rsquo;é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&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Médias sources : photo, vidéo, voix, texte"] --&gt; B["Réduction conservatrice des formats&lt;br/&gt;JPEG baseline · AVI MJPEG/PCM · WAV PCM · UTF-8"]
 B --&gt; C["Archive : tar + zlib + SHA-256"]
 C --&gt; D["Code à effacement inter-pages&lt;br/&gt;MDS de Cauchy sur GF(256) : K pages quelconques parmi N"]
 D --&gt; E["Reed–Solomon + CRC-32 par bloc&lt;br/&gt;entrelacement sur la page, en-tête triplé"]
 E --&gt; F["Rendu de cellules multiniveaux&lt;br/&gt;PDF A4 1 bit à 1200 dpi"]
 F --&gt; G["Impression → numérisation&lt;br/&gt;(canal simulé)"]
 G --&gt; H["Repères → homographie → marqueurs d'alignement locaux"]
 H --&gt; I["Calibration des niveaux de gris à partir de la page elle-même"]
 I --&gt; J["Décodage RS/CRC → décodage d'effacement → contrôle SHA-256"]
 J --&gt; K["Fichiers identiques à l'octet près, ou récupération partielle"]
 F -.-&gt; L["Annexe imprimée : spécification du format + source du décodeur en OCR-B avec CRC-16 par ligne"]
 L -.-&gt; J&lt;/pre&gt;&lt;p&gt;&lt;img alt="Une page de données A4 encodée de l’archive photo, à côté d’un agrandissement de son coin supérieur gauche à la résolution de l’imprimante, montrant le repère d’angle, le début du bandeau d’en-tête et les premières cellules en niveaux de gris avec un marqueur d’alignement" class="gallery-image" data-flex-basis="436px" data-flex-grow="181" height="880" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/codex-paper-archive/codex-page-and-macro.png" srcset="https://borisdupoux.com/research/codex-paper-archive/codex-page-and-macro_hu_7e58d21b3fd6152e.png 800w, https://borisdupoux.com/research/codex-paper-archive/codex-page-and-macro.png 1600w" width="1600"&gt;
&lt;em&gt;À gauche : la page 1 sur 10 de l&amp;rsquo;archive photo, telle qu&amp;rsquo;envoyée à l&amp;rsquo;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&amp;rsquo;imprimante (environ 10 × 9 mm, chaque point d&amp;rsquo;imprimante dessiné en 2 × 2 pixels) : le repère d&amp;rsquo;angle plein, le début du bandeau d&amp;rsquo;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&amp;rsquo;un des 4 niveaux. Le carré situé au coin de la grille est un marqueur d&amp;rsquo;alignement.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Une page de l’annexe imprimée : le début du fichier du décodeur cdx_read.py, composé en OCR-B, chaque ligne précédée de son numéro et d’un CRC-16 à quatre chiffres" class="gallery-image" data-flex-basis="339px" data-flex-grow="141" height="778" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/codex-paper-archive/codex-appendix-decoder-page.png" srcset="https://borisdupoux.com/research/codex-paper-archive/codex-appendix-decoder-page_hu_f0b09cea3a0e024f.png 800w, https://borisdupoux.com/research/codex-paper-archive/codex-appendix-decoder-page.png 1100w" width="1100"&gt;
&lt;em&gt;Une page de l&amp;rsquo;annexe imprimée (page 11 sur 30) : le début de &lt;code&gt;cdx_read.py&lt;/code&gt; (360 lignes), composé en OCR-B. Chaque ligne porte son numéro et son CRC-16 : une ligne mal relue par l&amp;rsquo;OCR peut ainsi être repérée et vérifiée à la main.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cellules multiniveaux plutôt que modules binaires.&lt;/strong&gt; Chaque cellule porte 2 bits. Les cellules sont dessinées sous forme de points groupés à la résolution native de l&amp;rsquo;imprimante, de sorte que le pilote n&amp;rsquo;effectue aucun tramage et ne produit aucun moiré.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Récupération de la géométrie par étapes.&lt;/strong&gt; Quatre repères d&amp;rsquo;angle, dont l&amp;rsquo;un est creux pour fixer l&amp;rsquo;orientation, donnent une homographie globale. Des marqueurs d&amp;rsquo;alignement répartis sur la page absorbent ensuite l&amp;rsquo;étirement local et non linéaire du papier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lecteur auto-calibré.&lt;/strong&gt; Le décodeur estime les niveaux de gris imprimés et l&amp;rsquo;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&amp;rsquo;imprimante.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contrôle d&amp;rsquo;erreurs à deux niveaux, un code produit.&lt;/strong&gt; Reed–Solomon et CRC-32 à l&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dégradation progressive.&lt;/strong&gt; Si le contrôle SHA-256 échoue, le décodeur extrait malgré tout chaque fichier complet situé avant la zone endommagée.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archive autodescriptive.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prototype antérieur (&lt;code&gt;codex_proto/&lt;/code&gt;).&lt;/strong&gt; 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&amp;rsquo;une réduction des médias avec pertes (codage paramétrique de la voix, codage des photos par résidus d&amp;rsquo;ondelettes).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;Tous les chiffres ci-dessous proviennent &lt;strong&gt;uniquement de simulations&lt;/strong&gt;. 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&amp;rsquo;entraînement, flou, vignettage, bruit, gamma 2,2), des taches de café, des rayures et &lt;strong&gt;une page volontairement perdue par archive&lt;/strong&gt;. Aucun essai physique d&amp;rsquo;impression et de numérisation n&amp;rsquo;a encore été réalisé.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Charge utile nette :&lt;/strong&gt; 383 469 octets par page A4, soit environ 59 bits/mm².&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;De bout en bout :&lt;/strong&gt; 46 pages sur 50 ont été numérisées et les &lt;strong&gt;4 archives sur 4 ont été restaurées à l&amp;rsquo;identique, octet pour octet&lt;/strong&gt; (photo, vidéo, voix, texte). Aucun mot de code Reed–Solomon n&amp;rsquo;a échoué et aucun bloc inter-pages n&amp;rsquo;a été perdu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taux d&amp;rsquo;erreur :&lt;/strong&gt; les pages propres ont nécessité la correction d&amp;rsquo;environ 0,007–0,008 % des octets. Les pages tachées et/ou rayées en ont nécessité au plus 0,90 %.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taille des archives :&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Texte :&lt;/strong&gt; les &lt;em&gt;Mémoires d&amp;rsquo;outre-tombe&lt;/em&gt;, 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&amp;rsquo;environ 226. zlib compresse cette prose d&amp;rsquo;un facteur 2,62 et LZMA d&amp;rsquo;un facteur 3,58.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Récupération partielle :&lt;/strong&gt; une archive tronquée au quart de sa longueur a encore restitué 1,42 Mo des 5,58 Mo de texte.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Robustesse du décodeur :&lt;/strong&gt; 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).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taille du décodeur :&lt;/strong&gt; 731 lignes de Python pour les modules du décodeur imprimé.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="La même petite zone d’une page de données, à gauche telle qu’encodée, à droite après le canal impression-numérisation simulé, à cheval sur le bord d’une tache de café simulée" class="gallery-image" data-flex-basis="616px" data-flex-grow="256" height="600" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/codex-paper-archive/codex-encoded-vs-scan.png" srcset="https://borisdupoux.com/research/codex-paper-archive/codex-encoded-vs-scan_hu_25056d9200d46d29.png 800w, https://borisdupoux.com/research/codex-paper-archive/codex-encoded-vs-scan.png 1540w" width="1540"&gt;
&lt;em&gt;La même zone de la page photo (380 × 300 points, environ 8 × 6,4 mm), agrandie. À gauche : telle qu&amp;rsquo;encodée. À droite : après le canal impression-numérisation &lt;strong&gt;simulé&lt;/strong&gt;, rééchantillonnée sur la grille de la page grâce à l&amp;rsquo;homographie des repères. L&amp;rsquo;étalement du toner, le flou et le bruit adoucissent les cellules, et le bord d&amp;rsquo;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&amp;rsquo;au plus 0,90 % des octets.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Trois images d’une vidéo sous-marine : en haut l’original, en bas les images restituées après encodage, impression-numérisation simulée et décodage" class="gallery-image" data-flex-basis="480px" data-flex-grow="200" height="792" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/codex-paper-archive/codex-video-frames.jpg" srcset="https://borisdupoux.com/research/codex-paper-archive/codex-video-frames_hu_87a931ee2368d927.jpg 800w, https://borisdupoux.com/research/codex-paper-archive/codex-video-frames.jpg 1584w" width="1584"&gt;
&lt;em&gt;L&amp;rsquo;archive vidéo : un plan sous-marin (banc de poissons au-dessus d&amp;rsquo;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 &lt;strong&gt;simulées&lt;/strong&gt; des 25 pages (dont une volontairement perdue). Le canal papier lui-même ne perd rien : l&amp;rsquo;AVI restitué est identique, octet pour octet, à l&amp;rsquo;AVI archivé. Ce qui diffère de l&amp;rsquo;original, c&amp;rsquo;est la réduction faite avant l&amp;rsquo;impression (MJPEG 800 × 600, 12,5 images/s, son mono 16 kHz) pour que 24 s de vidéo tiennent en 8,30 Mo.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gros plan sur la même zone du récif : vidéo originale à gauche, vidéo restituée à droite, avec effets de blocs JPEG et perte des détails fins dans l’image restituée" class="gallery-image" data-flex-basis="648px" data-flex-grow="270" height="585" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/research/codex-paper-archive/codex-video-detail.jpg" srcset="https://borisdupoux.com/research/codex-paper-archive/codex-video-detail_hu_ef2152090c0bf4cc.jpg 800w, https://borisdupoux.com/research/codex-paper-archive/codex-video-detail.jpg 1580w" width="1580"&gt;
&lt;em&gt;Gros plan sur l&amp;rsquo;image à 12,8 s. À gauche : une zone de 1 152 × 864 pixels de l&amp;rsquo;original, réduite. À droite : la zone correspondante de 240 × 180 pixels de l&amp;rsquo;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&amp;rsquo;est le prix à payer pour faire tenir le plan en 25 pages.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pas encore d&amp;rsquo;essai physique.&lt;/strong&gt; 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&amp;rsquo;erreur effective.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jeu de test restreint.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Propriétés physiques non mesurées.&lt;/strong&gt; 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&amp;rsquo;ont pas été mesurés.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dépendance à une police.&lt;/strong&gt; Le corps de texte de l&amp;rsquo;annexe repose sur une police système.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;NumPy&lt;/code&gt; · &lt;code&gt;SciPy&lt;/code&gt; · &lt;code&gt;Pillow&lt;/code&gt; · &lt;code&gt;reedsolo&lt;/code&gt; · &lt;code&gt;ReportLab&lt;/code&gt; · &lt;code&gt;soundfile&lt;/code&gt; · &lt;code&gt;ffmpeg&lt;/code&gt; · &lt;code&gt;Tesseract (OCR-B)&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Graphes de connaissances de mission : des preuves de conseil à une ontologie interrogée via MCP</title><link>https://borisdupoux.com/fr/research/mission-knowledge-graph/</link><pubDate>Tue, 01 Sep 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/mission-knowledge-graph/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Le conseil en observation des processus produit des logigrammes, des notes d&amp;rsquo;entretien, des
enregistrements d&amp;rsquo;écran et des recommandations. Une fois la mission livrée, ce matériau est
de fait inerte : la mission suivante repart d&amp;rsquo;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 &lt;strong&gt;documents en données typées, sourcées et interrogeables&lt;/strong&gt;, afin qu&amp;rsquo;un
assistant puisse répondre à « où avons-nous déjà vu cela, et qu&amp;rsquo;en avions-nous conclu ? » en
citant des preuves vérifiables.&lt;/p&gt;
&lt;p&gt;Deux exigences structurent le travail : la &lt;strong&gt;traçabilité&lt;/strong&gt; (chaque assertion renvoie à sa
preuve) et une stricte &lt;strong&gt;séparation entre preuve et connaissance&lt;/strong&gt; (ce qui a été observé
n&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["`Sources brutes de mission
immuables, hachées`"] --&gt; B["`Journal d'événements en ajout seul
source de vérité`"]
 B --&gt; C["`Base SQLite reconstructible
jetable`"]
 C --&gt; D[Extraction déterministe]
 C --&gt; E["`Extraction par LLM
simple force de proposition`"]
 D --&gt; F["`Nœuds et arêtes proposés
avec provenance`"]
 E --&gt; F
 F --&gt; G{"`Revue humaine
hors MCP`"}
 G --&gt;|validé| H[Graphe de connaissances]
 H --&gt; I[MCP : preuves]
 H --&gt; J[MCP : connaissances]
 H --&gt; K[MCP : ontologie]
 I --&gt; L[Assistant IA]
 J --&gt; L
 K --&gt; L&lt;/pre&gt;&lt;p&gt;Le choix de conception central consiste à scinder l&amp;rsquo;interface en &lt;strong&gt;trois serveurs MCP selon
le statut épistémique&lt;/strong&gt; : &lt;em&gt;preuves&lt;/em&gt; (observations attestées et sourcées), &lt;em&gt;connaissances&lt;/em&gt;
(généralisations) et &lt;em&gt;ontologie&lt;/em&gt; (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.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart 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" .-&gt; EV
 EV == "fonde chaque conclusion" ==&gt; KN
 EV --&gt; AI["`Assistant IA
réponses étiquetées par statut`"]
 KN --&gt; AI
 ON --&gt; AI&lt;/pre&gt;&lt;p&gt;Le graphe est unique ; seules les façades sont séparées. La frontière qui compte passe entre
preuves et connaissances : le serveur &lt;em&gt;preuves&lt;/em&gt; ne renvoie que ce qui a été observé, et où ;
le serveur &lt;em&gt;connaissances&lt;/em&gt; renvoie des conclusions qui doivent remonter jusqu&amp;rsquo;à ces preuves,
et aucun outil MCP ne peut marquer quoi que ce soit comme validé.&lt;/p&gt;
&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Méta-modèle.&lt;/strong&gt; Un noyau fixe, complété de profils de mission et d&amp;rsquo;une ontologie
versionnée (v0). Chaque nœud porte une origine (structurelle, déterministe, extraite par
LLM) et un statut (proposé → validé).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invariants (I1–I6).&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Questions de compétence avant l&amp;rsquo;implémentation.&lt;/strong&gt; Un jeu v0 de 33 questions, typées
comme factuelles, agrégées, de traçabilité, de contradiction, temporelles, inter-missions
et &lt;strong&gt;négatives&lt;/strong&gt; (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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocole d&amp;rsquo;évaluation.&lt;/strong&gt; 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&amp;rsquo;outils par tâche ; chaque
question soluble en ≤ 3 appels ; précision de l&amp;rsquo;extraction déterministe ≥ 0,95 par type ;
κ inter-annotateurs ≥ 0,7.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phases P0–P6 avec jalons humains.&lt;/strong&gt; L&amp;rsquo;implémentation est déléguée à une session d&amp;rsquo;agent
qui doit s&amp;rsquo;arrêter à chaque jalon et consigner les décisions en suspens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cartographie d&amp;rsquo;un logiciel en boîte noire.&lt;/strong&gt; La même méthode a été appliquée à un
logiciel commercial de gestion d&amp;rsquo;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&amp;rsquo;appariement de valeurs, la perturbation
inverse et directe, les champs calculés, la visibilité conditionnelle, les différences
entre scénarios, la fouille d&amp;rsquo;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&amp;rsquo;arborescence des menus via AT-SPI, un relevé des écrans, le
profilage des colonnes et une typologie d&amp;rsquo;événements issue du journal d&amp;rsquo;audit de
l&amp;rsquo;application. Une hypothèse n&amp;rsquo;est acceptée qu&amp;rsquo;avec une contre-preuve indépendante ; les
cartographies produites par l&amp;rsquo;éditeur sont tenues en quarantaine et servent d&amp;rsquo;oracle de
notation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un extrait illustratif du graphe typé (libellés fictifs) : la préconisation n&amp;rsquo;est recevable
que parce que la chaîne qui descend jusqu&amp;rsquo;à un fragment littéral d&amp;rsquo;une source est complète.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 R["`Préconisation
point de saisie unique`"] -- répond à --&gt; C["`Constat
double saisie à la réception`"]
 O["`Observation
« le stock est ressaisi à la main »`"] -- atteste --&gt; C
 O -- extrait de --&gt; F["`Fragment
notes d'entretien, lignes 40–52`"]
 F -- cite --&gt; P["`Pièce source
hachée, immuable`"]
 C -- porte sur --&gt; A["`Activité
réception des marchandises`"]
 A -- utilise --&gt; S["`Écran
formulaire de réception`"]
 S -- module de --&gt; Y["`Système
logiciel de gestion`"]&lt;/pre&gt;&lt;h2 id="état-davancement--résultats"&gt;&lt;a href="#%c3%a9tat-davancement--r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;État d&amp;rsquo;avancement &amp;amp; résultats
&lt;/h2&gt;&lt;p&gt;Il s&amp;rsquo;agit &lt;strong&gt;principalement d&amp;rsquo;une conception partiellement implémentée&lt;/strong&gt;, et non d&amp;rsquo;un
système en service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pilote (corpus d&amp;rsquo;observation, passe déterministe).&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mesure sur jeu de référence.&lt;/strong&gt; 145 unités d&amp;rsquo;annotation et 100 paires de résolution
d&amp;rsquo;entités. L&amp;rsquo;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&amp;rsquo;extracteur par rapport à la référence humaine : 0,74, 0,43,
0,04, 0,63. &lt;strong&gt;Jalon G2 (≥ 0,95) non franchi&lt;/strong&gt; ; le résultat sur la catégorie traduit un
désaccord de définition, et non une erreur de calcul.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cartographie du logiciel.&lt;/strong&gt; 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&amp;rsquo;agent superviseur. Un prototype MCP en lecture seule
existe ; &lt;strong&gt;aucune règle n&amp;rsquo;a encore été prouvée&lt;/strong&gt; dans le logiciel. Les travaux ont été
suspendus après une surcharge de la VM hôte.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mesure sur jeu de référence face aux seuils fixés à l&amp;rsquo;avance : les barres sont les valeurs
mesurées par champ, la ligne orange est le seuil. Une seule barre le franchit.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;---
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 --&gt; 1
 bar [0.72, 0.41, 0.31, 0.52]
 line [0.7, 0.7, 0.7, 0.7]&lt;/pre&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;---
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 --&gt; 1
 bar [0.74, 0.43, 0.04, 0.63]
 line [0.95, 0.95, 0.95, 0.95]&lt;/pre&gt;&lt;p&gt;La cartographie du logiciel, en entonnoir : l&amp;rsquo;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&amp;rsquo;hypothèses n&amp;rsquo;a encore produit aucune règle prouvée.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;---
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 --&gt; 3000
 bar [1048, 899, 154, 2845, 1519, 0]&lt;/pre&gt;&lt;p&gt;Les serveurs MCP et l&amp;rsquo;évaluation de bout en bout (P4–P5) ne sont &lt;strong&gt;pas implémentés&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;p&gt;Les résultats du pilote sont inférieurs aux seuils et reposent sur une annotation humaine
partielle. Prochaines étapes : redéfinir l&amp;rsquo;étiquette de catégorie, constituer une référence
entièrement humaine, mesurer à nouveau G1/G2, puis construire les trois serveurs et mener
l&amp;rsquo;é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.&lt;/p&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python 3.11&lt;/code&gt; · &lt;code&gt;JSONL event log&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;YAML ontology&lt;/code&gt; · &lt;code&gt;MCP&lt;/code&gt; · &lt;code&gt;AT-SPI&lt;/code&gt; · &lt;code&gt;Ollama&lt;/code&gt; · &lt;code&gt;pytest&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Automatisation déterministe des processus sous fortes contraintes de sécurité</title><link>https://borisdupoux.com/fr/research/deterministic-rpa/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/deterministic-rpa/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;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&amp;rsquo;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&amp;rsquo;entrée sont dispersées entre trois systèmes aux modes d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="contraintes-de-conception"&gt;&lt;a href="#contraintes-de-conception" class="header-anchor"&gt;&lt;/a&gt;Contraintes de conception
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aucun modèle de langage à l&amp;rsquo;exécution.&lt;/strong&gt; Chaque décision découle de règles explicites
et chaque phrase d&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;écran enregistrées
d&amp;rsquo;opérateurs ; il ne fait pas partie du système déployé.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Des brouillons, pas des envois.&lt;/strong&gt; Le robot se contente de créer des brouillons
Outlook ; l&amp;rsquo;opérateur les relit et les envoie. Un interrupteur d&amp;rsquo;arrêt global impose le
mode brouillon quels que soient les réglages propres à chaque processus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exécution locale, sans nouvelle infrastructure.&lt;/strong&gt; Python sur un poste Windows, tâches
planifiées, dossier partagé sur NAS pour l&amp;rsquo;état et la configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aucun secret en clair.&lt;/strong&gt; Identifiants et jetons sont stockés dans le Gestionnaire
d&amp;rsquo;identifiants Windows (DPAPI) ; la configuration est en YAML, modifiable par
l&amp;rsquo;opérateur sans recompilation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architecture"&gt;&lt;a href="#architecture" class="header-anchor"&gt;&lt;/a&gt;Architecture
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 SCHED["Passages planifiés (matin / après-midi)"] --&gt; ING
 MAIL["Boîte aux lettres (Microsoft Graph, lecture)"] --&gt; ING["Ingestion rapports PDF regroupés par jour"]
 ING --&gt; 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"] --&gt; RULES
 XLS["Classeurs de référence &amp; d'historique (Excel)"] --&gt; RULES
 PARSE --&gt; RULES["Moteur de règles 4 processus, règles ordonnées &amp; exclusions"]
 RULES --&gt; TPL["Composeur de modèles accords, noms, dates en français"]
 TPL --&gt; DRAFTS["Brouillons Outlook (Graph, jamais envoyés)"]
 RULES --&gt; TRACK["Classeurs de suivi (ajout atomique)"]
 DRAFTS --&gt; OP(["L'opérateur relit &amp; envoie"])
 OP -. "éléments envoyés : destinataires corrigés" .-&gt; RULES
 NAS[("NAS : verrous, battements de cœur, journal, registre d'idempotence")] --- RULES
 RULES --&gt; HEALTH["Alertes de santé webhook + contrôle de l'homme mort"]&lt;/pre&gt;&lt;h2 id="les-quatre-processus"&gt;&lt;a href="#les-quatre-processus" class="header-anchor"&gt;&lt;/a&gt;Les quatre processus
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Maintenance des équipements.&lt;/strong&gt; Les lignes de panne extraites des rapports PDF
quotidiens sont confrontées à l&amp;rsquo;historique des piles et des réparations de chaque
appareil. Un arbre de décision ordonné (la première correspondance l&amp;rsquo;emporte) choisit
entre ignorer, attendre, remplacer la pile, remplacer l&amp;rsquo;appareil ou tester la portée
radio, et rédige un ordre d&amp;rsquo;intervention pour le technicien ; chaque appareil d&amp;rsquo;un ordre
portant sur plusieurs appareils conserve sa propre décision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Événements parasites récurrents.&lt;/strong&gt; Le nombre d&amp;rsquo;é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&amp;rsquo;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&amp;rsquo;intervention, ou rien.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rapports d&amp;rsquo;intervention.&lt;/strong&gt; Pour chaque intervention sur site, le robot reconstitue une
chronologie unique à partir du journal d&amp;rsquo;événements du portail, du journal d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Contrôles de santé périodiques.&lt;/strong&gt; Les sites dont le contrôle de santé périodique est
absent sont identifiés, l&amp;rsquo;état de chaque canal de connectivité est vérifié sur le
portail, puis un courriel au client, un ordre d&amp;rsquo;intervention ou une note interne est
rédigé.&lt;/p&gt;
&lt;h2 id="rédiger-un-courriel--des-paramètres-au-brouillon"&gt;&lt;a href="#r%c3%a9diger-un-courriel--des-param%c3%a8tres-au-brouillon" class="header-anchor"&gt;&lt;/a&gt;Rédiger un courriel : des paramètres au brouillon
&lt;/h2&gt;&lt;p&gt;Chaque brouillon est l&amp;rsquo;aboutissement d&amp;rsquo;une longue chaîne de décisions explicites.
Comptés dans le code source (octobre 2026), les quatre moteurs de règles comportent
&lt;strong&gt;53 issues terminales&lt;/strong&gt; (chaque endroit où une règle rend une décision), réparties sur
&lt;strong&gt;37 types de décision&lt;/strong&gt; et &lt;strong&gt;13 générateurs de brouillons&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le courriel de sensibilisation du processus « événements parasites » en donne la mesure.
Un site n&amp;rsquo;y aboutit qu&amp;rsquo;après &lt;strong&gt;14 tests ordonnés&lt;/strong&gt; au plus dans le moteur de règles
(16 issues terminales pour ce seul processus). Le composeur lit ensuite &lt;strong&gt;21 entrées&lt;/strong&gt; :
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&amp;rsquo;orthographe appris dans le classeur d&amp;rsquo;historique de
l&amp;rsquo;opérateur lui-même). Entre la décision et le texte final, on compte &lt;strong&gt;108 points de
branchement conditionnel&lt;/strong&gt; (instructions &lt;code&gt;if&lt;/code&gt;, expressions conditionnelles et opérandes
booléens, comptés sur l&amp;rsquo;arbre syntaxique du composeur et des dix fonctions auxiliaires
qu&amp;rsquo;il appelle, avant la mise en forme HTML).&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart 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"]) --&gt; T0

 T0["Drapeau bloquant sur la fiche du site ?"] -- oui --&gt; X0["Pas de courriel"]
 T0 -- non --&gt; T1["R6 · incident confirmé comme réel aujourd'hui ?"]
 T1 -- oui --&gt; X1["Pas de courriel"]
 T1 -- non --&gt; T2["R17 · événements médias à moins de 30 s entre zones ?"]
 T2 -- oui --&gt; X2["Arbitrage manuel"]
 T2 -- non --&gt; T3["R12 · cause externe confirmée par les médias ?"]
 T3 -- non --&gt; T4["R8 · ≥ 8 événements d'intégrité ?"]
 T4 -- oui --&gt; T4b["persistants depuis ≥ 3 jours ?"]
 T4b -- oui --&gt; X3["Ordre d'intervention technicien"]
 T4b -- non --&gt; X4["En attente"]
 T4 -- non --&gt; T5["≥ 2 événements d'intégrité, ≥ la moitié de la salve ?"]
 T5 -- oui --&gt; X5["Pas de courriel"]
 T5 -- non --&gt; T6["R16 · ≥ 140 événements, sensibilisation ignorée depuis ≥ 4 semaines ? (désactivée par défaut)"]
 T6 -- oui --&gt; X6["Avis de facturation"]
 T6 -- non --&gt; T7["R15 · drapeau bâtiment partagé ?"]
 T7 -- oui --&gt; X7["Courriel de coordination"]
 T7 -- non --&gt; T8["R5 · week-end + drapeau appareil chroniquement défaillant ?"]
 T8 -- oui --&gt; X8["Demande de masquage temporaire"]
 T8 -- non --&gt; T9["R1 · même appareil ≥ 7 événements ?"]
 T9 -- non --&gt; T10["R2 · ≥ 5 appareils et ≥ 8 événements ?"]
 T10 -- non --&gt; T11["R4 · ≥ 8 événements, ≥ 50 % entre 5 h et 7 h ?"]
 T11 -- non --&gt; T12["R3 · ≥ 8 événements, ≥ 60 % entre 12 h et 18 h, ≥ 70 % en 4 h ?"]
 T12 -- non --&gt; T13["R1bis · total du site ≥ 7 événements ?"]
 T13 -- non --&gt; X9["Pas de courriel"]

 T3 &amp; T9 &amp; T10 &amp; T11 &amp; T12 &amp; T13 -- oui --&gt; 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 --&gt; SUBJ["≥ 30 événements ?"]
 SUBJ -- oui --&gt; S1["Objet avec préfixe d'urgence"]
 SUBJ -- non --&gt; S2["Objet simple"]
 S1 &amp; S2 --&gt; GR["Cellule contact"]
 GR -- "plusieurs personnes, ou mot de fonction / d'organisation" --&gt; G1["Salutation générique"]
 GR -- "civilité + nom" --&gt; G2["Salutation + civilité normalisée (7 abréviations) + NOM"]
 GR -- "nom seul" --&gt; G3["Salutation + NOM"]
 G1 &amp; G2 &amp; G3 --&gt; DEV["Appareils concernés"]
 DEV -- un --&gt; D1["Nom de zone du portail s'il est connu, sinon libellé nettoyé + table de jargon + accents appris"]
 DEV -- plusieurs --&gt; D2["Formule générique + liste de 6 au plus par nombre d'événements, chacun avec son code s'il est connu"]
 D1 &amp; D2 --&gt; HND["Système mis en marche ou à l'arrêt à quelques minutes de la salve ? (R1 à R4 seulement)"]
 HND -- "arrêt juste après" --&gt; C1["Erreur de manipulation, formulation A"]
 HND -- "marche juste avant" --&gt; C2["Erreur de manipulation, formulation B"]
 HND -- non --&gt; 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 --&gt; C3["Formulation « site en activité »"]
 ACT -- non --&gt; RUL["Règle déclenchée"]
 RUL -- "R1, R2" --&gt; C4["Cause environnementale générique"]
 RUL -- "R3, R4" --&gt; C5["Cause : passages du personnel"]
 RUL -- R12 --&gt; C6["Cause externe confirmée par les médias"]
 RUL -- R1bis --&gt; C7["Cause à rechercher sur place"]
 C4 &amp; C5 --&gt; ATT["Médias réellement joints ?"]
 ATT -- oui --&gt; A1["+ renvoi aux pièces jointes"]
 ATT -- non --&gt; FLG
 A1 &amp; C1 &amp; C2 &amp; C3 &amp; C6 &amp; C7 --&gt; FLG["Drapeau du site : travaux fréquents ?"]
 FLG -- oui --&gt; F1["Demande : arrêt avant travaux"]
 FLG -- non --&gt; F2["Demande : traiter la cause"]
 F1 &amp; F2 --&gt; REC["Adresses dans la fiche client ?"]
 REC -- oui --&gt; RC1["Toutes les adresses trouvées"]
 REC -- non --&gt; RC2["Boîte interne de repli"]
 RC1 &amp; RC2 --&gt; 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;&lt;/pre&gt;&lt;p&gt;L&amp;rsquo;espace de formulation de ce seul courriel : 2 formes d&amp;rsquo;objet, 3 formes de salutation,
2 formes de phrase d&amp;rsquo;ouverture, 7 formulations de cause atteignables (dont deux avec ou
sans renvoi aux médias joints), 2 demandes d&amp;rsquo;action et une liste facultative de 2 à
6 appareils. Tous les seuils ci-dessus sont dans la configuration YAML, pas dans le code.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Paramètre&lt;/th&gt;
					&lt;th&gt;Source&lt;/th&gt;
					&lt;th&gt;Effet sur le courriel&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Nombre d&amp;rsquo;événements sur 24 h&lt;/td&gt;
					&lt;td&gt;rapports quotidiens&lt;/td&gt;
					&lt;td&gt;chiffre de la phrase d&amp;rsquo;ouverture ; à partir de 30, préfixe d&amp;rsquo;urgence dans l&amp;rsquo;objet&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Règle déclenchée&lt;/td&gt;
					&lt;td&gt;moteur de règles&lt;/td&gt;
					&lt;td&gt;choisit la formulation de la cause ; conditionne les vérifications « erreur de manipulation » et « site en activité »&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Appareils concernés (nettoyés, dédoublonnés)&lt;/td&gt;
					&lt;td&gt;rapports quotidiens&lt;/td&gt;
					&lt;td&gt;un appareil nommé, ou une formule générique suivie d&amp;rsquo;une liste de 6 lignes au plus, par nombre d&amp;rsquo;événements&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Code de l&amp;rsquo;appareil sur chaque ligne de rapport&lt;/td&gt;
					&lt;td&gt;rapports quotidiens&lt;/td&gt;
					&lt;td&gt;ajouté entre parenthèses à chaque appareil listé, seulement s&amp;rsquo;il est connu&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Nom de zone de l&amp;rsquo;appareil principal&lt;/td&gt;
					&lt;td&gt;portail&lt;/td&gt;
					&lt;td&gt;remplace le libellé brut du rapport lorsqu&amp;rsquo;il est disponible&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Graphies apprises&lt;/td&gt;
					&lt;td&gt;classeur d&amp;rsquo;historique de l&amp;rsquo;opérateur&lt;/td&gt;
					&lt;td&gt;rétablit accents et casse des noms d&amp;rsquo;appareils&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Cellules civilité et nom du contact&lt;/td&gt;
					&lt;td&gt;fiche client&lt;/td&gt;
					&lt;td&gt;l&amp;rsquo;une des 3 formes de salutation ; plusieurs personnes, une fonction ou un nom d&amp;rsquo;organisation ramènent à la forme générique&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Raison sociale&lt;/td&gt;
					&lt;td&gt;fiche client&lt;/td&gt;
					&lt;td&gt;forme juridique retirée, casse rétablie en conservant les sigles, utilisée dans l&amp;rsquo;objet et le corps&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Type de site, heures d&amp;rsquo;ouverture apprises, interventions dans la fenêtre&lt;/td&gt;
					&lt;td&gt;classeur de suivi, journal du portail&lt;/td&gt;
					&lt;td&gt;active ou neutralise la formulation « site en activité »&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Mise en marche ou à l&amp;rsquo;arrêt autour de la salve&lt;/td&gt;
					&lt;td&gt;journal du portail&lt;/td&gt;
					&lt;td&gt;formulation « erreur de manipulation » (2 variantes), prioritaire sur toute autre cause&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Drapeaux du site&lt;/td&gt;
					&lt;td&gt;fiche client&lt;/td&gt;
					&lt;td&gt;choix entre les 2 demandes d&amp;rsquo;action&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Présence de pièces jointes&lt;/td&gt;
					&lt;td&gt;médias du portail&lt;/td&gt;
					&lt;td&gt;renvoi aux pièces jointes, ou rien&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Adresses des destinataires&lt;/td&gt;
					&lt;td&gt;fiche client&lt;/td&gt;
					&lt;td&gt;toutes les adresses trouvées ; à défaut, une boîte interne de repli&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Les autres brouillons s&amp;rsquo;appuient sur les mêmes fonctions partagées de rédaction en
français : la préposition devant un nom de site s&amp;rsquo;accorde avec son premier nom (6 formes,
de « chez » à « à l&amp;rsquo; » et « aux ») ; les titres des rapports s&amp;rsquo;accordent en genre et en
nombre ; les dates sont écrites en toutes lettres ; l&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="ingénierie-de-la-fiabilité"&gt;&lt;a href="#ing%c3%a9nierie-de-la-fiabilit%c3%a9" class="header-anchor"&gt;&lt;/a&gt;Ingénierie de la fiabilité
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idempotence.&lt;/strong&gt; Un registre quotidien indexé par site, type de message et empreinte de
l&amp;rsquo;objet empêche les brouillons en double ; un registre inter-jours empêche de réémettre
un ordre d&amp;rsquo;intervention avant que l&amp;rsquo;intervention précédente n&amp;rsquo;ait eu lieu. Les jours
manqués sont rattrapés automatiquement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrence sur un NAS partagé.&lt;/strong&gt; Fichiers de verrou exclusifs (&lt;code&gt;O_CREAT|O_EXCL&lt;/code&gt;)
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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Écritures sûres dans les classeurs.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Robustesse réseau.&lt;/strong&gt; Les appels Graph gèrent le renouvellement des jetons, l&amp;rsquo;en-tête
&lt;code&gt;Retry-After&lt;/code&gt; des réponses HTTP 429 et le repli progressif sur les erreurs 5xx.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Échec explicite.&lt;/strong&gt; Une enveloppe de plantage, sans dépendance au paquet principal,
envoie une alerte expurgée et un signal d&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Évaluation en parallèle (shadow).&lt;/strong&gt; Une version bac à sable rejoue une journée en
lecture seule et compare ses brouillons à ceux de la production. Le critère
d&amp;rsquo;acceptation est la part des brouillons que l&amp;rsquo;opérateur envoie sans en modifier un
seul mot.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 766&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;Un audit du corpus de rapports reçus a montré que &lt;strong&gt;9,5 %&lt;/strong&gt; des lignes d&amp;rsquo;événements
étaient écartées silencieusement, parce que les codes et libellés d&amp;rsquo;événements sont
concaténés dans le texte extrait des PDF ; l&amp;rsquo;analyseur a été réécrit pour reconnaître les
formes de codes effectivement émises.&lt;/li&gt;
&lt;li&gt;La mise en cache du classeur d&amp;rsquo;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
&lt;strong&gt;161,1 s à 23,3 s&lt;/strong&gt; ; le nombre d&amp;rsquo;ouvertures du classeur est passé de 26 à 3.&lt;/li&gt;
&lt;li&gt;Première comparaison en parallèle sans écart avec la production : &lt;strong&gt;14 brouillons de
chaque côté, 14 en commun, 0 manquant, 0 en trop&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python 3.11&lt;/code&gt; · &lt;code&gt;Microsoft Graph&lt;/code&gt; · &lt;code&gt;MSAL&lt;/code&gt; · &lt;code&gt;httpx&lt;/code&gt; · &lt;code&gt;Playwright&lt;/code&gt; · &lt;code&gt;pypdf&lt;/code&gt; ·
&lt;code&gt;openpyxl&lt;/code&gt; · &lt;code&gt;pydantic&lt;/code&gt; · &lt;code&gt;keyring&lt;/code&gt; · &lt;code&gt;pytest&lt;/code&gt; · &lt;code&gt;PyInstaller&lt;/code&gt;&lt;/p&gt;</description></item><item><title>De l'enregistrement multipiste à la timeline éditable : transcription, diarisation et export AAF</title><link>https://borisdupoux.com/fr/research/speech-to-edit/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/speech-to-edit/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Une conférence enregistrée sur plusieurs microphones (intervenants, salle,
musique) produit des heures d&amp;rsquo;audio multipiste brut. L&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Les 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&amp;rsquo;arrêtent au &lt;strong&gt;texte&lt;/strong&gt;. La question traitée ici est de savoir si cette analyse
peut être livrée sous la forme d&amp;rsquo;un &lt;strong&gt;objet de montage&lt;/strong&gt; : une timeline
multipiste au format AAF, le format d&amp;rsquo;échange que les stations audionumériques
ouvrent nativement, avec des pistes qualifiées et les temps morts supprimés.&lt;/p&gt;
&lt;h2 id="avant--après"&gt;&lt;a href="#avant--apr%c3%a8s" class="header-anchor"&gt;&lt;/a&gt;Avant → après
&lt;/h2&gt;&lt;p&gt;Un vrai projet traité de bout en bout : une conférence enregistrée sur
&lt;strong&gt;16 pistes&lt;/strong&gt;. Toute la colonne de droite est produite automatiquement, sans
aucune coupe manuelle ; les chiffres sont lus dans la base d&amp;rsquo;analyse du projet
et dans l&amp;rsquo;AAF livré.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;Entrée (enregistrement brut)&lt;/th&gt;
					&lt;th&gt;Sortie générée (timeline AAF)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Pistes&lt;/td&gt;
					&lt;td&gt;16 × 1 h 32 min 54 s (≈ 24 h 46 min d&amp;rsquo;audio à parcourir)&lt;/td&gt;
					&lt;td&gt;16 pistes conservées dans l&amp;rsquo;AAF, dont 6 portent des clips&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rôles des pistes&lt;/td&gt;
					&lt;td&gt;4 parole · 2 musique (dont une détectée comme ambiance) · 10 silencieuses&lt;/td&gt;
					&lt;td&gt;10 pistes silencieuses laissées vides, sans tri manuel&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Matière&lt;/td&gt;
					&lt;td&gt;204 régions de parole et 5 passages musicaux détectés&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;41 clips&lt;/strong&gt; (37 parole, 4 musique)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Coupes&lt;/td&gt;
					&lt;td&gt;—&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;40 coupes franches&lt;/strong&gt; entre sources, dont 33 changements de micro&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Transitions&lt;/td&gt;
					&lt;td&gt;—&lt;/td&gt;
					&lt;td&gt;0 fondu enchaîné : coupes franches, chaque clip de parole prolongé de 0,3 s&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Temps morts&lt;/td&gt;
					&lt;td&gt;—&lt;/td&gt;
					&lt;td&gt;3 trous ≥ 4,5 s supprimés en ripple (36,9 s) ; timeline de 1 h 32 min 17 s&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img alt="Avant/après multipiste : les 16 pistes d’entrée colorées par rôle dans le temps, et le montage généré montrant la piste retenue pour chaque segment, avec les changements de source marqués" class="gallery-image" data-flex-basis="333px" data-flex-grow="138" height="1152" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://borisdupoux.com/fr/research/speech-to-edit/multitrack-before-after.fr.png" srcset="https://borisdupoux.com/fr/research/speech-to-edit/multitrack-before-after.fr_hu_ed7871e33c6cf34f.png 800w, https://borisdupoux.com/fr/research/speech-to-edit/multitrack-before-after.fr.png 1600w" width="1600"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;En haut : les 16 pistes d&amp;rsquo;entrée sur toute la durée de l&amp;rsquo;enregistrement,
colorées selon le rôle et l&amp;rsquo;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&amp;rsquo;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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Les clips de parole sont peu nombreux et longs (médiane 79 s, le plus long
10 min 11 s) : le montage suit l&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Enregistrement WAV multipiste"] --&gt; B["Décodage en mono 16 kHz + énergie RMS par 100 ms"]
 B --&gt; C["Détection d'activité vocale (Silero)"]
 C --&gt; D["Transcription (Whisper large-v3, par segments)"]
 D --&gt; E["Alignement forcé des mots (WhisperX / wav2vec2)"]
 C --&gt; F["Diarisation des locuteurs (pyannote)"]
 E --&gt; G["Attribution des locuteurs + post-traitement des segments"]
 F --&gt; G
 B --&gt; H["Rôle de la piste : parole / musique / silence"]
 G --&gt; H
 H --&gt; I["Montage : micro actif par trame de 100 ms"]
 I --&gt; J["Export AAF (lié aux noms WAV d'origine)"]
 I --&gt; K["Mixage mono WAV"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Transcription.&lt;/strong&gt; Whisper &lt;code&gt;large-v3&lt;/code&gt; via faster-whisper (CTranslate2), exécuté
sur des segments de longueur fixe dans un processus de travail isolé et
persistant : le modèle n&amp;rsquo;est chargé qu&amp;rsquo;une fois, et un plantage natif ne fait
perdre qu&amp;rsquo;un segment, signalé plutôt qu&amp;rsquo;ignoré silencieusement. Le décodage
utilise une recherche en faisceau avec filtrage Silero VAD, et
&lt;code&gt;condition_on_previous_text&lt;/code&gt; est désactivé pour limiter les boucles de
répétition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Horodatage des mots et locuteurs.&lt;/strong&gt; Les horodatages au niveau du mot
proviennent de l&amp;rsquo;alignement forcé de WhisperX (wav2vec2). Les tours de parole
proviennent de la diarisation pyannote et sont attribués aux mots par
recouvrement temporel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Post-traitement.&lt;/strong&gt; Des filtres purs suppriment les hallucinations connues de
Whisper (crédits de sous-titrage types, formules du genre « merci d&amp;rsquo;avoir
regardé », segments purement musicaux), les sorties en écriture non latine sur
de l&amp;rsquo;audio français et les doublons, puis fusionnent les segments consécutifs
d&amp;rsquo;un même locuteur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Qualification des pistes et montage.&lt;/strong&gt; Chaque piste est classée en parole,
musique ou silence en combinant l&amp;rsquo;é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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synchronisation.&lt;/strong&gt; 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&amp;rsquo;horloge et corrigé de la dérive
d&amp;rsquo;horloge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Export.&lt;/strong&gt; La liste de montage est écrite sous forme d&amp;rsquo;AAF multipiste avec
&lt;code&gt;pyaaf2&lt;/code&gt;, en intégrant l&amp;rsquo;audio ou en le référençant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Déploiement.&lt;/strong&gt; Un portail web reçoit les tâches et un nœud de calcul distinct
l&amp;rsquo;interroge en HTTPS. Les clients ne téléversent que des copies d&amp;rsquo;analyse
compressées accompagnées d&amp;rsquo;un manifeste de leurs fichiers d&amp;rsquo;origine ; l&amp;rsquo;AAF
livré référence les &lt;strong&gt;noms des WAV d&amp;rsquo;origine&lt;/strong&gt;, de sorte que le monteur
reconnecte localement les sources en pleine qualité et que les originaux ne
quittent jamais la machine du client.&lt;/p&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;Banc d&amp;rsquo;essai (&lt;code&gt;bench_stt.py&lt;/code&gt;) sur de l&amp;rsquo;audio réel de conférence : fenêtres de
parole d&amp;rsquo;une minute sélectionnées par VAD sur quatre pistes de parole, Whisper
&lt;code&gt;large-v3&lt;/code&gt; dans tous les cas, ordinateur portable Apple Silicon, mesures à
chaud hors chargement du modèle. Aucune transcription de référence n&amp;rsquo;étant
disponible, les indicateurs de qualité sont des &lt;strong&gt;divergences par rapport à
une pseudo-référence&lt;/strong&gt; (sortie de WhisperX), et non des erreurs absolues.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Chaîne de traitement (CPU)&lt;/th&gt;
					&lt;th style="text-align: right"&gt;Facteur temps réel&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;openai-whisper&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,43&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;WhisperX&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,51&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;WhisperX + alignement forcé&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,54&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;openai-whisper + horodatage des mots&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,57&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;faster-whisper (faisceau 5 + VAD)&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,66&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;faster-whisper + horodatage des mots&lt;/td&gt;
					&lt;td style="text-align: right"&gt;0,70&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Horodatage des mots :&lt;/strong&gt; les horodatages natifs s&amp;rsquo;écartent de l&amp;rsquo;alignement
forcé d&amp;rsquo;environ 205 ms en médiane (faster-whisper) et d&amp;rsquo;environ 210 ms
(openai-whisper) ; l&amp;rsquo;alignement forcé ajoute environ 1,2 s par minute
d&amp;rsquo;audio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Divergence des transcriptions :&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Répétitions :&lt;/strong&gt; 1 à 2 % de contenu répété ; aucun passage halluciné observé
sur ces extraits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Détection des pistes :&lt;/strong&gt; les trois pistes de musique ou de silence de
l&amp;rsquo;enregistrement à sept pistes ont été identifiées par VAD et écartées
automatiquement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;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&amp;rsquo;erreur sur les mots et un taux d&amp;rsquo;erreur de diarisation.&lt;/li&gt;
&lt;li&gt;Les extraits du banc d&amp;rsquo;essai sont courts (une minute par piste) et ne
comportent qu&amp;rsquo;un seul locuteur par fenêtre : la précision de la diarisation
en cas de chevauchement de plusieurs locuteurs n&amp;rsquo;est donc pas encore
quantifiée.&lt;/li&gt;
&lt;li&gt;CTranslate2 n&amp;rsquo;a pas de backend Metal : sur Apple Silicon, faster-whisper et
WhisperX s&amp;rsquo;exécutent sur CPU, tandis que CUDA est utilisé lorsqu&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;export AAF cible l&amp;rsquo;import dans Logic Pro ; les autres logiciels de montage
n&amp;rsquo;ont pas été testés de manière systématique.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;faster-whisper&lt;/code&gt; · &lt;code&gt;CTranslate2&lt;/code&gt; · &lt;code&gt;WhisperX&lt;/code&gt; · &lt;code&gt;pyannote.audio&lt;/code&gt; · &lt;code&gt;Silero VAD&lt;/code&gt; · &lt;code&gt;PyTorch (MPS / CUDA)&lt;/code&gt; · &lt;code&gt;ffmpeg&lt;/code&gt; · &lt;code&gt;pyaaf2&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;PHP&lt;/code&gt; · &lt;code&gt;MySQL&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Identification sur le terrain des véhicules concernés par un rappel</title><link>https://borisdupoux.com/fr/research/fleet-management/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/fleet-management/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les campagnes de rappel de sécurité supposent d&amp;rsquo;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&amp;rsquo;étend sur plusieurs
territoires et le registre de qui conduit quoi est incomplet. La question pratique devient
alors une question de gestion de flotte : &lt;em&gt;quels véhicules du parc en circulation sont
encore concernés, où sont-ils aperçus, et où en est chacun d&amp;rsquo;eux sur le chemin de la
réparation ?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Liste de rappel&lt;br/&gt;(récupération planifiée du fichier ou CSV manuel)"] --&gt; B["Serveur central&lt;br/&gt;import · versionnage · décodage des noms de modèles"]
 B --&gt;|"diff incrémental"| C["Unités de terrain (ordinateurs portables dans les véhicules des agents)&lt;br/&gt;copie locale de la liste de rappel"]
 D["Flux caméra"] --&gt; E["Détection de plaques + OCR&lt;br/&gt;(sur l'appareil, hors ligne)"]
 E --&gt; F["Correction tenant compte du format&lt;br/&gt;+ confirmation par double lecture"]
 F --&gt; G{"Correspondance avec&lt;br/&gt;la liste de rappel locale ?"}
 G --&gt;|"non"| H["Écartée — rien n'est stocké"]
 G --&gt;|"oui"| I["Alerte à l'agent&lt;br/&gt;+ file d'attente locale"]
 I --&gt;|"synchronisation au retour du réseau"| B
 B --&gt; J["Tableau de bord&lt;br/&gt;unités · tournées · détections · incidents"]
 J --&gt; K["Processus de contact des propriétaires&lt;br/&gt;identifié → contacté → réparé"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Ingestion et versionnage des données.&lt;/strong&gt; 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&amp;rsquo;aide d&amp;rsquo;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&amp;rsquo;import.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correspondance malgré le bruit de l&amp;rsquo;OCR.&lt;/strong&gt; La détection des plaques et la reconnaissance
des caractères s&amp;rsquo;exécutent sur l&amp;rsquo;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 &lt;em&gt;correction positionnelle&lt;/em&gt; exploite la structure connue des formats de plaques
nationaux (actuel et ancien) pour lever les confusions classiques de l&amp;rsquo;OCR (O/0, I/1, S/5,
B/8, Z/2, G/6), en rejetant toute lecture ambiguë ; (ii) une &lt;em&gt;confirmation par double
lecture&lt;/em&gt; 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).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synchronisation pensée pour le hors-ligne.&lt;/strong&gt; Les correspondances sont mises en file d&amp;rsquo;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).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Opérations de terrain.&lt;/strong&gt; 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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;à la
réparation et une ventilation par territoire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protection des données dès la conception.&lt;/strong&gt; 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&amp;rsquo;audit ; l&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="déploiement--exploitation-devops"&gt;&lt;a href="#d%c3%a9ploiement--exploitation-devops" class="header-anchor"&gt;&lt;/a&gt;Déploiement &amp;amp; exploitation (DevOps)
&lt;/h2&gt;&lt;p&gt;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&amp;rsquo;essentiel du travail d&amp;rsquo;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.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 subgraph ADM["Poste d'administration"]
 GIT["Dépôt Git&lt;br/&gt;arbre commité uniquement"]
 PROV["Script de provisionnement&lt;br/&gt;un fichier de configuration par unité"]
 BLD["Build terrain&lt;br/&gt;paquet PyInstaller + modèles ONNX"]
 end
 subgraph SRV["Serveur (VPS Ubuntu LTS)"]
 CAD["Caddy&lt;br/&gt;TLS · HSTS · sans journal d'accès"]
 APP["Conteneur Docker&lt;br/&gt;API FastAPI + tableau de bord&lt;br/&gt;port en boucle locale uniquement"]
 VOL[("Volume LUKS2&lt;br/&gt;SQLite · photos · archives")]
 TIM["Timers systemd&lt;br/&gt;supervision · sauvegarde · nettoyage"]
 end
 FLD["Portables de terrain&lt;br/&gt;SQLite local · boucle de synchronisation"]
 OBJ[("Stockage objet externe&lt;br/&gt;sauvegardes chiffrées age")]
 CHAT["Alertes messagerie&lt;br/&gt;changements d'état + bilans quotidiens"]
 GIT --&gt;|"git archive via SSH → script de déploiement"| APP
 PROV --&gt;|"API d'administration"| APP
 PROV --&gt;|"fichier de configuration + LISEZMOI"| FLD
 BLD --&gt;|"archive + installateur en un clic"| FLD
 FLD &lt;--&gt;|"HTTPS : signal de vie · envois · diff des rappels"| CAD
 CAD --&gt; APP
 APP --- VOL
 TIM --&gt; VOL
 TIM --&gt;|"copie chiffrée"| OBJ
 TIM --&gt; CHAT&lt;/pre&gt;&lt;h3 id="portables-de-terrain--empaquetage-installation-et-mises-à-jour"&gt;&lt;a href="#portables-de-terrain--empaquetage-installation-et-mises-%c3%a0-jour" class="header-anchor"&gt;&lt;/a&gt;Portables de terrain : empaquetage, installation et mises à jour
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Empaquetage.&lt;/strong&gt; L&amp;rsquo;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&amp;rsquo;OCR : une unité n&amp;rsquo;a besoin ni d&amp;rsquo;une
installation Python ni du réseau pour lire les plaques. Des modes intégrés
&lt;code&gt;--diag&lt;/code&gt; et &lt;code&gt;--selftest&lt;/code&gt; vérifient l&amp;rsquo;environnement d&amp;rsquo;exécution embarqué et
lisent une image de test sans lancer l&amp;rsquo;interface, ce qui a permis de
diagnostiquer les échecs de démarrage directement sur la machine de terrain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installateur en un clic.&lt;/strong&gt; Le build est livré sous forme d&amp;rsquo;archive avec un
&lt;code&gt;INSTALLER.bat&lt;/code&gt; à lancer d&amp;rsquo;un double-clic. Il s&amp;rsquo;é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&amp;rsquo;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&amp;rsquo;unité là où
l&amp;rsquo;exécutable le lit. Le script refuse de deviner : si plusieurs fichiers de
configuration &lt;em&gt;différents&lt;/em&gt; sont présents, il les liste et demande lequel est
le nouveau. Une réinitialisation optionnelle efface la base locale lorsqu&amp;rsquo;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&amp;rsquo;accès de l&amp;rsquo;unité n&amp;rsquo;est jamais affiché. Une mise à jour suit le même
chemin : nouveau build, nouvelle exécution de l&amp;rsquo;installateur.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Provisionnement.&lt;/strong&gt; Un script Python qui n&amp;rsquo;utilise que la bibliothèque
standard, et tourne donc sur un Windows nu, crée les unités à partir d&amp;rsquo;un
fichier CSV via l&amp;rsquo;API d&amp;rsquo;administration du serveur et génère, pour chacune, son
fichier de configuration (adresse du serveur, code de l&amp;rsquo;unité, nom affiché,
jeton) et un LISEZMOI à remettre avec le portable. La clé d&amp;rsquo;administration est
lue dans une variable d&amp;rsquo;environnement ou saisie de manière masquée, jamais
passée en argument de ligne de commande.&lt;/p&gt;
&lt;h3 id="versionnage--logiciel-et-liste-de-rappel"&gt;&lt;a href="#versionnage--logiciel-et-liste-de-rappel" class="header-anchor"&gt;&lt;/a&gt;Versionnage : logiciel et liste de rappel
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Version du logiciel.&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version de la liste de rappel.&lt;/strong&gt; 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&amp;rsquo;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&amp;rsquo;empreinte locale n&amp;rsquo;avance que si tout a été appliqué.&lt;/p&gt;
&lt;p&gt;Cette dernière règle vient d&amp;rsquo;un incident de terrain. Une contrainte de la base
de données faisait échouer le diff sur une unité, l&amp;rsquo;erreur était absorbée par
la boucle de synchronisation, et l&amp;rsquo;unité continuait d&amp;rsquo;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&amp;rsquo;ancien schéma. La
supervision lève désormais une alerte « synchronisation des rappels figée »
lorsqu&amp;rsquo;une unité n&amp;rsquo;a pas reçu une liste publiée au-delà d&amp;rsquo;un délai de grâce.&lt;/p&gt;
&lt;h3 id="synchronisation-incrémentale-et-résiliente"&gt;&lt;a href="#synchronisation-incr%c3%a9mentale-et-r%c3%a9siliente" class="header-anchor"&gt;&lt;/a&gt;Synchronisation incrémentale et résiliente
&lt;/h3&gt;&lt;p&gt;Toutes les cinq minutes, ou à la demande, une unité exécute un cycle de
synchronisation composé d&amp;rsquo;é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&amp;rsquo;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.&lt;/p&gt;
&lt;h3 id="déploiement-du-serveur"&gt;&lt;a href="#d%c3%a9ploiement-du-serveur" class="header-anchor"&gt;&lt;/a&gt;Déploiement du serveur
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Kit d&amp;rsquo;instance.&lt;/strong&gt; Chaque déploiement est une instance indépendante, décrite
par un court identifiant, sur un serveur virtuel Ubuntu LTS. Un script
d&amp;rsquo;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&amp;rsquo;authentification par clé, active un pare-feu en refus par défaut et une
protection contre la force brute, et vérifie que l&amp;rsquo;enregistrement DNS pointe
vers le serveur avant d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conteneur et proxy inverse.&lt;/strong&gt; 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&amp;rsquo;OCR sont chargés avant que le serveur n&amp;rsquo;écoute. Le conteneur n&amp;rsquo;est publié
que sur l&amp;rsquo;interface de boucle locale. Caddy est le seul point d&amp;rsquo;entrée public :
certificat Let&amp;rsquo;s Encrypt automatique, HSTS explicite et aucun journal
d&amp;rsquo;accès, car les URL de scan contiennent des plaques. Le journal d&amp;rsquo;accès de
l&amp;rsquo;application elle-même est désactivé pour la même raison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Déploiement et retour arrière.&lt;/strong&gt; Le code ne quitte le poste
d&amp;rsquo;administration que sous la forme d&amp;rsquo;un &lt;code&gt;git archive&lt;/code&gt; d&amp;rsquo;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&amp;rsquo;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&amp;rsquo;interrompt ni le déploiement ni un retour arrière. Un
verrou empêche les déploiements concurrents. Le script construit l&amp;rsquo;image
(étiquetée avec son commit), conserve l&amp;rsquo;image précédente comme &lt;code&gt;rollback&lt;/code&gt;,
recrée le conteneur et attend qu&amp;rsquo;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&amp;rsquo;échec, il revient automatiquement à l&amp;rsquo;image et à l&amp;rsquo;arbre source
précédents, met de côté le code en échec et envoie une alerte. Revenir à
n&amp;rsquo;importe quelle version antérieure revient à redéployer ce commit. Un retour
arrière d&amp;rsquo;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.&lt;/p&gt;
&lt;h3 id="volume-chiffré-et-redémarrages-sûrs"&gt;&lt;a href="#volume-chiffr%c3%a9-et-red%c3%a9marrages-s%c3%bbrs" class="header-anchor"&gt;&lt;/a&gt;Volume chiffré et redémarrages sûrs
&lt;/h3&gt;&lt;p&gt;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&amp;rsquo;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&amp;rsquo;un fichier sentinelle
&lt;em&gt;situé sur le volume chiffré&lt;/em&gt; est absent. Sans lui, un redémarrage aurait
laissé un dossier vide à la place du volume, et l&amp;rsquo;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&amp;rsquo;il est monté.&lt;/p&gt;
&lt;h3 id="sauvegardes-et-reprise"&gt;&lt;a href="#sauvegardes-et-reprise" class="header-anchor"&gt;&lt;/a&gt;Sauvegardes et reprise
&lt;/h3&gt;&lt;p&gt;Un timer systemd quotidien prend un instantané cohérent de la base SQLite via
son API de sauvegarde, l&amp;rsquo;archive avec les photos et les archives de rappel, et
chiffre le résultat avec &lt;code&gt;age&lt;/code&gt; vers une clé publique. La clé privée n&amp;rsquo;est
affichée qu&amp;rsquo;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 &lt;code&gt;rclone&lt;/code&gt;, configuré uniquement par variables
d&amp;rsquo;environnement. Un mode de &lt;em&gt;test&lt;/em&gt; de restauration déchiffre une sauvegarde
dans un dossier temporaire sur le volume chiffré, lance un contrôle
d&amp;rsquo;intégrité, compte les lignes par table, puis efface tout. Le mode
d&amp;rsquo;&lt;em&gt;application&lt;/em&gt; déplace l&amp;rsquo;é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.&lt;/p&gt;
&lt;h3 id="supervision"&gt;&lt;a href="#supervision" class="header-anchor"&gt;&lt;/a&gt;Supervision
&lt;/h3&gt;&lt;p&gt;Un chien de garde s&amp;rsquo;exécute toutes les 15 minutes et ne publie sur un webhook
de messagerie que lorsqu&amp;rsquo;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&amp;rsquo;API (avec
plusieurs essais, car l&amp;rsquo;import quotidien peut le bloquer environ une minute),
l&amp;rsquo;état de santé du conteneur, la lisibilité de la base, l&amp;rsquo;occupation du disque
système et du volume chiffré, la taille du journal d&amp;rsquo;écriture anticipée de
SQLite, l&amp;rsquo;expiration du certificat TLS, l&amp;rsquo;â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&amp;rsquo;aucun import de liste de rappel
n&amp;rsquo;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 &lt;code&gt;rollback&lt;/code&gt;. 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.&lt;/p&gt;
&lt;h3 id="résilience-hors-ligne"&gt;&lt;a href="#r%c3%a9silience-hors-ligne" class="header-anchor"&gt;&lt;/a&gt;Résilience hors ligne
&lt;/h3&gt;&lt;p&gt;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&amp;rsquo;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é.&lt;/p&gt;
&lt;h3 id="tests"&gt;&lt;a href="#tests" class="header-anchor"&gt;&lt;/a&gt;Tests
&lt;/h3&gt;&lt;p&gt;Le dépôt ne comporte pas de chaîne d&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Lors des premières opérations de terrain, les agents ont signalé &lt;strong&gt;32 %&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;Les nouvelles étapes ont été livrées avec des tests unitaires : &lt;strong&gt;12/12&lt;/strong&gt; pour la
correction des plaques et &lt;strong&gt;6/6&lt;/strong&gt; pour la confirmation, les réglages et le journal des
lectures.&lt;/li&gt;
&lt;li&gt;Après l&amp;rsquo;extension de la table de correspondance des noms de modèles, &lt;strong&gt;une seule&lt;/strong&gt; ligne
de la liste de rappel de production restait sans nom de modèle décodé.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aucun taux de reconnaissance de bout en bout n&amp;rsquo;a encore été mesuré.&lt;/p&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;La précision de la reconnaissance n&amp;rsquo;a pas été mesurée sur un banc d&amp;rsquo;essai avec vérité
terrain. Les objectifs du cahier des charges (taux de lecture, latence) sont des
objectifs de conception, non des résultats.&lt;/li&gt;
&lt;li&gt;Aucune lecture de plaque à l&amp;rsquo;ancien format n&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;Une fausse correspondance avec une liste volumineuse coûte toujours du temps aux agents.
L&amp;rsquo;étape suivante consiste à calibrer le seuil de confiance et la fenêtre de confirmation
sur des vidéos de terrain annotées.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;FastAPI&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;ONNX Runtime&lt;/code&gt; · &lt;code&gt;fast-alpr&lt;/code&gt; (détecteur de plaques YOLOv9 + OCR) · &lt;code&gt;OpenCV&lt;/code&gt; · &lt;code&gt;PaddleOCR&lt;/code&gt; · &lt;code&gt;React&lt;/code&gt; · &lt;code&gt;TypeScript&lt;/code&gt; · &lt;code&gt;Vite&lt;/code&gt; · &lt;code&gt;Leaflet&lt;/code&gt; · &lt;code&gt;Docker&lt;/code&gt; · &lt;code&gt;Caddy&lt;/code&gt; · &lt;code&gt;LUKS&lt;/code&gt; · &lt;code&gt;systemd&lt;/code&gt; · &lt;code&gt;age&lt;/code&gt; · &lt;code&gt;rclone&lt;/code&gt; · &lt;code&gt;PyInstaller&lt;/code&gt; · &lt;code&gt;PowerShell&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Analyse vidéo géolocalisée et mesure des distances entre objets</title><link>https://borisdupoux.com/fr/research/video-geolocation/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/video-geolocation/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les sites industriels sont souvent couverts par des caméras fixes dont les images ne sont consultées qu&amp;rsquo;après un incident et ne produisent aucune donnée exploitable. L&amp;rsquo;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&amp;rsquo;une boîte en pixels.&lt;/p&gt;
&lt;p&gt;La difficulté tient à trois raisons. Une caméra unique ne donne pas de profondeur, si bien que l&amp;rsquo;é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&amp;rsquo;image à 640 px élimine le détail géométrique dont dépendent les positions au sol.&lt;/p&gt;
&lt;h2 id="approche"&gt;&lt;a href="#approche" class="header-anchor"&gt;&lt;/a&gt;Approche
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Source vidéo&lt;br/&gt;fichier · RTSP · séquence drone (jusqu'à 3840×2160)"] --&gt; B["Détecteur d'objets en résolution native&lt;br/&gt;détection · segmentation · pose · OBB"]
 A --&gt; C["Modèle de profondeur monoculaire métrique&lt;br/&gt;carte de profondeur"]
 B --&gt; D["Suivi multi-objets&lt;br/&gt;modèle de mouvement + association"]
 B --&gt; E["Profondeur par objet&lt;br/&gt;pixels du masque, rejet des aberrants"]
 C --&gt; E
 E --&gt; F["Lancer de rayon&lt;br/&gt;rayon pixel + profondeur métrique + pose caméra"]
 F --&gt; G["Position WGS84&lt;br/&gt;MNT optionnel pour l'altitude du sol"]
 E --&gt; H["Distances 3D&lt;br/&gt;entre masques · le long des trajectoires"]
 D --&gt; H
 G --&gt; I["Stockage SQLite&lt;br/&gt;détections · pistes · trajectoires GPS"]
 H --&gt; I
 I --&gt; J["Analyses&lt;br/&gt;zones · flux · superposition sur orthophoto"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Détection.&lt;/strong&gt; 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&amp;rsquo;inférence s&amp;rsquo;exécute en résolution native, sans &lt;code&gt;imgsz&lt;/code&gt; 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).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Profondeur monoculaire.&lt;/strong&gt; Un modèle de profondeur monoculaire métrique prédit une carte de profondeur, rééchantillonnée à la taille de l&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Géolocalisation par lancer de rayon.&lt;/strong&gt; Un rayon est lancé depuis le centre de la caméra à travers le pixel de l&amp;rsquo;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&amp;rsquo;altitude du sol. Les positions peuvent être superposées à une orthophoto géoréférencée pour un contrôle visuel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Suivi.&lt;/strong&gt; 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&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distances entre objets.&lt;/strong&gt; 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&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingénierie.&lt;/strong&gt; La configuration permet une répartition sur deux GPU (détection sur un périphérique, estimation de la profondeur sur l&amp;rsquo;autre), la découverte et l&amp;rsquo;enregistrement de flux RTSP, ainsi que le traitement de plusieurs caméras en parallèle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;p&gt;Mesures effectuées sur une seule NVIDIA RTX 5090. Le banc d&amp;rsquo;essai de détection ne couvre que la détection et le suivi, profondeur désactivée.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Configuration&lt;/th&gt;
					&lt;th&gt;Vidéo&lt;/th&gt;
					&lt;th&gt;Débit&lt;/th&gt;
					&lt;th&gt;Sortie&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Plus gros détecteur, batch 1&lt;/td&gt;
					&lt;td&gt;3840×2160, 50 fps, 3 301 images&lt;/td&gt;
					&lt;td&gt;5,1 fps&lt;/td&gt;
					&lt;td&gt;320 217 détections, 1 941 pistes&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Plus petit détecteur, batch 1&lt;/td&gt;
					&lt;td&gt;3840×2160, 50 fps&lt;/td&gt;
					&lt;td&gt;13,0 fps&lt;/td&gt;
					&lt;td&gt;158 989 détections, 908 pistes&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Plus gros détecteur, batch 1&lt;/td&gt;
					&lt;td&gt;2304×1296, 15 fps, 5 000 images&lt;/td&gt;
					&lt;td&gt;17,9 fps&lt;/td&gt;
					&lt;td&gt;73 502 détections, 2 706 pistes&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Plus petit détecteur, batch 1&lt;/td&gt;
					&lt;td&gt;2304×1296, 15 fps&lt;/td&gt;
					&lt;td&gt;39,0 fps&lt;/td&gt;
					&lt;td&gt;51 890 détections, 1 499 pistes&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Chaîne complète (détection + profondeur + suivi + stockage)&lt;/td&gt;
					&lt;td&gt;2304×1296, 300 images&lt;/td&gt;
					&lt;td&gt;2,02 fps&lt;/td&gt;
					&lt;td&gt;12,3 détections par image&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Sur l&amp;rsquo;exécution de la chaîne complète, l&amp;rsquo;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&amp;rsquo;étranglement est l&amp;rsquo;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&amp;rsquo;usage visé, à savoir l&amp;rsquo;analyse d&amp;rsquo;archives enregistrées et non l&amp;rsquo;alerte en direct.&lt;/p&gt;
&lt;h2 id="limites--suite"&gt;&lt;a href="#limites--suite" class="header-anchor"&gt;&lt;/a&gt;Limites &amp;amp; suite
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Aucune précision de géolocalisation n&amp;rsquo;a encore été mesurée par rapport à une vérité terrain levée. L&amp;rsquo;étape de lancer de rayon a été ajoutée après les mesures de temps ci-dessus ; son coût n&amp;rsquo;y est donc pas inclus.&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;é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&amp;rsquo;inclinaison ou de focale se répercutent directement sur les positions au sol.&lt;/li&gt;
&lt;li&gt;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&amp;rsquo;exécute en 4K.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;PyTorch&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · &lt;code&gt;NumPy&lt;/code&gt; · &lt;code&gt;SciPy&lt;/code&gt; · &lt;code&gt;pyproj&lt;/code&gt; · &lt;code&gt;rasterio&lt;/code&gt; · &lt;code&gt;SQLite&lt;/code&gt; · &lt;code&gt;CUDA&lt;/code&gt; · &lt;code&gt;Apple MPS&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Détection de polluants par drone (jour &amp; nuit)</title><link>https://borisdupoux.com/fr/research/pollutant-detection/</link><pubDate>Mon, 01 Jul 2024 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/pollutant-detection/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Détecter depuis un drone les &lt;strong&gt;polluants gazeux et les hydrocarbures&lt;/strong&gt;, &lt;strong&gt;de jour comme
de nuit&lt;/strong&gt;, afin de surveiller les sources de pollution mobiles (navires, engins) dans
les zones maritimes et industrielles.&lt;/p&gt;
&lt;h2 id="chaîne-de-traitement"&gt;&lt;a href="#cha%c3%aene-de-traitement" class="header-anchor"&gt;&lt;/a&gt;Chaîne de traitement
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Drone — thermique/IR + visible"] --&gt; B["Acquisition jour / nuit"]
 B --&gt; C["Détection de signatures polluantes"]
 C --&gt; D["Localisation sur cibles en mouvement"]
 D --&gt; E["Surveillance maritime / industrielle"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Imagerie combinée thermique/infrarouge et spectre visible.&lt;/li&gt;
&lt;li&gt;Détection et localisation de traces de polluants sur des cibles &lt;strong&gt;en mouvement&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fonctionnement en conditions diurnes comme nocturnes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Détection de fuites de carburant et de rejets d&amp;rsquo;hydrocarbures dans les zones portuaires et les eaux côtières.&lt;/li&gt;
&lt;li&gt;Capacité de surveillance continue des zones maritimes et industrielles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · imagerie thermique/IR · drone&lt;/p&gt;</description></item><item><title>Détection des sargasses par satellite &amp; prédiction des échouements</title><link>https://borisdupoux.com/fr/research/sargassum-detection/</link><pubDate>Sat, 01 Jun 2024 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/sargassum-detection/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Les échouements de sargasses perturbent les littoraux caribéens. L&amp;rsquo;objectif : &lt;strong&gt;détecter
tôt les radeaux d&amp;rsquo;algues en mer&lt;/strong&gt; et &lt;strong&gt;prédire où et en quelle quantité&lt;/strong&gt; ils
s&amp;rsquo;échoueront, afin que les communes et les autorités environnementales puissent
planifier à l&amp;rsquo;avance le ramassage — et les interventions en mer.&lt;/p&gt;
&lt;h2 id="le-problème--une-réflectance-brute-difficile-à-lire"&gt;&lt;a href="#le-probl%c3%a8me--une-r%c3%a9flectance-brute-difficile-%c3%a0-lire" class="header-anchor"&gt;&lt;/a&gt;Le problème : une réflectance brute difficile à lire
&lt;/h2&gt;&lt;p&gt;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&amp;rsquo;eau environnante, et la
structure d&amp;rsquo;ensemble d&amp;rsquo;une bande — où elle commence, où elle s&amp;rsquo;amincit, où elle se
disloque — est difficile à distinguer à l&amp;rsquo;œil comme avec des indices génériques.&lt;/p&gt;
&lt;p&gt;Savoir &lt;em&gt;qu&amp;rsquo;il y a&lt;/em&gt; des sargasses ne suffit pas. Pour agir, il faut voir &lt;strong&gt;à quoi
elles ressemblent&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="contribution-principale--un-indicateur-de-contraste-original"&gt;&lt;a href="#contribution-principale--un-indicateur-de-contraste-original" class="header-anchor"&gt;&lt;/a&gt;Contribution principale : un indicateur de contraste original
&lt;/h2&gt;&lt;p&gt;J&amp;rsquo;ai conçu un &lt;strong&gt;indicateur de contraste dédié&lt;/strong&gt; aux sargasses. Plutôt que de
simplement signaler des pixels, il est construit pour donner une &lt;strong&gt;lecture très
nette des données et des formes&lt;/strong&gt; : radeaux et bandes ressortent franchement de
l&amp;rsquo;eau, avec des contours bien définis et une structure interne préservée.
(Détails de formulation non publiés pour l&amp;rsquo;instant.)&lt;/p&gt;
&lt;p&gt;Ce qu&amp;rsquo;il apporte :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une &lt;strong&gt;délimitation nette&lt;/strong&gt; des radeaux et des bandes allongées de sargasses.&lt;/li&gt;
&lt;li&gt;Une image lisible de &lt;strong&gt;l&amp;rsquo;organisation de la masse&lt;/strong&gt;, et pas seulement de sa position.&lt;/li&gt;
&lt;li&gt;Une entrée plus propre pour la segmentation, la quantification et la modélisation
de la dérive en aval.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pourquoi-la-forme-compte"&gt;&lt;a href="#pourquoi-la-forme-compte" class="header-anchor"&gt;&lt;/a&gt;Pourquoi la forme compte
&lt;/h2&gt;&lt;p&gt;La géométrie des bandes est l&amp;rsquo;information clé pour les opérations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dispersion&lt;/strong&gt; — les sargasses sont-elles concentrées en un radeau dense ou
éparpillées en nombreuses petites plaques ?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traîne&lt;/strong&gt; — la façon dont la bande s&amp;rsquo;étire et s&amp;rsquo;allonge derrière sa tête,
qui révèle comment elle est entraînée par les courants et le vent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orientation et direction de dérive&lt;/strong&gt; — vers où se dirige la bande, et donc
quelles portions de côte sont exposées.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est la lecture de ces formes qui permet de &lt;strong&gt;planifier les interventions sur
site&lt;/strong&gt; (où déployer la collecte en mer ou les barrages) et d&amp;rsquo;&lt;strong&gt;anticiper les
échouements&lt;/strong&gt; plutôt que de les subir.&lt;/p&gt;
&lt;h2 id="chaîne-de-traitement"&gt;&lt;a href="#cha%c3%aene-de-traitement" class="header-anchor"&gt;&lt;/a&gt;Chaîne de traitement
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Imagerie satellitaire — multispectrale"] --&gt; B["Masquage nuages / eau"]
 B --&gt; C["Indicateur de contraste sargasses original"]
 C --&gt; D["Délimitation des radeaux &amp; bandes — forme, dispersion, traîne"]
 D --&gt; E["Quantification en mer"]
 E --&gt; F["Modèle de dérive / d'échouement"]
 F --&gt; G["Alertes &amp; planification des interventions"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Analyse d&amp;rsquo;images satellitaires multispectrales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Indicateur de contraste original&lt;/strong&gt; pour une lecture nette des radeaux et bandes de sargasses.&lt;/li&gt;
&lt;li&gt;Analyse de la forme des bandes : dispersion, allongement/traîne, orientation.&lt;/li&gt;
&lt;li&gt;Détection des radeaux et quantification de leur surface en mer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modélisation prédictive de la dérive et des échouements&lt;/strong&gt; pour anticiper les zones d&amp;rsquo;arrivée et les volumes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Cartes claires et lisibles des radeaux et bandes de sargasses en mer.&lt;/li&gt;
&lt;li&gt;Capacité d&amp;rsquo;alerte précoce pour les communes littorales.&lt;/li&gt;
&lt;li&gt;Prévisions quantitatives des échouements au service d&amp;rsquo;une planification proactive du ramassage et des interventions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Visuels et compléments à venir.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · imagerie satellitaire · analyse spectrale · modélisation prédictive&lt;/p&gt;</description></item><item><title>Détection de fissures submillimétriques sur ouvrages de génie civil</title><link>https://borisdupoux.com/fr/research/crack-detection/</link><pubDate>Fri, 01 Mar 2024 00:00:00 +0000</pubDate><guid>https://borisdupoux.com/fr/research/crack-detection/</guid><description>&lt;h2 id="contexte"&gt;&lt;a href="#contexte" class="header-anchor"&gt;&lt;/a&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Surveillance non destructive de l&amp;rsquo;état des ponts, bâtiments et infrastructures.
L&amp;rsquo;enjeu n&amp;rsquo;est pas seulement de &lt;strong&gt;détecter&lt;/strong&gt; les fissures, mais de les &lt;strong&gt;classer
selon leur ouverture&lt;/strong&gt; — sans contact ni échafaudage.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est l&amp;rsquo;ouverture qui compte pour l&amp;rsquo;inspection : selon la largeur d&amp;rsquo;une fissure,
&lt;strong&gt;la méthode de réparation (de remplissage) n&amp;rsquo;est pas la même&lt;/strong&gt;. Un système
d&amp;rsquo;inspection doit donc être très précis, car une mauvaise classe d&amp;rsquo;ouverture
conduit à une mauvaise prescription de réparation.&lt;/p&gt;
&lt;h2 id="quatre-classes-douverture"&gt;&lt;a href="#quatre-classes-douverture" class="header-anchor"&gt;&lt;/a&gt;Quatre classes d&amp;rsquo;ouverture
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Classe&lt;/th&gt;
					&lt;th&gt;Ouverture&lt;/th&gt;
					&lt;th&gt;Conséquence&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;&amp;lt; 0,3 mm&lt;/td&gt;
					&lt;td&gt;Fissures les plus fines — souvent plus étroites qu&amp;rsquo;un pixel ; réparation spécifique&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;0,3 – 0,7 mm&lt;/td&gt;
					&lt;td&gt;Méthode de réparation différente&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;0,7 – 1 mm&lt;/td&gt;
					&lt;td&gt;Méthode de réparation différente&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;≥ 1 mm&lt;/td&gt;
					&lt;td&gt;Méthode de réparation différente&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Chaque classe appelle sa propre méthode de remplissage ou de réparation : la
classification conditionne donc directement la décision de maintenance.&lt;/p&gt;
&lt;h2 id="le-défi-du-sous-pixel"&gt;&lt;a href="#le-d%c3%a9fi-du-sous-pixel" class="header-anchor"&gt;&lt;/a&gt;Le défi du sous-pixel
&lt;/h2&gt;&lt;p&gt;La principale difficulté est de descendre &lt;strong&gt;sous la taille du pixel&lt;/strong&gt;. Une
fissure de 0,3 mm ne couvre même pas un pixel entier aux résolutions
d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Pourquoi est-ce possible ? Une fissure plus fine qu&amp;rsquo;un pixel ne disparaît pas :
elle occupe &lt;strong&gt;une partie&lt;/strong&gt; des pixels qu&amp;rsquo;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 &lt;strong&gt;continu et allongé&lt;/strong&gt; :
le même contraste ténu se répète de façon cohérente sur de nombreux pixels
voisins. C&amp;rsquo;est en exploitant ce contraste et cette continuité qu&amp;rsquo;on peut détecter
la fissure — et estimer son ouverture — au-delà de la résolution nominale de l&amp;rsquo;image.&lt;/p&gt;
&lt;h2 id="acquisition--drone-et-smartphone"&gt;&lt;a href="#acquisition--drone-et-smartphone" class="header-anchor"&gt;&lt;/a&gt;Acquisition : drone et smartphone
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Photographie par drone&lt;/strong&gt; — acquisition haute résolution des surfaces des
ouvrages, pour les structures étendues ou difficiles d&amp;rsquo;accès.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Photographie au smartphone&lt;/strong&gt; — l&amp;rsquo;approche fonctionne aussi sur des images
prises au téléphone portable, ce que j&amp;rsquo;ai testé, ce qui permet une inspection
rapprochée avec un équipement courant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="chaîne-de-traitement"&gt;&lt;a href="#cha%c3%aene-de-traitement" class="header-anchor"&gt;&lt;/a&gt;Chaîne de traitement
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 A["Prise de vue — drone ou smartphone"] --&gt; B["Découpage en tuiles &amp; calibration"]
 B --&gt; C["Segmentation des fissures — CV / DL"]
 C --&gt; D["Estimation sous-pixel de l'ouverture"]
 D --&gt; E["Classification de l'ouverture — 4 classes"]
 E --&gt; F["Carte des défauts &amp; rapport d'inspection"]&lt;/pre&gt;&lt;h2 id="méthodes"&gt;&lt;a href="#m%c3%a9thodes" class="header-anchor"&gt;&lt;/a&gt;Méthodes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Acquisition haute résolution des surfaces des ouvrages par drone ou smartphone.&lt;/li&gt;
&lt;li&gt;Segmentation des fissures par vision par ordinateur / apprentissage profond sur béton et maçonnerie.&lt;/li&gt;
&lt;li&gt;Calibration métrique et analyse &lt;strong&gt;sous-pixel&lt;/strong&gt; pour l&amp;rsquo;estimation de l&amp;rsquo;ouverture des fissures.&lt;/li&gt;
&lt;li&gt;Classification en quatre classes d&amp;rsquo;ouverture associées aux méthodes de réparation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="résultats"&gt;&lt;a href="#r%c3%a9sultats" class="header-anchor"&gt;&lt;/a&gt;Résultats
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Inspection non destructive et reproductible des ouvrages de génie civil.&lt;/li&gt;
&lt;li&gt;Cartes de défauts géolocalisées pour hiérarchiser les interventions de maintenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Modèles et visuels à venir.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="stack-technique"&gt;&lt;a href="#stack-technique" class="header-anchor"&gt;&lt;/a&gt;Stack technique
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;OpenCV&lt;/code&gt; · apprentissage profond · drone RVB haute résolution · imagerie smartphone · photogrammétrie&lt;/p&gt;</description></item></channel></rss>