V1.010 préparation de la création d'une banque de dictées

This commit is contained in:
2026-09-03 20:36:51 +00:00
parent 32e36387dd
commit fc5ea2d5ba
9 changed files with 532 additions and 38 deletions
+81
View File
@@ -0,0 +1,81 @@
<?php
/**
* ASPIC — dictees_test.php
*
* Outil de mise au point interne (3 septembre 2026, demande de Jean-Marc) —
* PAS un endpoint destiné aux futurs utilisateurs. Reçoit, sans aucune
* interprétation, chaque énoncé capté par micro_test.js (branché
* temporairement sur le micro de l'écran de fond — voir le commentaire
* d'en-tête de ce fichier et celui d'ecran_fond.html) et l'enregistre tel
* quel dans ASP_DicteesTest — y compris les essais ratés, jamais filtrés ni
* supprimables depuis l'écran (décision explicite de Jean-Marc : un post-it
* raté fera aussi partie de la vraie vie des futurs utilisateurs, la banque
* de tests doit en tenir compte dès maintenant plutôt que de ne garder que
* les essais réussis).
*
* Objectif : accumuler un corpus réel de dictées sur le thème "Gestion des
* Contacts" — valeur par défaut de DCT_Theme, posée directement en base
* (DEFAULT 'Gestion des Contacts'), volontairement pas reprise ici pour ne
* pas dupliquer une valeur qui doit rester pilotée par la table — en vue de
* concevoir plus tard les règles d'interprétation du pilotage vocal (voir
* réflexions stratégiques).
*
* POST uniquement, corps JSON : { "texte": "..." } — un seul énoncé par
* appel (contrairement à agent_notes.php qui reçoit un lot de lignes d'une
* notation complète, ici chaque énoncé segmenté par le moteur de
* reconnaissance du navigateur est envoyé et enregistré immédiatement).
*
* Session utilisateur : accès réservé aux utilisateurs identifiés, même
* principe que les autres endpoints (agent_notes.php, todolist.php...).
*/
session_start();
header('Content-Type: application/json; charset=utf-8');
require __DIR__ . '/db.php';
if (empty($_SESSION['USR_Code'])) {
http_response_code(401);
echo json_encode(['error' => 'Non identifié — veuillez vous connecter.']);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Méthode non autorisée']);
exit;
}
$data = json_decode(file_get_contents('php://input'), true) ?? [];
$texte = trim((string) ($data['texte'] ?? ''));
if ($texte === '') {
http_response_code(400);
echo json_encode(['error' => 'Rien à enregistrer']);
exit;
}
try {
$pdo = getDbConnection();
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['error' => 'Connexion base de données impossible']);
exit;
}
// DCT_Texte est un TEXT (pas de contrainte de longueur pratique, contrairement
// à CVX_Consigne dans ASP_ConsignesVoix qui est un varchar(200)) : la dictée
// brute est conservée intégralement, sans troncature — un énoncé sur les
// contacts (nom, profession, ville, téléphone...) peut être plus long qu'une
// simple consigne de tâche.
try {
$stmt = $pdo->prepare(
'INSERT INTO ASP_DicteesTest (DCT_Texte, DCT_Utilisateur) VALUES (?, ?)'
);
$stmt->execute([$texte, $_SESSION['USR_Code']]);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['error' => 'Erreur base de données : ' . $e->getMessage()]);
exit;
}
echo json_encode(['success' => true]);
+48 -30
View File
@@ -110,8 +110,35 @@
d'origine, pour se fondre dans la grille plutôt que ressortir comme d'origine, pour se fondre dans la grille plutôt que ressortir comme
un autocollant. Fermé = glyphe micro en gris clair ; ouvert = barres un autocollant. Fermé = glyphe micro en gris clair ; ouvert = barres
façon vu-mètre en --rouge-micro, animées (voir @keyframes) — "les façon vu-mètre en --rouge-micro, animées (voir @keyframes) — "les
barres qui bougent" demandé par Jean-Marc. Toggle en pur JS pour ce barres qui bougent" demandé par Jean-Marc.
test : ne déclenche pas encore la reconnaissance vocale de micro.js. */ Branché sur la reconnaissance vocale réelle le 3 septembre 2026 :
un script pilote désormais #micro-desk et bascule la classe "ecoute"
dessus (voir plus bas #micro-desk.ecoute ~ #micro-icone pour la
bascule visuelle des deux glyphes, via un combinateur de fratrie
puisque #micro-icone n'est pas un descendant de #micro-desk — voir
plus haut pourquoi ces deux éléments sont séparés). Le toggle JS
local qui existait ici pour le tout premier essai d'affichage (pur
visuel, sans reconnaissance vocale) est retiré.
Mise à jour du même jour (suite de session) : ce micro est
temporairement détourné de son usage final. Plutôt que micro.js (le
vrai pilotage, agents nommés Viktor/Matilda/Léon/Nikita, mode
notation — resté inchangé et toujours utilisé tel quel sur
liste_contacts.html), c'est micro_test.js qui est chargé ici, le
temps de la phase de mise au point du pilotage vocal : outil de
constitution d'une banque de dictées réelles (table
ASP_DicteesTest, thème "Gestion des Contacts"), PAS un module
destiné aux futurs utilisateurs (voir le commentaire d'en-tête de
micro_test.js). Écoute continue, aucun mot déclencheur nécessaire
(le clic sur le micro fait déjà office de signal explicite), chaque
énoncé restitué au fur et à mesure dans une fenêtre dédiée puis
enregistré tel quel — y compris les essais ratés, jamais
supprimables depuis l'écran (décision explicite de Jean-Marc : ça
fera aussi partie de la vraie vie des futurs utilisateurs). Pour
reconnecter le vrai pilotage sur ce micro une fois cette phase
terminée : remettre <script src="micro.js"> à la place de
<script src="micro_test.js"> en bas de cette page, rien d'autre à
défaire. */
#micro-desk{ #micro-desk{
position:fixed; position:fixed;
border:none;background:transparent;padding:0;margin:0; border:none;background:transparent;padding:0;margin:0;
@@ -132,6 +159,17 @@
width:70%;height:70%;display:block; width:70%;height:70%;display:block;
} }
#micro-icone svg[hidden]{display:none;} #micro-icone svg[hidden]{display:none;}
/* Bascule repos/écoute pilotée par la classe "ecoute" que le script chargé
en bas de page ajoute sur #micro-desk (micro_test.js actuellement — voir
commentaire plus haut sur le détournement temporaire de ce micro ; même
mécanisme que #bouton-micro.ecoute dans liste_contacts.html avec
micro.js) — combinateur de fratrie ~ nécessaire ici puisque
#micro-icone n'est pas un descendant du bouton. Spécificité (3 id + 1
classe) volontairement plus élevée que la règle [hidden] ci-dessus pour
la surclasser sans !important, l'attribut hidden restant présent dans
le HTML de #glyphe-ecoute (jamais modifié en JS ici désormais). */
#micro-desk.ecoute ~ #micro-icone #glyphe-repos{display:none;}
#micro-desk.ecoute ~ #micro-icone #glyphe-ecoute{display:block;}
#glyphe-repos{ #glyphe-repos{
fill:#d9d9d3; fill:#d9d9d3;
opacity:.92; opacity:.92;
@@ -310,7 +348,7 @@
<a id="classeur-contacts" href="liste_contacts.html" title="Ouvrir le classeur des contacts"></a> <a id="classeur-contacts" href="liste_contacts.html" title="Ouvrir le classeur des contacts"></a>
<div id="etiquette-contacts">Contacts</div> <div id="etiquette-contacts">Contacts</div>
<button id="micro-desk" type="button"></button> <button id="micro-desk" type="button" title="Le micro est inactif"></button>
<div id="micro-icone"> <div id="micro-icone">
<svg id="glyphe-repos" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <svg id="glyphe-repos" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/> <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/>
@@ -493,33 +531,12 @@ Créé par Mevelia Solutions">
window.addEventListener('resize', positionner); window.addEventListener('resize', positionner);
positionner(); positionner();
// Bascule ouvert/fermé du micro du bureau — pur affichage pour ce test // Bascule ouvert/fermé du micro du bureau : gérée par le script chargé en
// (icône + infobulle), ne démarre pas encore la reconnaissance vocale // fin de page (micro_test.js actuellement, voir commentaire plus haut),
// réelle de micro.js. Fermé par défaut à l'arrivée sur l'écran. // qui pilote le clic, la reconnaissance vocale et la classe "ecoute" sur
let microOuvert = false; // #micro-desk — voir la règle CSS correspondante plus
function appliquerEtatMicroDesk() { // haut pour la bascule visuelle des deux glyphes. L'ancien toggle purement
const bouton = document.getElementById('micro-desk'); // visuel du premier essai (2-3 septembre 2026) est retiré.
const glyphRepos = document.getElementById('glyphe-repos');
const glyphEcoute = document.getElementById('glyphe-ecoute');
// setAttribute/removeAttribute plutôt que la propriété .hidden : sur un
// <svg> inline, la réflexion de .hidden s'est révélée peu fiable au test
// (attribut inchangé malgré l'affectation) — passage par l'attribut DOM
// directement pour un résultat garanti.
if (microOuvert) {
glyphRepos.setAttribute('hidden', '');
glyphEcoute.removeAttribute('hidden');
bouton.title = 'Le micro est ouvert, cliquez pour le fermer';
} else {
glyphRepos.removeAttribute('hidden');
glyphEcoute.setAttribute('hidden', '');
bouton.title = 'Le micro est fermé, cliquez pour l\'ouvrir';
}
}
document.getElementById('micro-desk').addEventListener('click', () => {
microOuvert = !microOuvert;
appliquerEtatMicroDesk();
});
appliquerEtatMicroDesk();
// Société et prénom de l'utilisateur connecté (3 septembre 2026, voir // Société et prénom de l'utilisateur connecté (3 septembre 2026, voir
// journal) : preferences.php, même endpoint et même logique que // journal) : preferences.php, même endpoint et même logique que
@@ -667,6 +684,7 @@ Créé par Mevelia Solutions">
// faute d'un "retour" qui ait un sens depuis l'écran d'accueil. À revoir // faute d'un "retour" qui ait un sens depuis l'écran d'accueil. À revoir
// le jour où la ToDoList aura son propre objet cliquable sur le bureau. // le jour où la ToDoList aura son propre objet cliquable sur le bureau.
</script> </script>
<script src="micro_test.js"></script>
</body> </body>
</html> </html>
+8 -3
View File
@@ -80,13 +80,18 @@ Version incrémentée une seule fois pour l'ensemble de cette session (pastille
**3 septembre 2026 : homogénéisation liste des contacts / écran de fond, adaptation à la nouvelle photo de bureau (V1.009).** Détail complet en section 28 du journal (`/journal` sur GitHub). Résumé : nettoyage des bandeaux de `liste_contacts.html` (hamburger, avatar, badge société et micro retirés du haut, regroupés avec le logo et la version dans la barre du bas désormais commune aux deux écrans) ; icône Mévélia Solutions ajoutée devant le logo ASPIC (et en favicon) avec infobulle ; bug corrigé où Échap sur l'écran de fond ouvrait par erreur la ToDoList ; correctif `.htaccess` livré pour un problème récurrent de cache navigateur (déploiement non encore confirmé) ; nouvelle photo `ecran_fond.jpg` fournie par Jean-Marc (chevalet physiquement retiré de la scène, 13px de bureau en moins / de liège en plus), tous les positionnements calés sur l'image repris avec un décalage de +13px mesuré par analyse de pixels ; bloc identité (société/prénom/logo/version) reconstruit en position fixe de viewport, identique sur les deux écrans, après une première tentative erronée de le caler sur les coordonnées de la photo ; bug d'alignement horizontal entre les deux écrans corrigé (résidu de calcul `--sb-width` sans rapport avec cette barre). Version incrémentée une seule fois pour l'ensemble de cette session : **V1.009**. Documentation utilisateur mise à jour en fin de session pour refléter le nouvel écran d'accueil et la disparition du hamburger. **3 septembre 2026 : homogénéisation liste des contacts / écran de fond, adaptation à la nouvelle photo de bureau (V1.009).** Détail complet en section 28 du journal (`/journal` sur GitHub). Résumé : nettoyage des bandeaux de `liste_contacts.html` (hamburger, avatar, badge société et micro retirés du haut, regroupés avec le logo et la version dans la barre du bas désormais commune aux deux écrans) ; icône Mévélia Solutions ajoutée devant le logo ASPIC (et en favicon) avec infobulle ; bug corrigé où Échap sur l'écran de fond ouvrait par erreur la ToDoList ; correctif `.htaccess` livré pour un problème récurrent de cache navigateur (déploiement non encore confirmé) ; nouvelle photo `ecran_fond.jpg` fournie par Jean-Marc (chevalet physiquement retiré de la scène, 13px de bureau en moins / de liège en plus), tous les positionnements calés sur l'image repris avec un décalage de +13px mesuré par analyse de pixels ; bloc identité (société/prénom/logo/version) reconstruit en position fixe de viewport, identique sur les deux écrans, après une première tentative erronée de le caler sur les coordonnées de la photo ; bug d'alignement horizontal entre les deux écrans corrigé (résidu de calcul `--sb-width` sans rapport avec cette barre). Version incrémentée une seule fois pour l'ensemble de cette session : **V1.009**. Documentation utilisateur mise à jour en fin de session pour refléter le nouvel écran d'accueil et la disparition du hamburger.
**3 septembre 2026 (soirée) : micro du bureau branché sur la reconnaissance vocale réelle, puis détourné pour constituer une banque de dictées de test (V1.010).** Détail complet en sections 27 et 28 du journal. Résumé : `micro.js` cherche désormais le bouton micro par `#bouton-micro` (bandeau) ou, à défaut, `#micro-desk` (écran de fond) — un seul comportement partagé, sans dupliquer la logique — et le micro du bureau déclenche bien la reconnaissance vocale réelle depuis ce soir. Discussion stratégique dans la foulée (Réflexions stratégiques, section 12) : Jean-Marc, après avoir montré l'application à sa compagne (confrontée à SAP dans son travail), s'inquiète de la fiabilité du pilotage vocal une fois étendu aux contacts, au catalogue, aux devis, à la facturation — distinction actée avec Claude entre le problème de reconnaissance du mot déclencheur (déjà traité, sa surface d'erreur ne grandit pas avec les modules) et celui de l'interprétation d'une dictée bien captée (à traiter via un LLM à sortie structurée contre un catalogue d'actions, le RAG/pgvector restant réservé à la recherche floue dans un corpus, pas au déclenchement d'action). Décision : constituer d'abord un vrai corpus de dictées avant d'écrire la moindre règle. Micro du bureau temporairement détourné vers un nouvel outil de mise au point (`micro_test.js`/`dictees_test.php`, table `ASP_DicteesTest`, thème "Gestion des Contacts") — écoute continue sans mot déclencheur, restitution au fur et à mesure dans une fenêtre dédiée, aucune suppression possible même pour un essai raté (décision explicite de Jean-Marc : la banque doit refléter la réalité). Premier essai réel concluant le soir même. Version incrémentée une seule fois pour l'ensemble de cette session (branchement réel + outil de test) : **V1.010**.
**Reste à faire, noté au passage :** **Reste à faire, noté au passage :**
- Vérifier concrètement que le `.htaccess` du dossier `/journal` bloque bien l'accès direct (`curl -I` sur un fichier du dossier doit répondre `403`, pas `200` — point en suspens depuis le 31 août). - Vérifier concrètement que le `.htaccess` du dossier `/journal` bloque bien l'accès direct (`curl -I` sur un fichier du dossier doit répondre `403`, pas `200` — point en suspens depuis le 31 août).
- Confirmer le déploiement du correctif `.htaccess` de cache livré le 3 septembre (fichier `htaccess-racine-aspic.txt`, à renommer et déposer à la racine de l'application). - Confirmer le déploiement du correctif `.htaccess` de cache livré le 3 septembre (fichier `htaccess-racine-aspic.txt`, à renommer et déposer à la racine de l'application).
- Pilotage vocal, étape 2 : définir les règles d'interprétation du contenu dicté (aujourd'hui stocké tel quel), envisagée via n8n avec des règles modifiables par l'utilisateur. - Laisser Jean-Marc constituer un vrai volume de dictées sur "Gestion des Contacts" (nouvel outil, voir ci-dessus) avant toute analyse ; puis concevoir le catalogue d'actions et le mécanisme LLM à sortie structurée correspondant (voir réflexions stratégiques, section 12, et journal section 27).
- Reconnecter `micro.js` (vrai pilotage) sur le micro de l'écran de fond une fois la phase de mise au point terminée — une ligne à changer dans `ecran_fond.html`.
- Étendre `MARQUEUR_FIN_LIGNE` dans `micro.js` pour accepter "puis" en plus de "ensuite" (retour d'usage de Jean-Marc, 3 septembre) — sans urgence.
- Continuer à observer les agents actifs (Viktor, Matilda, Léon, Nikita) en usage réel ; ajuster `AGN_Variantes` en base si de nouvelles confusions apparaissent. - Continuer à observer les agents actifs (Viktor, Matilda, Léon, Nikita) en usage réel ; ajuster `AGN_Variantes` en base si de nouvelles confusions apparaissent.
- Documentation utilisateur : le panneau de détail du contact, la ToDoList et le pilotage vocal restent à documenter (mise à jour du 3 septembre limitée à l'écran d'accueil et à la liste des contacts). - Documentation utilisateur : le panneau de détail du contact, la ToDoList et le pilotage vocal restent à documenter (mise à jour du 3 septembre limitée à l'écran d'accueil et à la liste des contacts) — l'outil de banque de dictées n'a volontairement pas vocation à y figurer, ce n'est pas un module utilisateur.
- Écran de fond : reconfirmer l'état de la "tranche du bureau" après le recadrage du 3 septembre (a pu déplacer le problème sans que ce soit son objet) ; décider si les autres objets photographiés (carnet, téléphone) doivent devenir cliquables ; brancher le micro du bureau (et celui de la barre de statut) sur la reconnaissance vocale réelle ; trancher un jour le sort de la piste "maquette liège + post-its par agent" (Claude Design, mise de côté pour cet essai, pas explicitement abandonnée). - Écran de fond : reconfirmer l'état de la "tranche du bureau" après le recadrage du 3 septembre (a pu déplacer le problème sans que ce soit son objet) ; décider si les autres objets photographiés (carnet, téléphone) doivent devenir cliquables ; trancher un jour le sort de la piste "maquette liège + post-its par agent" (Claude Design, mise de côté pour cet essai, pas explicitement abandonnée).
- Concevoir les deux signes graphiques distincts pour les post-its "à corriger"/"à valider" (réflexions stratégiques, section 12) — le premier acté (point d'interrogation), le second encore à choisir.
- Tableau de liège : coder la répartition dynamique des 70% entre assistants par charge de tâches (formule actée, voir Statut actuel) — bloqué tant que la ToDoList des assistants n'existe pas réellement. - Tableau de liège : coder la répartition dynamique des 70% entre assistants par charge de tâches (formule actée, voir Statut actuel) — bloqué tant que la ToDoList des assistants n'existe pas réellement.
- Étendre `ASP_ToDoList`/`todolist.php` pour qu'un assistant puisse être attributaire d'une tâche (discriminant humain/agent à définir) — préalable à la répartition dynamique et aux couleurs de post-it par assistant (`AGN_Couleur`, à ajouter). - Étendre `ASP_ToDoList`/`todolist.php` pour qu'un assistant puisse être attributaire d'une tâche (discriminant humain/agent à définir) — préalable à la répartition dynamique et aux couleurs de post-it par assistant (`AGN_Couleur`, à ajouter).
- Écran "journalier" (trace des réalisations, humain + assistants) — donnée déjà quasi disponible (`TDL_RealDate`/`TDL_RealUser`/`TDL_RealText`), écran de consultation à construire. - Écran "journalier" (trace des réalisations, humain + assistants) — donnée déjà quasi disponible (`TDL_RealDate`/`TDL_RealUser`/`TDL_RealText`), écran de consultation à construire.
@@ -126,3 +126,27 @@ En marge de sa recherche d'un serveur Hostinger plus puissant, Jean-Marc a déco
**Périmètre et statut.** Vision explicitement limitée à ASPIC lui-même à ce stade, pas un projet d'outillage plus large. Jean-Marc reconnaît que cette réflexion peut évoluer avec l'expérience acquise sur le terrain — voir justement le principe ci-dessous, tiré d'un premier retour d'expérience concret le jour même. Aucun développement engagé — pure réflexion à ce stade, capturée ici pour mémoire. **Périmètre et statut.** Vision explicitement limitée à ASPIC lui-même à ce stade, pas un projet d'outillage plus large. Jean-Marc reconnaît que cette réflexion peut évoluer avec l'expérience acquise sur le terrain — voir justement le principe ci-dessous, tiré d'un premier retour d'expérience concret le jour même. Aucun développement engagé — pure réflexion à ce stade, capturée ici pour mémoire.
**Principe de conception qui en découle, tiré de l'expérience réelle du pilotage vocal (2 septembre 2026) :** mieux vaut choisir des noms d'agents qui passent bien nativement à la reconnaissance vocale que d'empiler des tolérances pour rattraper un nom mal choisi — chaque tolérance ajoutée étant à la fois un risque de faux déclenchement (si elle recoupe un mot français courant) et un pari sur un seul accent/une seule prononciation testée, fragile face à la diversité réelle des utilisateurs. Deux agents (Lilou, Karl) ont été retirés sur cette base après des essais répétés peu concluants, plutôt que d'être maintenus à coups de correctifs successifs. Principe à garder en tête si le "bureau à l'ancienne" se concrétise un jour avec davantage d'assistants nommés. **Principe de conception qui en découle, tiré de l'expérience réelle du pilotage vocal (2 septembre 2026) :** mieux vaut choisir des noms d'agents qui passent bien nativement à la reconnaissance vocale que d'empiler des tolérances pour rattraper un nom mal choisi — chaque tolérance ajoutée étant à la fois un risque de faux déclenchement (si elle recoupe un mot français courant) et un pari sur un seul accent/une seule prononciation testée, fragile face à la diversité réelle des utilisateurs. Deux agents (Lilou, Karl) ont été retirés sur cette base après des essais répétés peu concluants, plutôt que d'être maintenus à coups de correctifs successifs. Principe à garder en tête si le "bureau à l'ancienne" se concrétise un jour avec davantage d'assistants nommés.
## 12. Interpréter le pilotage vocal sans s'effondrer à l'échelle — LLM à sortie structurée pour l'action, RAG réservé à la recherche (3 septembre 2026)
**Origine — un enjeu concurrentiel identifié via un tiers.** Jean-Marc a montré les évolutions du pilotage vocal à sa compagne, qui a immédiatement fait le rapprochement avec sa propre expérience professionnelle : elle travaille dans une grosse PME équipée de SAP, confrontée au quotidien à une application qui rame pendant de longues minutes, des arrêts brutaux, et des procédures extrêmement lourdes pour la moindre intervention (créer un utilisateur, corriger un bug de saisie) — délai moyen de 2 à 3 jours via un prestataire externe. Jean-Marc en tire une conviction stratégique : le pilotage vocal, davantage qu'un simple confort, pourrait devenir un vrai argument différenciant face à ce type d'outil lourd, auprès de futurs clients de son agence. **Conséquence directe sur l'exigence de qualité :** cette perspective augmente la pression de fiabilité plutôt que de la relâcher — Jean-Marc redoute explicitement le scénario inverse ("sympa en démo, mais ça ne marche pas en vrai"), d'autant qu'il ne croit pas à la viabilité d'un empilement de règles/rustines au cas par cas une fois le pilotage vocal étendu bien au-delà de la ToDoList (contacts, catalogue, devis et affaires en cours, facturation).
**Deux problèmes distincts, à ne pas confondre sous un seul chantier.** Discussion posée avec Claude pour trancher cette inquiétude :
- **La reconnaissance du mot déclencheur** (l'épisode Lilou/"les loups", voir journal de développement section 27) est un problème de transcription audio, en amont de tout traitement — aucune base vectorielle, aucun RAG, aucun LLM n'y changerait quoi que ce soit, c'est une limite de la reconnaissance vocale elle-même (la même que rencontrent Alexa, Siri ou Google Home). Déjà traité par le choix de noms qui passent bien à l'oral et par `AGN_Variantes` piloté en base — et point rassurant pour la suite : cette surface d'erreur ne grandit pas avec le nombre de modules d'ASPIC, elle reste bornée au nombre d'agents nommés.
- **L'interprétation d'une dictée déjà bien captée** — transformer "il faut ajouter un contact, il s'appelle Pierre Chartier, il est plombier à Quimper..." en une action structurée (quel module, quelle opération, quels paramètres) — est un problème différent, qui se posera réellement une fois la ToDoList suivie par la gestion des contacts, du catalogue, des devis, de la facturation.
**Pourquoi le RAG/pgvector n'est pas l'outil pour ce deuxième problème.** Un RAG/base vectorielle sert à retrouver de l'information pertinente par similarité sémantique dans un corpus large et non structuré — une recherche, pas un déclenchement d'action. C'est l'outil du **répondeur téléphonique intelligent** (section 10 ci-dessus), où le besoin est justement de chercher une réponse dans une base de connaissances ouverte, avec une contrainte de latence quasi temps réel. Le pilotage vocal d'ASPIC, même étendu à plusieurs modules, reste un ensemble d'actions **enumérable et borné** (créer un contact, ajouter une ligne de devis, appliquer une remise...) — la bonne réponse est un LLM à sortie structurée (function calling) : on lui fournit un catalogue d'actions disponibles (nom, paramètres attendus, endpoint concerné), il renvoie l'action reconnue et ses paramètres extraits du texte, sans deviner s'il n'est pas sûr. Chaque nouveau module ajoute des entrées à ce catalogue, pas du code d'interprétation nouveau — c'est ce qui évite l'empilement de règles redouté par Jean-Marc, bien mieux qu'une base vectorielle qui ne répond pas à ce besoin précis. Le RAG garde sa place légitime, mais ailleurs : recherche floue dans un futur catalogue produits ("quelle référence pour un connecteur étanche IP67 20A"), ou dans l'historique des devis/affaires — pas pour interpréter une commande. L'infrastructure (PostgreSQL/pgvector, n8n, LangFlow) tourne déjà sur le VPS de Jean-Marc, prête sans réinstallation le jour où un vrai besoin de ce type apparaîtra (voir section 10).
**Modèle affiné pour le retour visuel à l'utilisateur : deux statuts distincts, pas un seul niveau de confiance.** Proposition initiale de Claude (un seuil de confiance unique) affinée par Jean-Marc, qui avait déjà anticipé le besoin d'une correction ou d'une validation propre à l'action demandée :
- **"À corriger"** — l'IA n'a pas réussi à comprendre proprement la demande (information manquante, incohérente, ou dictée incompréhensible). Un problème d'interprétation, détecté par le LLM lui-même au moment de faire correspondre la dictée à une action du catalogue.
- **"À valider"** — l'IA a bien compris et préparé l'action, mais cette action précise exige toujours un accord humain avant de partir pour de vrai (ex. l'envoi d'un devis à un client), **indépendamment du niveau de confiance de l'interprétation** — une propriété portée par l'action elle-même dans le catalogue, pas un seuil réglé globalement.
Jean-Marc a proposé un signe graphique sur le post-it de l'assistant pour identifier ce qui l'attend (un point d'interrogation, par exemple) — retenu pour "à corriger" (il doit apporter une information ou trancher une ambiguïté). Un second signe, distinct, est envisagé pour "à valider" (un geste plus simple, oui/non, sur quelque chose déjà prêt) — non choisi à ce stade, pour que les deux situations restent reconnaissables d'un coup d'œil sans ouvrir le post-it.
**Rôle de n8n confirmé, dans les mots de Jean-Marc : un "agent de veille" réagissant à des déclencheurs programmés** — pas un outil interrogé à la demande. Concrètement, soit une surveillance périodique des nouvelles clôtures de notation, soit un appel direct dès la clôture d'une dictée pour plus de réactivité — un réglage à choisir plus tard, pas une contrainte d'architecture.
**Décision pour la suite immédiate : ne pas concevoir les règles d'interprétation à l'avance, constituer d'abord un corpus réel.** Cohérent avec la leçon déjà tirée de Lilou/"les loups" — ce qui paraît naturel en le pensant seul se révèle différent une fois dicté réellement et de façon détendue. Jean-Marc en a fourni la preuve lui-même, avant même d'avoir l'outil en main : il a par exemple relevé qu'il commence souvent une instruction par "il faut"/"il faudrait" plutôt que par le prénom d'un agent, et utilise aussi bien "puis" que "ensuite" pour enchaîner deux idées — deux détails qu'aucune conception à la table n'aurait fait ressortir aussi vite. Voir journal de développement, section 27, pour l'outil concret construit ce soir-là (`micro_test.js`/`dictees_test.php`, table `ASP_DicteesTest`) : aucune règle d'interprétation n'y est codée, volontairement — l'objectif de cette phase est uniquement d'accumuler la matière première (dictées réelles, y compris les essais ratés) qui permettra, plus tard, de concevoir le catalogue d'actions et les règles d'extraction avec des exemples réels plutôt qu'hypothétiques.
**Statut : orientation actée, aucun développement de la couche d'interprétation elle-même engagé.** Le développement immédiat porte uniquement sur la constitution du corpus (voir journal, section 27) — le catalogue d'actions, l'appel LLM à sortie structurée et les deux signes graphiques du post-it restent à concevoir, une fois ce corpus jugé suffisant.
+47 -1
View File
@@ -53,8 +53,54 @@ CREATE TABLE `ASP_Agents` (
**État à la fin de cette session.** Fonctionnalité validée de bout en bout sur les quatre agents actifs (ouverture → contenu → clôture, y compris avec variantes de prononciation). Version applicative incrémentée une fois pour cette session, **V1.006**. **État à la fin de cette session.** Fonctionnalité validée de bout en bout sur les quatre agents actifs (ouverture → contenu → clôture, y compris avec variantes de prononciation). Version applicative incrémentée une fois pour cette session, **V1.006**.
**Reste à faire.** **Reste à faire (à la clôture de la session du 1-2 septembre).**
- Étape 2 : règles d'interprétation du contenu dicté (aujourd'hui stocké tel quel, sans traitement), envisagées via n8n, avec des règles modifiables par l'utilisateur. - Étape 2 : règles d'interprétation du contenu dicté (aujourd'hui stocké tel quel, sans traitement), envisagées via n8n, avec des règles modifiables par l'utilisateur.
- Continuer à observer les agents actifs en usage réel ; envisager d'autres retraits, ou l'ajout de nouvelles variantes via `AGN_Variantes`, si de nouvelles confusions apparaissent — sans jamais y ajouter un mot français courant. - Continuer à observer les agents actifs en usage réel ; envisager d'autres retraits, ou l'ajout de nouvelles variantes via `AGN_Variantes`, si de nouvelles confusions apparaissent — sans jamais y ajouter un mot français courant.
- Vérifier concrètement que le `.htaccess` du dossier `/journal` bloque bien l'accès direct (`curl -I` doit répondre `403`, pas `200`) — point resté en suspens depuis le 31 août, sans lien avec le pilotage vocal mais toujours ouvert. - Vérifier concrètement que le `.htaccess` du dossier `/journal` bloque bien l'accès direct (`curl -I` doit répondre `403`, pas `200`) — point resté en suspens depuis le 31 août, sans lien avec le pilotage vocal mais toujours ouvert.
- Documentation utilisateur : pas encore mise à jour pour cette fonctionnalité, encore en phase d'essais techniques (choix des noms d'agents notamment) — à envisager une fois l'usage stabilisé. - Documentation utilisateur : pas encore mise à jour pour cette fonctionnalité, encore en phase d'essais techniques (choix des noms d'agents notamment) — à envisager une fois l'usage stabilisé.
## 3 septembre 2026 (soirée) : vers l'étape 2 — constitution d'une banque de dictées réelles avant toute règle d'interprétation (V1.010)
Reprise de session le même jour (voir aussi section 28, où le micro de l'écran de fond est branché sur la reconnaissance vocale réelle plus tôt dans cette même soirée). Discussion engagée par Jean-Marc après avoir montré les évolutions du pilotage vocal à sa compagne, qui a directement fait le lien avec son expérience de SAP dans une grosse PME (application qui rame, arrêts brutaux, procédures lourdes pour un simple changement — délai moyen de 2-3 jours via un prestataire externe pour créer un utilisateur ou corriger un bug de saisie). Jean-Marc en tire une conviction : l'aspect vocal sera vraisemblablement un atout concurrentiel important vis-à-vis de futurs clients, ce qui **augmente l'exigence de fiabilité** plutôt que de la relâcher — inquiétude explicite sur la capacité du projet à tenir cette fiabilité une fois le pilotage vocal étendu au-delà de la ToDoList (contacts, catalogue, devis et affaires en cours, facturation...), sans tomber dans un empilement de règles/rustines au cas par cas comme cela avait déjà été nécessaire pour Lilou/"les loups" (voir plus haut).
**Distinction actée avec Claude, développée en détail dans les réflexions stratégiques (section 12) :** deux problèmes différents, à ne pas traiter par le même mécanisme. D'un côté, la confusion de reconnaissance en amont (mot déclencheur mal transcrit) — un problème de reconnaissance audio, déjà traité par `AGN_Variantes` et le choix de noms d'agents qui passent bien à l'oral, dont la surface d'erreur ne grandit pas avec le nombre de modules d'ASPIC. De l'autre, l'interprétation d'une dictée déjà bien captée — transformer "il faut ajouter un contact, il s'appelle Pierre Chartier, il est plombier à Quimper..." en une action structurée (quel module, quelle opération, quels paramètres). Conclusion : ni RAG ni base vectorielle pour ce deuxième problème (outil de recherche floue dans un corpus, pas de déclenchement d'action) — un LLM à sortie structurée (function calling) contre un catalogue d'actions par module est l'outil adapté, sans avoir besoin de pgvector avant qu'un vrai besoin de recherche floue (catalogue produits, historique de devis) n'apparaisse. Modèle affiné avec Jean-Marc pour le retour visuel sur le post-it : deux statuts distincts plutôt qu'un seul niveau de confiance — "à corriger" (information manquante/incohérente, l'IA n'a pas su comprendre) versus "à valider" (l'IA a bien compris et préparé l'action, mais cette action précise exige toujours un accord humain avant exécution réelle, par nature — ex. l'envoi d'un devis à un client — indépendamment du niveau de confiance de l'interprétation). Deux signes graphiques distincts envisagés sur le post-it (un point d'interrogation pour "à corriger", proposé par Jean-Marc ; un symbole différent, à définir, pour "à valider") plutôt qu'un seul, pour que Jean-Marc sache d'un coup d'œil ce qu'on attend de lui sans ouvrir le post-it.
**Décision pour cette session : ne pas anticiper les règles, constituer d'abord un corpus réel.** Cohérent avec la leçon déjà tirée de Lilou/"les loups" — ce qui semble naturel en le pensant seul (ex. faire commencer chaque instruction par le prénom d'un agent) se révèle différent une fois dicté réellement et de façon détendue. Jean-Marc a d'ailleurs déjà relevé, avant même d'avoir l'outil, deux exemples concrets : il commence souvent une instruction par "il faut"/"il faudrait" plutôt que par le prénom d'un agent, et utilise aussi bien "puis" que "ensuite" pour marquer un enchaînement — points à garder tels quels dans le corpus plutôt qu'à corriger à la main, l'objectif de cette phase étant justement de laisser le vrai usage remonter ces variations plutôt que de les deviner.
**Outil construit : `micro_test.js` + `dictees_test.php` + table `ASP_DicteesTest`.** Outil de mise au point interne, explicitement pas destiné aux futurs utilisateurs (précision de Jean-Marc). Table créée par Jean-Marc lui-même (voir convention actée en tête de journal) :
```sql
CREATE TABLE `ASP_DicteesTest` (
`DCT_Incr` int NOT NULL,
`DCT_Theme` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'Gestion des Contacts',
`DCT_Texte` text NOT NULL,
`DCT_Date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`DCT_Utilisateur` varchar(3) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```
Choix de conception actés avec Jean-Marc, plusieurs à contre-courant du réflexe initial de Claude :
- **Aucun mot déclencheur.** Le clic sur le micro fait déjà office de signal explicite de début — contrairement à `micro.js` en écoute ambiante continue, qui doit filtrer une conversation de fond d'une vraie commande, ce problème ne se pose pas ici : tout ce qui est dit après le clic est un essai volontaire. Ça répond directement à la remarque de Jean-Marc sur le prénom d'agent en tête de phrase — cette contrainte est un artefact du filtrage en écoute ambiante, pas une exigence de l'interprétation elle-même.
- **Pas de segmentation "à la main".** Le "silence de x secondes" évoqué par Jean-Marc n'est pas un réglage exposé par l'application : c'est le moteur de reconnaissance du navigateur qui décide, en interne, quand un énoncé est terminé (chaque événement `result` avec `isFinal=true` correspond déjà à "ce qui a été dit avant une pause") — même mécanisme que celui déjà éprouvé en production dans `micro.js`, repris tel quel plutôt que réinventé.
- **Restitution au fur et à mesure.** Contrairement à `micro.js` (`interimResults=false`), ce script active `interimResults=true` : le texte apparaît progressivement dans une fenêtre dédiée (fond noir, texte blanc, `overflow-y:auto`) pendant la dictée, la ligne se fige (et s'enregistre) dès que le silence est détecté, puis une nouvelle ligne démarre.
- **Aucune suppression possible, y compris pour un essai raté.** Décision explicite de Jean-Marc, à contre-courant d'une première proposition de Claude (bouton de suppression pour nettoyer un essai avorté) : *"les dictées ratées feront partie de la vie des futurs utilisateurs"* — la banque doit refléter la réalité, pas une version nettoyée qui fausserait la conception des règles de correction à venir.
- **Fenêtre vidée à chaque fermeture du micro**, rouverte vide au prochain clic — purement un retour visuel immédiat, la table continue évidemment d'accumuler tous les essais d'une session à l'autre.
- **Thème fixé** à la valeur par défaut de la colonne (`'Gestion des Contacts'`), non transmis par le script — évite de dupliquer une valeur qui doit rester pilotée par la table.
Branché, comme détaillé en section 28, sur le micro de l'écran de fond (`#micro-desk`) à la place de `micro.js`, le temps de cette phase — décision explicite de Jean-Marc de réutiliser ce micro plutôt que de construire un écran séparé, pour permettre des essais rapides et répétés en se décontractant sur le sujet. `micro.js` n'est pas modifié pour ça (seul le repli d'id ajouté plus tôt dans la soirée y reste, voir section 28) et continue de tourner normalement sur `liste_contacts.html`.
Endpoint `dictees_test.php` : reçoit `{"texte": "..."}`, enregistre tel quel dans `ASP_DicteesTest` avec l'utilisateur de la session — même squelette que `agent_notes.php` (session requise, POST uniquement), sans logique de lot ni de type de ligne (chaque énoncé est indépendant ici, pas de notion d'ouverture/clôture).
Testé par Claude en navigateur headless avec un faux moteur de reconnaissance piloté à la main (restitution en direct, figeage de ligne au bon moment, deuxième essai qui ne recouvre pas le premier, fenêtre bien vidée à la fermeture) avant livraison. **Premier essai réel le soir même, concluant** : micro laissé ouvert par Jean-Marc pour une session de dictées, une phrase dite par sa compagne dans la pièce correctement captée (voir section 28) — confirme que l'écoute continue et le redémarrage automatique tiennent la route en usage prolongé, pas seulement en essai bref.
### Fichiers touchés (3 septembre, soirée)
`micro_test.js` (nouveau), `dictees_test.php` (nouveau), `ecran_fond.html` (charge `micro_test.js` à la place de `micro.js`, voir section 28), `version.php` (`V1.010`). Table `ASP_DicteesTest` créée par Jean-Marc directement en base.
**Reste à faire.**
- Laisser Jean-Marc constituer un vrai volume de dictées sur le thème "Gestion des Contacts" avant toute analyse — aucune règle d'interprétation à écrire tant que le corpus n'est pas jugé suffisant.
- Une fois ce corpus analysé : concevoir le catalogue d'actions pour le module Contacts (actions, paramètres attendus, lesquelles exigent une validation par nature) et le mécanisme d'appel LLM à sortie structurée correspondant (voir réflexions stratégiques, section 12).
- Reconnecter `micro.js` (vrai pilotage) sur le micro de l'écran de fond une fois cette phase de mise au point terminée — une seule ligne à changer dans `ecran_fond.html` (voir section 28).
- Étendre `MARQUEUR_FIN_LIGNE` dans `micro.js` pour accepter "puis" en plus de "ensuite" (retour d'usage de Jean-Marc, 3 septembre) — sans urgence, à faire quand on retouche `micro.js`.
- Concevoir les deux signes graphiques distincts pour les post-its "à corriger" / "à valider" évoqués plus haut — non codé, ni même définitivement choisi pour "à valider" (le point d'interrogation de "à corriger" est acté).
- Étendre l'outil de banque de dictées à d'autres thèmes (catalogue, devis...) le jour où ces modules existeront — `DCT_Theme` est déjà prévu pour ça, seule la valeur par défaut en base et le script de capture sont à dupliquer/adapter.
+15 -1
View File
@@ -159,6 +159,20 @@ Après déploiement et test réel par Jean-Marc (*"tatillon, je sais"*), écart
- Déploiement du correctif `.htaccess` de cache (voir ci-dessus) — à confirmer par Jean-Marc. - Déploiement du correctif `.htaccess` de cache (voir ci-dessus) — à confirmer par Jean-Marc.
- Documentation utilisateur : certains passages décrivant l'écran "Liste des contacts" comme écran d'accueil et le menu hamburger sont devenus obsolètes suite aux changements du 3 septembre — corrections ponctuelles apportées le jour même (voir document séparé), une repasse plus complète (écran de fond, panneau détail, ToDoList, pilotage vocal — aucun de ces écrans n'est encore documenté pour l'utilisateur) reste à faire un jour. - Documentation utilisateur : certains passages décrivant l'écran "Liste des contacts" comme écran d'accueil et le menu hamburger sont devenus obsolètes suite aux changements du 3 septembre — corrections ponctuelles apportées le jour même (voir document séparé), une repasse plus complète (écran de fond, panneau détail, ToDoList, pilotage vocal — aucun de ces écrans n'est encore documenté pour l'utilisateur) reste à faire un jour.
## 3 septembre 2026 (suite de soirée) : micro du bureau branché sur la reconnaissance vocale réelle, puis détourné temporairement (V1.010)
Reprise de session le même jour, après la clôture ci-dessus. Premier point traité, en réponse à une question de Jean-Marc constatant l'écart de comportement entre les deux micros de l'application (celui de la liste des contacts déclenchait bien la demande d'autorisation Chrome et l'icône d'enregistrement du navigateur ; celui de l'écran de fond non) : confirmation que le micro du bureau (`#micro-desk`) n'avait effectivement jamais été branché sur `micro.js`, comme déjà noté dans "Reste à faire" ci-dessus — seul un toggle visuel local (`appliquerEtatMicroDesk()`, voir V1.007) y bascule l'icône, sans jamais appeler l'API de reconnaissance.
**Branchement réel.** `micro.js` cherchait jusqu'ici le bouton par un seul identifiant fixe (`#bouton-micro`, structure du bandeau). Plutôt que de recalquer la structure DOM de l'écran de fond sur celle du bandeau (ce qui aurait cassé la séparation volontaire zone-cliquable/icône déjà en place, voir V1.007 sur la raison de cette séparation), `micro.js` a été modifié pour chercher `#bouton-micro` puis, à défaut, `#micro-desk` — un seul fichier de comportement continue de piloter les deux écrans, chacun gardant sa structure visuelle propre. Côté `ecran_fond.html` : le toggle JS local (visuel seul) est retiré, remplacé par une règle CSS qui réagit à la classe `ecoute` que `micro.js` pose désormais sur `#micro-desk` — combinateur de fratrie (`#micro-desk.ecoute ~ #micro-icone #glyphe-repos/#glyphe-ecoute`) puisque `#micro-icone` n'est pas un descendant du bouton (voir V1.007). Vérifié par un test en navigateur headless (Playwright) : clic déclenchant bien un vrai appel à l'API de reconnaissance vocale, bascule visuelle des deux glyphes correctement pilotée par la classe.
**Détournement temporaire, le soir même.** Discussion engagée par Jean-Marc sur la fiabilité à long terme du pilotage vocal (voir réflexions stratégiques, section 12, pour le raisonnement complet) a abouti à la décision de constituer d'abord une banque de dictées réelles avant d'écrire la moindre règle d'interprétation — voir section 27 du journal pour le détail technique de cet outil (`micro_test.js`, `dictees_test.php`, table `ASP_DicteesTest`). Ergonomie proposée par Jean-Marc : réutiliser directement le micro de l'écran général plutôt qu'un écran séparé. Concrètement, `ecran_fond.html` charge désormais `micro_test.js` **à la place de** `micro.js` — `micro.js` lui-même n'est pas modifié pour ça, et reste utilisé tel quel sur `liste_contacts.html`. Pour reconnecter le vrai pilotage sur ce micro une fois la phase de mise au point terminée : remettre `<script src="micro.js">` à la place de `<script src="micro_test.js">` dans `ecran_fond.html`, rien d'autre à défaire.
**Premier essai réel concluant.** Testé en conditions réelles par Jean-Marc le soir même — micro resté ouvert, dictées répétées sans reprise en main, et une phrase dite par une tierce personne dans la pièce ("bonne nuit") correctement captée, confirmant que l'écoute continue et le redémarrage automatique du moteur fonctionnent bien en usage prolongé, pas seulement en essai bref. Point d'ergonomie mineur relevé par Jean-Marc : la fenêtre de restitution des dictées masque visuellement l'icône du micro pendant l'écoute — sans gravité, la zone cliquable réelle (le "pied" du micro, hors de la fenêtre) reste accessible pour refermer le micro. Jean-Marc a explicitement demandé de ne rien changer sur ce point.
### Fichiers touchés (3 septembre, soirée)
`micro.js` (repli d'id `#micro-desk`), `ecran_fond.html` (CSS de bascule, retrait du toggle JS local, chargement de `micro_test.js`), `version.php` (`V1.010`, incrémentée une seule fois pour l'ensemble de cette session du 3 septembre y compris sa suite de soirée). Voir section 27 pour `micro_test.js` et `dictees_test.php` (nouveaux).
## Statut et suite ## Statut et suite
**Trois livraisons réelles en trois jours consécutifs (2-3 septembre) :** l'essai fonctionnel initial de l'écran de fond (classeur Contacts, chevalet, micro test d'affichage, version — V1.007), la pastille de comptage et le premier affichage réel du tableau de post-its (V1.008), puis cette session d'homogénéisation des deux écrans et d'adaptation à la nouvelle photo sans chevalet (V1.009). Plusieurs allers-retours de correction fine à chaque étape, à partir des retours directs de Jean-Marc sur son propre écran ou sur des rendus envoyés par Claude — la mesure de position sur une photo réelle (plutôt que sur un dessin vectoriel) continue de demander une vérification fine à chaque retour, y compris pour des détails de mise en page fine (calage horizontal du bloc identité). **Trois livraisons réelles en trois jours consécutifs (2-3 septembre) :** l'essai fonctionnel initial de l'écran de fond (classeur Contacts, chevalet, micro test d'affichage, version — V1.007), la pastille de comptage et le premier affichage réel du tableau de post-its (V1.008), puis cette session d'homogénéisation des deux écrans et d'adaptation à la nouvelle photo sans chevalet (V1.009). Plusieurs allers-retours de correction fine à chaque étape, à partir des retours directs de Jean-Marc sur son propre écran ou sur des rendus envoyés par Claude — la mesure de position sur une photo réelle (plutôt que sur un dessin vectoriel) continue de demander une vérification fine à chaque retour, y compris pour des détails de mise en page fine (calage horizontal du bloc identité).
@@ -169,7 +183,7 @@ Séance close sur un bilan explicitement positif de Jean-Marc — *"content car.
- Confirmer le déploiement du correctif `.htaccess` de cache. - Confirmer le déploiement du correctif `.htaccess` de cache.
- Reconfirmer l'état de la "tranche du bureau" après le recadrage du 3 septembre (voir ci-dessus). - Reconfirmer l'état de la "tranche du bureau" après le recadrage du 3 septembre (voir ci-dessus).
- Décider si les autres objets photographiés sur le bureau (carnet, téléphone) doivent devenir cliquables/fonctionnels, ou rester un habillage visuel statique. - Décider si les autres objets photographiés sur le bureau (carnet, téléphone) doivent devenir cliquables/fonctionnels, ou rester un habillage visuel statique.
- Brancher réellement le micro du bureau (et celui de la barre de statut) sur la reconnaissance vocale de `micro.js` (aujourd'hui : bascule d'affichage seule, sans effet sur l'écoute réelle). - ~~Brancher réellement le micro du bureau sur la reconnaissance vocale de `micro.js`~~ — fait le 3 septembre (soirée), voir plus haut. Détourné le même soir vers `micro_test.js` (outil de mise au point, voir section 27) : à reconnecter à `micro.js` une fois cette phase terminée.
- Trancher, un jour, le sort de la piste "maquette liège + post-its par agent" (Claude Design) : mise de côté pour les essais en cours, mais pas explicitement enterrée pour une version plus aboutie. - Trancher, un jour, le sort de la piste "maquette liège + post-its par agent" (Claude Design) : mise de côté pour les essais en cours, mais pas explicitement enterrée pour une version plus aboutie.
- Artifact de travail de la maquette liège (dernière version, non utilisée dans l'essai actuel) : https://claude.ai/code/artifact/a647369f-d320-4b21-9f8c-11b20f2ad353 — lien privé à Jean-Marc, à ne pas considérer comme un livrable définitif. - Artifact de travail de la maquette liège (dernière version, non utilisée dans l'essai actuel) : https://claude.ai/code/artifact/a647369f-d320-4b21-9f8c-11b20f2ad353 — lien privé à Jean-Marc, à ne pas considérer comme un livrable définitif.
- Repasse complète de la documentation utilisateur pour couvrir l'écran de fond, le panneau détail, la ToDoList et le pilotage vocal. - Repasse complète de la documentation utilisateur pour couvrir l'écran de fond, le panneau détail, la ToDoList et le pilotage vocal.
+13 -2
View File
@@ -21,6 +21,14 @@
* retour visuel — micro.js s'en sert si elle existe, sinon se contente * retour visuel — micro.js s'en sert si elle existe, sinon se contente
* d'un console.log (utile en test avant d'avoir une page complète). * d'un console.log (utile en test avant d'avoir une page complète).
* *
* Exception à cette structure (3 septembre 2026) : l'écran de fond
* (ecran_fond.html) porte le même comportement sur un bouton #micro-desk
* plutôt que #bouton-micro — sa zone cliquable réelle est volontairement
* plus grande que l'icône affichée par-dessus, calée sur toute la
* silhouette du micro photographié (voir le commentaire dédié dans
* ecran_fond.html), donc pas la même structure DOM que les bandeaux. Voir
* plus bas la recherche du bouton avec repli sur cet id.
*
* Étape 1 (1er septembre 2026) : reconnaissance vocale réelle branchée sur * Étape 1 (1er septembre 2026) : reconnaissance vocale réelle branchée sur
* le bouton, texte transcrit simplement affiché en retour pour valider le * le bouton, texte transcrit simplement affiché en retour pour valider le
* circuit micro -> texte. Aucune commande interprétée ni action * circuit micro -> texte. Aucune commande interprétée ni action
@@ -132,8 +140,11 @@
(function(){ (function(){
"use strict"; "use strict";
const bouton = document.getElementById("bouton-micro"); // #bouton-micro sur les écrans à bandeau, #micro-desk en repli sur
if(!bouton) return; // écran sans bouton micro dans son bandeau // l'écran de fond (voir commentaire d'en-tête) — un seul des deux existe
// sur une page donnée.
const bouton = document.getElementById("bouton-micro") || document.getElementById("micro-desk");
if(!bouton) return; // écran sans bouton micro
function notifier(message){ function notifier(message){
if(typeof window.afficherToast === "function"){ if(typeof window.afficherToast === "function"){
+295
View File
@@ -0,0 +1,295 @@
/**
* ASPIC — micro_test.js
*
* Outil de mise au point interne (3 septembre 2026, demande explicite de
* Jean-Marc) : PAS un futur module utilisateur. Sert uniquement à
* constituer une banque de dictées réelles (table ASP_DicteesTest, thème
* "Gestion des Contacts") pour préparer, plus tard, la conception des
* règles d'interprétation du pilotage vocal — voir réflexions
* stratégiques et le commentaire d'en-tête de dictees_test.php.
*
* Chargé À LA PLACE de micro.js sur ecran_fond.html, le temps de cette
* phase de mise au point (voir le commentaire dédié dans ecran_fond.html,
* autour de #micro-desk) — micro.js (le vrai pilotage : agents nommés,
* mot déclencheur, mode notation) reste totalement inchangé et continue de
* tourner normalement sur liste_contacts.html. Pour reconnecter le vrai
* pilotage sur le micro de l'écran de fond une fois cette phase terminée :
* remettre <script src="micro.js"> à la place de
* <script src="micro_test.js"> en bas d'ecran_fond.html, rien d'autre à
* défaire — ce fichier-ci n'est jamais modifié pour ça.
*
* Différences volontaires avec micro.js, toutes actées avec Jean-Marc :
* - Aucun mot déclencheur : le clic sur le micro fait déjà office de
* signal explicite de début (contrairement à l'écoute ambiante continue
* de micro.js, qui doit filtrer une conversation de fond d'une vraie
* commande — ce problème ne se pose pas ici, on sait que tout ce qui est
* dit après le clic est un essai volontaire).
* - Aucune notion d'agent, de mode notation, de phrase de clôture : chaque
* énoncé séparé par un silence est une ligne indépendante, enregistrée
* immédiatement dès qu'il est reconnu — la segmentation elle-même n'est
* pas gérée à la main ici, c'est le moteur de reconnaissance du
* navigateur qui la fait (un événement "result" avec isFinal=true
* correspond déjà à "ce qui a été dit avant une pause" ; on ne choisit
* pas la durée exacte de cette pause, elle est interne au navigateur —
* même mécanisme que celui déjà éprouvé en production dans micro.js).
* - Restitution au fur et à mesure dans une fenêtre dédiée (fond noir,
* texte blanc, défilement) : la ligne en cours s'affiche pendant la
* dictée (interimResults activé, contrairement à micro.js) puis se fige
* et se sauvegarde dès que le silence est détecté par le navigateur ;
* une nouvelle ligne en cours démarre aussitôt après.
* - Aucune suppression possible depuis l'écran, y compris pour un essai
* raté (décision explicite de Jean-Marc, 3 septembre 2026) : un post-it
* raté fera aussi partie de la vraie vie des futurs utilisateurs, la
* banque de tests doit refléter ça dès maintenant plutôt que ne garder
* que les essais réussis.
* - Fenêtre ouverte à chaque ouverture du micro, vidée à chaque fermeture
* (elle ne conserve donc rien visuellement d'une session à l'autre — la
* table ASP_DicteesTest, elle, continue évidemment d'accumuler tous les
* essais, la fenêtre n'est qu'un retour visuel immédiat).
*
* Reprend, pour la robustesse, le même squelette que micro.js pour le
* redémarrage silencieux du moteur (qui peut s'arrêter tout seul sans que
* l'utilisateur l'ait demandé) et la coupure automatique après inactivité
* prolongée (même prudence de confidentialité que celle qui avait conduit
* à cet ajout dans micro.js — voir son commentaire d'en-tête) — sans
* dépendre de micro.js lui-même : ce fichier est volontairement autonome et
* plus simple, pour ne jamais risquer de contaminer le vrai pilotage avec
* de la logique de test jetable.
*/
(function(){
"use strict";
const bouton = document.getElementById("micro-desk");
if(!bouton) return; // ce script ne concerne que l'écran de fond
const ReconnaissanceVocale = window.SpeechRecognition || window.webkitSpeechRecognition;
if(!ReconnaissanceVocale){
bouton.title = "Reconnaissance vocale non disponible sur ce navigateur";
return;
}
const reconnaissance = new ReconnaissanceVocale();
reconnaissance.lang = "fr-FR";
reconnaissance.continuous = true;
reconnaissance.interimResults = true; // restitution au fur et à mesure, demandée par Jean-Marc
reconnaissance.maxAlternatives = 1;
let ecouteVoulue = false;
let erreurBloquante = false;
// Coupure automatique après inactivité — même prudence que micro.js
// (voir son commentaire d'en-tête sur l'incident de confidentialité qui
// avait motivé cet ajout) : un outil de test resté ouvert par oubli ne
// doit pas non plus continuer à envoyer l'audio ambiant indéfiniment.
const DUREE_INACTIVITE_MS = 10 * 60 * 1000; // 10 minutes
let minuteurInactivite = null;
function reinitialiserMinuteurInactivite(){
if(minuteurInactivite) clearTimeout(minuteurInactivite);
minuteurInactivite = setTimeout(couperPourInactivite, DUREE_INACTIVITE_MS);
}
function arreterMinuteurInactivite(){
if(minuteurInactivite){
clearTimeout(minuteurInactivite);
minuteurInactivite = null;
}
}
function couperPourInactivite(){
minuteurInactivite = null;
if(!ecouteVoulue) return; // déjà refermé entre-temps
ecouteVoulue = false;
reconnaissance.stop();
}
// -------- Fenêtre de restitution --------
// Construite ici plutôt que dans ecran_fond.html, pour que ce fichier
// reste entièrement autonome — le retirer (remettre micro.js) ne laisse
// aucune trace HTML/CSS à nettoyer côté page hôte.
let fenetre = null;
let zoneLignes = null;
let ligneEnCours = null;
function construireFenetre(){
if(fenetre) return;
const style = document.createElement("style");
style.textContent =
"#fenetre-dictees-test{position:fixed;top:8%;left:50%;" +
"transform:translateX(-50%);width:min(560px,80vw);height:min(420px,70vh);" +
"background:#000;border:1px solid #333;border-radius:6px;" +
"box-shadow:0 10px 40px rgba(0,0,0,.6);z-index:950;display:none;" +
"flex-direction:column;overflow:hidden;" +
"font-family:'Courier New',Consolas,monospace;}" +
"#fenetre-dictees-test.visible{display:flex;}" +
"#fenetre-dictees-test .entete{color:#888;font-size:11px;" +
"padding:6px 10px;border-bottom:1px solid #222;flex:none;}" +
"#fenetre-dictees-test .lignes{flex:1;overflow-y:auto;padding:8px 10px;" +
"color:#fff;font-size:14px;line-height:1.6;white-space:pre-wrap;}" +
"#fenetre-dictees-test .lignes .en-cours{color:#8a8a8a;font-style:italic;}" +
"#fenetre-dictees-test .lignes .erreur{color:#e14a5c;}";
document.head.appendChild(style);
fenetre = document.createElement("div");
fenetre.id = "fenetre-dictees-test";
fenetre.innerHTML =
'<div class="entete">Banque de dictées — Gestion des Contacts ' +
'(outil de mise au point, non destiné aux utilisateurs finaux)</div>' +
'<div class="lignes"></div>';
document.body.appendChild(fenetre);
zoneLignes = fenetre.querySelector(".lignes");
}
function ouvrirFenetre(){
construireFenetre();
zoneLignes.innerHTML = "";
ligneEnCours = null;
fenetre.classList.add("visible");
}
function fermerFenetre(){
if(fenetre) fenetre.classList.remove("visible");
if(zoneLignes) zoneLignes.innerHTML = "";
ligneEnCours = null;
}
function afficherEnCours(texte){
if(!zoneLignes) return;
if(!ligneEnCours){
ligneEnCours = document.createElement("div");
ligneEnCours.className = "en-cours";
zoneLignes.appendChild(ligneEnCours);
}
ligneEnCours.textContent = texte;
zoneLignes.scrollTop = zoneLignes.scrollHeight;
}
function figerLigne(texte){
if(!zoneLignes) return;
if(!ligneEnCours){
ligneEnCours = document.createElement("div");
zoneLignes.appendChild(ligneEnCours);
}
ligneEnCours.className = "";
ligneEnCours.textContent = texte;
ligneEnCours = null; // la prochaine ligne (en cours ou figée) en recrée une
zoneLignes.scrollTop = zoneLignes.scrollHeight;
}
function afficherErreur(texte){
if(!zoneLignes) return;
const div = document.createElement("div");
div.className = "erreur";
div.textContent = texte;
zoneLignes.appendChild(div);
zoneLignes.scrollTop = zoneLignes.scrollHeight;
}
// -------- Enregistrement --------
// Aucune interprétation, aucun filtrage : tout ce qui est capté part vers
// dictees_test.php, essai raté compris (décision de Jean-Marc, voir
// commentaire d'en-tête).
function enregistrerDictee(texte){
fetch("dictees_test.php", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({texte: texte})
}).then(function(reponse){
if(!reponse.ok) throw new Error("HTTP " + reponse.status);
}).catch(function(){
afficherErreur("(non enregistré — erreur de connexion à dictees_test.php)");
});
}
function passerEnEcoute(){
bouton.classList.add("ecoute");
bouton.title = "Le micro est ouvert (banque de dictées contacts — outil de mise au point)";
ouvrirFenetre();
reinitialiserMinuteurInactivite();
}
function revenirAuRepos(){
ecouteVoulue = false;
arreterMinuteurInactivite();
bouton.classList.remove("ecoute");
bouton.title = "Le micro est inactif";
fermerFenetre();
}
bouton.addEventListener("click", function(){
if(ecouteVoulue){
// Fermeture demandée : le retour au repos (et la fermeture de la
// fenêtre) se fait via l'événement "end" qui va suivre.
ecouteVoulue = false;
reconnaissance.stop();
return;
}
ecouteVoulue = true;
erreurBloquante = false;
try{
reconnaissance.start();
}catch(erreur){
ecouteVoulue = false;
afficherErreur("Impossible de démarrer le micro (" + erreur.name + ").");
}
});
reconnaissance.addEventListener("start", passerEnEcoute);
reconnaissance.addEventListener("end", function(){
if(ecouteVoulue && !erreurBloquante){
// Le moteur s'est arrêté tout seul (silence prolongé, limite interne
// du navigateur...) alors que l'écoute reste voulue : relance
// invisible pour l'utilisateur, même principe que micro.js.
try{
reconnaissance.start();
}catch(erreur){
revenirAuRepos();
afficherErreur("Le micro s'est arrêté et n'a pas pu redémarrer automatiquement.");
}
return;
}
revenirAuRepos();
});
reconnaissance.addEventListener("result", function(evenement){
const dernier = evenement.results[evenement.results.length - 1];
const texte = dernier[0].transcript.trim();
if(!texte) return;
if(dernier.isFinal){
// Silence détecté par le moteur : la ligne se fige et s'enregistre
// immédiatement, essai raté ou non — aucun jugement porté ici sur la
// qualité du texte reconnu.
figerLigne(texte);
enregistrerDictee(texte);
reinitialiserMinuteurInactivite();
} else {
// Restitution au fur et à mesure, avant que le silence ne fige la
// ligne — demande explicite de Jean-Marc.
afficherEnCours(texte);
}
});
reconnaissance.addEventListener("error", function(evenement){
const messagesBloquants = {
"not-allowed": "Micro refusé — vérifie l'autorisation dans le navigateur.",
"service-not-allowed": "Micro refusé — vérifie l'autorisation dans le navigateur.",
"audio-capture": "Aucun micro détecté."
};
if(messagesBloquants[evenement.error]){
erreurBloquante = true;
afficherErreur(messagesBloquants[evenement.error]);
return;
}
// "no-speech" est un bruit normal entre deux essais (silence pendant
// qu'on réfléchit à la phrase suivante) : pas affiché, pour ne pas
// polluer la fenêtre de tests — l'événement "end" qui suit relance de
// toute façon l'écoute tant qu'elle reste voulue.
if(evenement.error === "network"){
afficherErreur("(problème réseau, nouvelle tentative...)");
}
});
})();
+1 -1
View File
@@ -24,7 +24,7 @@
* d'identification, avant toute connexion. * d'identification, avant toute connexion.
*/ */
const ASPIC_VERSION = 'V1.009'; const ASPIC_VERSION = 'V1.010';
if (basename($_SERVER['SCRIPT_NAME']) === 'version.php') { if (basename($_SERVER['SCRIPT_NAME']) === 'version.php') {
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');