Coulisses

Épisode 2 — Le prototype qui marchait... sur UN formulaire

L'idée est claire sur le papier. Les trois briques sont dessinées. Il reste à écrire le code — et à découvrir que les formulaires web sont un gouffre de complexité qu'on ne soupçonne pas depuis l'extérieur.

Les 50 premières lignes

Le premier prototype tient en une cinquantaine de lignes de JavaScript. La logique est simple :

  1. Ouvrir l'URL dans Chromium avec Playwright
  2. Lister tous les éléments input, select, textarea visibles
  3. Pour chaque élément, récupérer son name, son id, son placeholder et le texte du label associé
  4. Passer cette liste au LLM avec les colonnes Excel : il retourne un JSON de mapping
  5. Remplir chaque champ : page.fill(selector, value) pour les textes, page.selectOption() pour les menus, page.check() pour les cases

Ça marche. Sur le formulaire de test. Pendant cinq minutes. Puis on essaie un deuxième formulaire — un vrai formulaire d'onboarding SIRH cette fois.

Catastrophe.

Le mur de la complexité

La diversité des formulaires web est un gouffre dont on ne mesure pas l'ampleur avant d'avoir essayé de les remplir programmatiquement. Ce qu'on imagine comme "un champ texte" cache en réalité des dizaines de variantes :

Les selects en cascade. Sélectionner "France" dans le champ "Pays" fait apparaître les régions. Sélectionner "Île-de-France" fait apparaître les départements. Sélectionner "Paris" (75) met à jour le code postal. Chaque sélection déclenche une requête asynchrone, un rechargement partiel de la page. Si on enchaîne les selectOption() sans attendre, la deuxième valeur disparaît quand la troisième se charge. Il faut détecter la fin du rechargement et attendre.

Les date pickers custom. Le champ input[type="date"] natif du navigateur est souvent remplacé par un composant JavaScript avec son propre calendrier graphique. page.fill() n'y fait rien — le champ n'est pas un vrai input. Il faut simuler un clic pour ouvrir le calendrier, cliquer sur le mois, cliquer sur l'année, cliquer sur le jour.

Les champs conditionnellement masqués. Certains formulaires SIRH ne montrent les champs "Coordonnées bancaires" que lorsqu'un onglet spécifique est actif, ou que le type de contrat sélectionné déclenche leur affichage. L'inspecteur qui liste tous les input trouve ces champs — mais ils ne sont pas remplissables car non visibles. Il faut filtrer les éléments réellement interactifs.

Les selects déguisés. Des <div> qui se comportent comme des <select> avec des rôles ARIA (role="combobox", role="listbox", role="option"), une navigation au clavier, mais aucune balise <option> dans le DOM. page.selectOption() ne fonctionne pas dessus — il faut cliquer sur le div, attendre l'ouverture de la liste, puis cliquer sur la valeur.

Les champs autocomplete. Taper "Mar" dans un champ "Ville" déclenche une requête à une API de géolocalisation. Un dropdown apparaît avec des suggestions. Il faut cliquer sur "Marseille" dans ce dropdown — pas simplement remplir le champ avec la valeur finale.

Face à tout ça, le fichier form-inspector.js grossit. 50 lignes. 150. 300. 600. Il apprend à filtrer les éléments vraiment visibles (pas de display:none, pas de visibility:hidden, pas de opacity:0, pas de pointer-events:none). Il apprend à déduire le label associé à un champ en remontant le DOM : chercher un label[for="id-du-champ"], sinon un aria-label, sinon un aria-labelledby qui pointe vers un autre élément, sinon le texte du nœud parent le plus proche. Il apprend à distinguer les vrais selects des selects ARIA.

L'IA pour le mapping : une règle non négociable

La question du mapping colonnes Excel → champs de formulaire est là où l'IA entre en jeu. Comment savoir que la colonne "NOM" doit aller dans le champ last_name ? Que "Date naissance" correspond à "Birthdate" sur un formulaire en anglais ? C'est de la sémantique, du langage naturel — exactement ce pour quoi un LLM est conçu.

Mais il y a une règle posée dès le premier jour, non négociable : le LLM ne voit jamais vos valeurs réelles.

Il reçoit uniquement deux listes :

  • Les noms de colonnes du fichier Excel : ["Prénom", "NOM", "Date_naissance", "IBAN", "Poste", ...]
  • Les labels des champs détectés dans le formulaire : ["first_name", "last_name", "dob", "bank_iban", "job_title", ...]

Il rend un objet JSON de mapping. C'est tout. Les 500 lignes de votre fichier Excel, avec les vrais noms, les vrais IBANs, les vraies dates de naissance, ne transitent jamais par un serveur d'IA. C'est une contrainte architecturale, pas une promesse de confidentialité dans les CGU.

Pour les fichiers Excel structurés de façon complexe — cellules fusionnées, titres au milieu du tableau, données sur plusieurs onglets — j'ajoute un premier appel LLM en amont. Cet appel (extractExcelData) reçoit uniquement le texte brut de l'Excel (quelques centaines de caractères représentatifs, pas les valeurs sensibles). Il identifie où se trouve l'en-tête, quelles lignes sont des titres de section, quelles colonnes contiennent des données utiles. Le second appel (suggestMapping) travaille ensuite sur une liste propre d'en-têtes.

Premier résultat qui marche vraiment

Après quelques semaines de développement, le wizard prend forme : upload du fichier Excel, saisie de l'URL du formulaire, validation du mapping suggéré par l'IA, remplissage ligne par ligne.

Premier test sur un vrai formulaire d'onboarding RH : 8 champs sur 11 mappés correctement au premier essai. Les 3 champs ratés ? Des colonnes avec des noms ambigus dans l'Excel — "Info1", "Zone_temp", "Ref_interne" — que même un humain aurait du mal à mapper sans contexte. L'utilisateur les corrige à la main en deux clics.

Ce n'est pas parfait. Mais c'est utilisable. C'est la première fois que l'outil fait ce qu'il est censé faire sur un cas réel, pas sur un formulaire de test fabriqué pour l'occasion.

L'étape suivante : ouvrir ça à de vraies personnes, et voir ce qui résiste à l'usage.

Essayez avec votre premier fichier

Importez votre Excel, indiquez l'URL du formulaire. DataToForm pré-remplit la première ligne gratuitement.

Démarrer gratuitement

← Retour au blog