# 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.
⚠️ **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. ---