DOCS/status/rayban-meta.md
2026-09-03 14:00:51 +02:00

52 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 5bis. Lunettes Ray-Ban Meta — état réel du code (relevé le 2026-08-09)
> ← Section **§5bis** du tableau de bord : [STATUS.md](../STATUS.md)
> Cette section corrige une erreur de ce fichier : la roadmap classait l'AR lunettes en « pas commencé, pilote subventionné quand le SDK sort de preview ». **Un POC fonctionnel existe depuis mai-juin 2026**, ~2 700 lignes de Dart dans `mymuseum-visitapp`, sur la branche **`Meta-Rayban-Test`** (23 commits d'avance sur `master`, jamais mergée — c'est la branche de travail courante du repo).
| Brique | Fichier | État |
|---|---|---|
| SDK Meta | `pubspec.yaml:84``meta_wearables_dat: ^0.1.3` | Dépendance **active**, pas commentée |
| Connexion / photo / stream vidéo | `lib/Services/meta_glasses_service.dart` (241 l.) | Cycle de vie complet, routage audio HFP via canal natif |
| Pipeline mains-libres | `lib/Services/Glasses/voice_orchestrator.dart` (408 l.) | wake word → STT → dispatch → LLM ou scan QR → TTS, sons d'état |
| Moteurs interchangeables | `lib/Services/Glasses/engines/` + `impl/` (~1 040 l.) | 4 interfaces, **11 implémentations** : openWakeWord, Porcupine, speech_to_text, Whisper, Home Assistant STT, Gemini TTS, ElevenLabs, flutter_tts, client LLM MyInfoMate |
| Service de fond | `lib/Services/Glasses/glasses_background_service.dart` | Téléphone en poche, écran verrouillé |
| UI | `VoiceModeSheet`, `GlassesStatusWidget`, `GlassesDebugPanel` (450 l., via `AdminPopup`) | Monté dans `main.dart:109-112` |
Commit `c652604` : *« Working flow also in background ! With custom wakeword working (hey visit et hey viva). flow llm working + take photo + scan qr code working »*.
### Ce qui bloque réellement la commercialisation
Pas « le SDK est en preview » — la liste est plus concrète :
- **Android uniquement** (`if (!Platform.isAndroid) return;` dans `meta_glasses_service.dart`). Le modèle **BYOD tombe** pour tous les visiteurs iPhone. Seul le modèle « kit prêté par le lieu » tient aujourd'hui.
- **Pas de distribution store** tant que le SDK est en developer preview : chaque installation passe par les credentials développeur.
-~~**TTS = ElevenLabs, facturé au caractère** — basculer sur Gemini avant de vendre l'add-on~~ **Déjà fait, constaté le 2026-08-13.** `constants.dart:20` dit « ElevenLabs retiré du pipeline (trop cher) » et `VoiceController` ne construit que `GeminiTtsEngine` ou la voix système. Le risque de marge qui motivait cette ligne est écarté. `impl/elevenlabs_tts_engine.dart` **est conservé** comme option — à rouvrir seulement si des clients jugent la voix Gemini insuffisante, en sachant que c'est beaucoup plus cher.
- ⚠️ **Mais deux défauts ont vécu derrière cette ligne, corrigés le 2026-08-13.**
1. **Le choix de voix du client n'était pas honoré.** Le sélecteur Viva (`Sulafat`) / Marco (`Umbriel`) existe dans manager-app depuis le 07/08 et écrit `Instance.GuideVoiceId` ; `mymuseum-visitapp` ne lisait **jamais** ce champ et utilisait une constante de build, dont le défaut était `Algieba` — une voix que personne n'a écoutée. Même forme que W1 : un réglage offert par le CMS que l'app visiteur ignore. La voix vient désormais de l'instance, la constante n'étant plus qu'un repli (passé à `Sulafat`).
2. **Aucun APK ne parlait avec la voix du produit.** `GeminiTtsEngine` n'est choisi que si `GEMINI_API_KEY` est injectée au build — elle ne l'était nulle part, donc tous les builds retombaient sur `FlutterTtsEngine`, la voix système d'Android, **en silence**. Le repli s'annonce maintenant dans les logs, `constants.dart` porte la commande, et `launch.json` a une configuration « Dev + voix Gemini ». ⚠️ **Le repli reste le défaut, et c'est voulu** : les tests de terrain ne consomment ni jetons ni argent.
- ⚠️ **Le STT n'est pas Google non plus** : `WhisperSttEngine` pointe sur `api.openai.com` si `WHISPER_API_KEY` est définie, sinon repli sur `speech_to_text`, le moteur du device. La clé est vide aujourd'hui, donc c'est le device qui transcrit. **À trancher au lot J** : activer Whisper ajouterait OpenAI comme sous-traitant, que le §8.5 des CGU ne mentionne pas — il ne parle que de Google.
- **Wake word de prod non réglé** : `porcupine_flutter` est commenté dans `pubspec.yaml` (payant), l'implémentation courante s'appuie sur `speech_to_text` / openWakeWord.
- **Branche jamais mergée** dans `master`.
- **Le POC ne compile plus en l'état — relevé le 2026-08-11.** `flutter analyze lib` sur `mymuseum-visitapp` remonte **4 erreurs**, toutes le même manque : `kElevenLabsApiKey` et `kElevenLabsVoiceId` sont **absents de `constants.dart`** alors que `glasses_qr_scanner_service.dart:110-111` et `wake_word_service.dart:133-134` les utilisent et importent bien `constants.dart`. La doc de `glasses_tts_service.dart:31-32` confirme l'intention (« typiquement `kElevenLabsApiKey` de `constants.dart` »). Ces deux constantes sont des **secrets qui n'ont jamais été committés** — le POC tournait avec un `constants.dart` local. Conséquence pratique : **« démontrable » suppose de les remettre**, ce n'est pas un `git checkout` qui suffit. À traiter avec la bascule TTS → Gemini ci-dessus, qui les rend inutiles.
-~~**`flutter build apk` ne passe plus non plus**~~**levé le 2026-08-12 par K5.** Les trois flavors construisent ; le NDK est passé à 28.2.13676358 et Kotlin à 2.3.10.
-**Correction du 2026-08-13 : « l'APK se construit sans le POC dedans » est faux, et la conclusion qu'on en tirait aussi.** Les 4 erreurs ne sont pas dans le POC vivant, elles sont dans ses **ancêtres** : `wake_word_service.dart` n'est importé par personne, et `glasses_qr_scanner_service.dart` seulement par lui — un îlot de deux fichiers hors du graphe de `main.dart`, la génération d'avant l'orchestrateur. Le POC **actuel**, lui, est bien dans l'APK : `Services/Glasses/` est importé par `VoiceController`, et `GlassesStatusWidget` est monté sur l'accueil.<br>⚠️ **Conséquence pratique, inverse de celle qui était écrite ici** : « démontrable » **ne suppose pas** de remettre les deux constantes ElevenLabs. Le chemin vivant choisit `GeminiTtsEngine` dès que `kGeminiApiKey` est renseignée (`voice_controller.dart:94-100`) et ne touche jamais `kElevenLabs*`. La bascule TTS → Gemini réclamée ci-dessus **est déjà faite dans le code** ; ce qui reste est de supprimer les deux ancêtres morts.
-~~**Branche jamais mergée / à trancher avant K6**~~**tranché le 2026-08-13 par le propriétaire du projet : `Meta-Rayban-Test` est la branche de travail à jour, pas un POC de côté.** Le nom est trompeur, il date de la première expérimentation ; tout le travail V1 de `mymuseum-visitapp` y vit et les lunettes n'en sont qu'une partie — invisibles, d'ailleurs, si l'instance n'a pas l'assistant. On développe et on publie depuis elle. Idem `tablet-app` sur `AI-Assistant-test`. **Rien à clarifier avant K6** ; c'est ce paragraphe qui affirmait le contraire et fabriquait l'alerte.
### Latence, langues et accusés de réception — relevé le 2026-08-13
> Plan complet : **[voice-latency-plan.md](../voice-latency-plan.md)**, découpé en « maintenant / après les tests / V2 ». Ce qui suit n'en garde que les constats vérifiés dans le code.
-**L'assistant vocal ne parle réellement que FR/NL/EN/DE, et personne ne le disait.** `_toLangCode` (`voice_orchestrator.dart:399-407`) ne mappe que ces quatre langues et **renvoie `fr-FR` par défaut** ; `constants.dart:59-70` en déclare 10. Un visiteur en italien se fait répondre en français, **sans erreur ni trace**. Décidé le 2026-08-13 : la limite est assumée et documentée, le reste de l'app garde ses 10 langues. Le coût d'en rajouter une est faible et c'est vérifié — les traductions `voice.*` existent **déjà pour les 10 langues** dans `translations.dart`, Whisper prend le code générique et est multilingue, le wake word est phonétique.
-**Et les quatre langues annoncées ne le sont pas non plus.** `_isStopCommand`, `_isRepeatCommand`, `_isQrScanCommand`, `_isPhotoCommand` (`:375-397`) cherchent des mots **français en dur** — « répète », « arrête », « prends », « regarde ». Elles avaient été écrites en français pour tester et n'ont jamais été reprises. Un néerlandophone qui dit « herhaal » n'est pas compris, et `_isQrScanCommand` matche sur `code` : « what's the **code** of this painting » déclenche un scan QR. **À corriger avant le lot H** — sinon les tests multilingues valident autre chose que ce qu'on croit.
- ⚠️ **`done.mp3` retarde la réponse de toute sa durée.** `:212` fait `await _playDoneSound()` juste avant `ttsEngine.speak()`, et `_playSound` attend `play()`, dont le future ne se résout qu'à **la fin de la lecture**. En prime c'est un doublon : la parole *est* le signal de fin.
- ⚠️ **Le time-to-first-audio est la somme de tout.** `LlmClient.chat()` retourne un future de réponse complète (pas de flux) et `GeminiTtsEngine._synthesize()` fait un `generateContent` unaire qui attend **tout** le PCM avant d'écrire le WAV. D'où le son de réflexion en boucle, qui bouche ce trou. Le remède qui ne dépend d'aucune API nouvelle : **découper la réponse en phrases** et synthétiser la première pendant que les suivantes se préparent — contenu dans `GeminiTtsEngine`, sans toucher au backend.
- 💡 **Idée retenue mais repoussée : remplacer le bip du wake word par une phrase parlée** (« Oui, je vous écoute ») dans la langue et la voix du visiteur, 2-3 variantes. Repoussée **après les tests** parce qu'elle demande de générer et valider à l'oreille ~40 fichiers (2 voix × 4 langues × 5 phrases), et qu'une partie du besoin qu'elle compense disparaît si la latence baisse. ⚠️ Règle de cohérence si on la fait : les acks ne s'activent que si le moteur runtime est **Gemini** et que la voix correspond à `guideVoiceId` — des acks en Sulafat suivis d'une réponse en voix système Android seraient pires que le bip.
- 🔭 **Piste V2 : le Live API de Gemini** (WebSocket, audio natif bidirectionnel) supprimerait les trois maillons Whisper → LLM → TTS et débloquerait le barge-in et le VAD serveur. Faisable, mais le tool calling devrait passer par un proxy WebSocket dans `manager-service` (option retenue sur le papier), le modèle de coût passe à la **session ouverte** avec des jetons audio bien plus chers, et les modèles sont **en preview**. **À ouvrir par un spike chiffré d'une journée, pas par une décision.**
### Ce que ça change côté commercial
Le POC est **démontrable**. Face à un concurrent mono-usage type Musa Guide, une démo qui tourne pèse plus qu'une ligne « bientôt » sur la landing. À condition d'assumer le kit Android prêté, et de ne pas vendre l'add-on avant la bascule TTS.
---