From c0308a95c004e65b0b5f3ba661068eb248a90994 Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Thu, 13 Aug 2026 13:39:34 +0200 Subject: [PATCH] =?UTF-8?q?Miroir=20vocal=20livr=C3=A9=20=E2=80=94=20plan,?= =?UTF-8?q?=20STATUS=20et=20kanban?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La carte quitte Planifié, qui retombe à 23. Compteurs mesurés : Fait récemment 56. Kanban republié sur l'artifact. Co-Authored-By: Claude Opus 5 --- kanban.html | 26 ++++++++++++-------------- v1-plan.md | 10 ++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/kanban.html b/kanban.html index e53da4f..3e7042f 100644 --- a/kanban.html +++ b/kanban.html @@ -458,9 +458,9 @@
1Migration v3
1Bugs ouverts
6À tester
-
24Planifié
+
23Planifié
8Bascule prod
-
55Fait récemment
+
56Fait récemment
@@ -584,7 +584,7 @@
-

Planifié

24
+

Planifié

23
@@ -656,16 +656,6 @@ v1-plan.md — lot J · cgu-myinfomate.md §8 · mention-information-visiteurs.md -
-
visitapplunettesNouveau 12/08
-

Miroir de la conversation vocale dans le chat

-

Tranché le 12/08 : ouvrir l'assistant pendant que les lunettes tournent doit montrer la même conversation, transcrite au fil de l'eau. Une conversation, deux surfaces.

-

⚠️ Le coût n'est pas l'affichage, c'est l'unification des historiques. MyInfoMateLlmClient construit son propre AssistantService (maxHistory: 6), distinct de celui du chat écrit : poser une question aux lunettes puis ouvrir le chat donne aujourd'hui un interlocuteur qui ne sait rien de ce qu'on vient de demander. La transcription, elle, est déjà là — VoiceOrchestrator expose lastTranscription et lastTtsText, personne ne les affiche.

-

Bénéfice de bord : VisitorQuestion.ConversationId est un GUID de session, « seul lien entre deux tours ». Deux historiques = deux conversations en base pour un visiteur qui a juste changé de surface. Unifier répare aussi les agrégats du Guide IA, donc ce que le job de thèmes du lot J regroupera. ⛔ Écarté : l'affichage passif dans VoiceModeSheet (2-3 h) — ça montrait que ça marche sans réparer la coupure. ~1 à 2 jours.

-

⚠️ Ne rien redessiner, l'UI existe. GlassesStatusWidget est monté en haut à droite de l'accueil (home_3.0.dart:465) : état par couleur, pastille de mode actif, tap → VoiceModeSheet (connexion, choix de mode, désactivation). GlassesDebugPanel existe et se garde — c'est l'outil de test. Seul écart avec « tout le temps présente », et il est volontaire : l'icône se cache si applicationInstanceDTO?.isAssistant != true (GlassesStatusWidget.dart:32) — invisible chez MDLF et le Fort, visible sur l'instance MyInfoMate. À savoir avant de tester chez un client et de croire à un bug.

- v1-plan.md lot F — miroir vocal -
-
manager-appJamais ouvert

Écrans du lot design — vérification à l'œil

@@ -864,9 +854,17 @@

Fait récemment

-

Cinquante-cinq chantiers clos entre le 5 et le 13 août 2026.

+

Cinquante-six chantiers clos entre le 5 et le 13 août 2026.

+
+ Une conversation, plusieurs surfaces — miroir vocal et conversationId + Le chat écrit, le vocal et le proactif partagent désormais une seule conversation, portée par VisitAppContext.assistant. Les trois AssistantService séparés ont disparu ; le maxHistory: 6 du vocal s'aligne sur 10, deux surfaces qui partagent une conversation ne pouvant pas la tronquer différemment selon le point d'entrée. La concision vocale vient d'isVoice, qui change le prompt côté serveur. + ⚠️ Le vrai obstacle n'était pas l'affichage mais la forme du chat. AssistantChatSheet gardait ses messages en List<Widget> — des bulles déjà construites. On ne rejoue pas une conversation à partir de widgets, et un tour vocal survenu pendant que la feuille était fermée n'aurait jamais pu y entrer. Le service porte maintenant les tours en données et notifie ; la feuille rend depuis eux et se met à jour en direct. + ⚠️ Deux listes, délibérément : celle envoyée au modèle et celle affichée ne coïncident pas. Un message d'erreur se montre sans repartir au guide — il n'a pas à s'excuser d'une panne au tour suivant ; le prompt d'un déclenchement proactif part au guide sans jamais s'afficher, seule sa réponse apparaît, marquée « À voix haute ». Sans ce marquage, le visiteur trouverait dans son chat des messages qu'il n'a jamais tapés. + conversationId est enfin envoyé — et le champ manquait dans le client généré, ce qui explique que personne ne l'envoyait. Ajouté à la main. Il est renouvelé quand la conversation est vidée, sinon la visite entière d'un visiteur n'en formerait qu'une. 2 tests serveur fixent le lien entre deux tours et le repli Guid.NewGuid(), que rien ne couvrait. dotnet test 215, APK dev ✅, flutter build web ✅. +
+
Les prompts du mode proactif ne polluent plus « Ce que demandent vos visiteurs » Le dernier bloquant du proactif. RecordVisitorQuestion écrivait Question = request.Message : chaque passage devant une œuvre aurait ajouté une fausse question de visiteur — une consigne que le système s'écrit à lui-même — dans l'écran fait pour montrer ce que les humains demandent. Et HasAnswer se déduisant des sources, un prompt d'accueil sans citation aurait gonflé le bloc ambre des questions sans réponse. Même famille que WeatherSyncService noyant le journal d'audit. diff --git a/v1-plan.md b/v1-plan.md index a2d2575..85cdf5b 100644 --- a/v1-plan.md +++ b/v1-plan.md @@ -176,6 +176,16 @@ Ne change pas : la popup de traduction (un niveau justifié, langues verticales, ✅ **Volet `manager-service` terminé le 2026-08-13.** Customer Portal livré, ratio jetons → questions calé sur du réel ; le rate limiting, l'endpoint `ApplicationInstance` et les quotas seed **étaient déjà faits** et n'attendaient qu'une vérification (détail dans les lignes concernées). `dotnet build` vert, `dotnet test` **211 au total : 197 passés, 14 sautés** (Testcontainers, pas de démon Docker), 0 échec. +✅ **Miroir de la conversation vocale livré le 2026-08-13.** `flutter analyze lib` sans erreur, APK `dev` ✅, `dotnet test` **215**, `flutter build web` ✅. + +**Une seule conversation, portée par `VisitAppContext.assistant`.** Le chat écrit, le vocal et le proactif partagent l'instance ; les trois `AssistantService` séparés ont disparu. Le `maxHistory: 6` du vocal s'aligne sur 10 : deux surfaces qui partagent une conversation ne peuvent pas la tronquer différemment selon le point d'entrée, et la concision vocale vient d'`isVoice`, qui change le prompt côté serveur. + +⚠️ **Le vrai obstacle n'était pas l'affichage mais la forme du chat** : `AssistantChatSheet` gardait ses messages en `List` — des bulles déjà construites. On ne rejoue pas une conversation à partir de widgets, et un tour vocal survenu pendant que la feuille était fermée n'aurait jamais pu y entrer. Le service porte désormais les tours **en données** (`AssistantTurn`) et notifie ; la feuille rend depuis eux et se met à jour en direct. + +⚠️ **Deux listes, et c'est délibéré** : `_history` (envoyée au modèle) et `_turns` (affichée) ne coïncident pas. Un message d'erreur se montre sans repartir au guide — il n'a pas à s'excuser d'une panne au tour suivant ; et le prompt d'un déclenchement proactif part au guide **sans jamais s'afficher**, seule sa réponse apparaît, marquée « À voix haute ». Sans ce marquage, un visiteur ouvrant le chat trouverait des messages qu'il n'a jamais tapés. + +✅ **`conversationId` est enfin envoyé, et le champ manquait dans le client généré** — c'est ce qui expliquait que personne ne l'envoyait. Ajouté à la main dans `manager_api_new`. Il est renouvelé quand la conversation est vidée : sinon la visite entière d'un même visiteur n'en formerait qu'une. **2 tests serveur** fixent le lien entre deux tours et le repli — la branche `Guid.NewGuid()` n'était couverte par rien. + **Ce qui reste au lot F, et dans quel repo** — le backend ne bloque plus rien : - ~~`manager-app`~~ ✅ **livré le 2026-08-13** : bouton du Customer Portal et diviseur `aiTokensPerQuestion`. `flutter analyze lib` **sans erreur**, `flutter build web` ✅. Détail ci-dessous. - `mymuseum-visitapp` : déclenchement proactif (+ M3), miroir de la conversation vocale, émission des événements vocaux. C'est désormais **tout le reste du lot F**, et le plus gros.