DOCS/rayban-meta-integration.md
Thomas Fransolet a5a8ecdb20 Documentation interne MyInfoMate / Unov
Import initial de la documentation : statut, roadmap, plans V1/V2,
specs verticales (creche, sport), audits securite, plan de test,
analyse concurrentielle et maquettes de design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:17:01 +02:00

12 KiB

Intégration Ray-Ban Meta — mymuseum-visitapp

Vue d'ensemble

L'intégration Ray-Ban Meta transforme mymuseum-visitapp en guide audio mains-libres. Le visiteur porte les lunettes ; son téléphone est en poche. Il peut :

  • Poser une question à voix haute à l'assistant sans toucher le téléphone
  • Scanner un QR code en appuyant sur le bouton des lunettes → entendre l'explication
  • Recevoir automatiquement des informations contextuelles en approchant d'une œuvre (beacon ou géolocalisation)

L'architecture existante (AssistantService, QR scanner, beacons, géoloc) est inchangée. Les lunettes sont une nouvelle surface d'entrée/sortie branchée dessus.


Prérequis

Matériel & apps

  • Ray-Ban Meta Gen 2 (~380€, 8h autonomie)
  • App Meta AI installée sur le téléphone — bridge Bluetooth obligatoire
  • Compte Meta connecté dans l'app Meta AI

Comptes & clés API

Service Usage Où obtenir
Picovoice Console Générer le wake word .ppn https://console.picovoice.ai/ — gratuit jusqu'à 3 keywords
ElevenLabs Synthèse vocale TTS https://elevenlabs.io — tier gratuit ou payant selon volume

SDK Flutter (developer preview)

Les packages Meta SDK doivent être ajoutés à pubspec.yaml quand publiés :

# Décommenter quand disponibles :
# meta_wearables_dat: any   # Android
# meta_wearables: any       # iOS (ChunkyTofuStudios)

Vérifier les versions actuelles sur pub.dev : meta_wearables_dat, meta_wearables.


Setup initial

1. Générer les fichiers wake word (.ppn)

  1. Aller sur https://console.picovoice.ai/
  2. Créer un compte → Wake WordCreate a keyword
  3. Keyword : Hey MyVisit (ou autre phrase de votre choix)
  4. Exporter pour Android → sauvegarder dans assets/wake_words/hey_myvisit_android.ppn
  5. Exporter pour iOS → sauvegarder dans assets/wake_words/hey_myvisit_ios.ppn
  6. Copier l'Access Key affiché dans le dashboard

2. Configurer les variables de build (--dart-define)

Toutes les clés et URLs sont injectées via --dart-define au moment du build/run. Aucune clé en dur dans le code.

Référence complète des --dart-define

Variable Obligatoire Exemple Description
API_BASE_URL prod https://api.mymuseum.be URL du backend MyInfoMate
API_KEY abc123 Clé API MyInfoMate (bootstrappe la clé depuis le backend au 1er run)
INSTANCE_ID 63514fd67ed8c735aaa4b8f2 ID de l'instance (fixe par flavor)
WHISPER_API_KEY recommandé sk-xxxx Clé OpenAI Whisper ou n'importe quelle valeur si endpoint auto-hébergé
WHISPER_ENDPOINT si auto-hébergé http://192.168.1.x:8000/v1/audio/transcriptions Endpoint Whisper compatible OpenAI (défaut: api.openai.com)
ELEVENLABS_API_KEY optionnel sk_xxxx TTS ElevenLabs — si vide, utilise flutter_tts (on-device gratuit)
ELEVENLABS_VOICE_ID optionnel EXAVITQu4vr4xnSDxMaL ID voix ElevenLabs
PICOVOICE_ACCESS_KEY optionnel xxxx Wake word Porcupine — si vide, utilise speech_to_text
FLAVOR build dev / mdlf / fortsaintheribert Détermine les couleurs et l'app name

Commandes de lancement

Dev minimal (speech_to_text + flutter_tts) :

flutter run --flavor dev \
  --dart-define=API_BASE_URL=http://192.168.x.x:5000 \
  --dart-define=API_KEY=ta_clé \
  --dart-define=INSTANCE_ID=63514fd67ed8c735aaa4b8f2

Dev avec Whisper OpenAI :

flutter run --flavor dev \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=ta_clé \
  --dart-define=INSTANCE_ID=63514fd67ed8c735aaa4b8f2 \
  --dart-define=WHISPER_API_KEY=sk-xxxx

Dev avec Whisper auto-hébergé (faster-whisper-server Docker) :

flutter run --flavor dev \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=ta_clé \
  --dart-define=INSTANCE_ID=63514fd67ed8c735aaa4b8f2 \
  --dart-define=WHISPER_API_KEY=anykey \
  --dart-define=WHISPER_ENDPOINT=http://192.168.x.x:8000/v1/audio/transcriptions

Production complète (Porcupine + Whisper auto-hébergé + flutter_tts) :

flutter build appbundle --flavor mdlf \
  --dart-define=API_BASE_URL=https://api.mymuseum.be \
  --dart-define=API_KEY=ta_clé \
  --dart-define=INSTANCE_ID=xxx \
  --dart-define=FLAVOR=mdlf \
  --dart-define=PICOVOICE_ACCESS_KEY=xxx \
  --dart-define=WHISPER_API_KEY=anykey \
  --dart-define=WHISPER_ENDPOINT=https://whisper.myinfomate.be/v1/audio/transcriptions

Démarrer faster-whisper-server (Docker)

docker run -p 8000:8000 fedirz/faster-whisper-server:latest-cpu
# Avec GPU :
docker run --gpus all -p 8000:8000 fedirz/faster-whisper-server:latest-cuda

3. Activer le mode lunettes dans l'app

Dans VisitAppContext, passer glassesEnabled = true. Pour l'instant c'est à faire dans le code ou via un toggle UI à créer dans les paramètres de la configuration.

4. Lancer l'app sur le device

flutter run --dart-define=ELEVENLABS_API_KEY=xxx --dart-define=PICOVOICE_ACCESS_KEY=xxx

Architecture technique

Lunettes Ray-Ban Meta
  │ Bluetooth (HFP mic, A2DP speakers, camera stream, button)
  ▼
[MetaGlassesService]          ← SDK DAT lifecycle + photo capture button
  │
  ├── [WakeWordService]        ← Porcupine détecte "Hey MyVisit" (on-device)
  │     └── speech_to_text   ← transcrit la commande après wake word
  │           ├── "scanne ce QR" → MetaGlassesService.requestPhotoCapture()
  │           ├── "répète"        → GlassesTtsService.replay()
  │           └── autre          → AssistantService.chat() → GlassesTtsService
  │
  ├── [GlassesQrScannerService] ← photo → mobile_scanner → regex URL → AssistantService
  │
  ├── [GeoBeaconTriggerService] ← geolocator GPS + beacon_scanner BLE → AssistantService
  │
  └── [GlassesTtsService]       ← ElevenLabs API → just_audio → AudioRoutingChannel
        └── [AudioRoutingPlugin] ← natif iOS (AVAudioSession) / Android (AudioManager)
                                   force sortie A2DP vers lunettes

Flux de données type (question vocale)

  1. Porcupine détecte "Hey MyVisit"
  2. speech_to_text transcrit : "Qui a peint ce tableau ?"
  3. AssistantService.chat("Qui a peint ce tableau ?") → backend MyInfoMate
  4. Réponse texte → GlassesTtsService.speak()
  5. ElevenLabs → MP3 → just_audio → AudioRoutingPlugin → lunettes Ray-Ban

Fonctionnalités

1. Wake word + conversation vocale

Déclencheur : "Hey MyVisit"
Commandes reconnues :

Phrase Action
"Hey MyVisit" + question Pose la question à l'assistant, entend la réponse
"Hey MyVisit, scanne ce QR" Déclenche la capture photo → pipeline QR
"Hey MyVisit, répète" Rejoue la dernière synthèse vocale

Le wake word fonctionne en permanence en background (Foreground Service sur Android).

2. Scanner QR via lunettes

Déclencheurs :

  • Pression courte sur le bouton hardware des lunettes
  • Commande vocale "Hey MyVisit, scanne ce QR"

Fonctionnement :

  1. Les lunettes capturent une photo
  2. GlassesQrScannerService décode le QR (même regex que le scanner téléphone)
  3. Si la section appartient à la configuration courante, l'assistant la résume en 3 phrases
  4. La réponse est lue dans les lunettes

Anti-spam : 10s de cooldown entre deux scans du même QR.

3. Géolocalisation → TTS automatique (mode proactif)

Activer VisitAppContext.proactiveModeEnabled = true pour que l'assistant parle spontanément.

GPS : Le service surveille en continu la position GPS. Quand le visiteur entre dans le rayon d'un GeoTriggerPoint (défini par lat/lng + rayon en mètres), l'assistant propose une présentation du lieu.

Beacons BLE : Quand la précision d'un beacon connu passe sous 3m, l'assistant présente l'œuvre ou l'espace associé.

Les deux fonctionnent en parallèle, avec un cooldown de 30s par point pour éviter le spam.

4. Navigation guidée mains-libres

Dans un GuidedPath, chaque étape peut déclencher un TTS automatique à l'entrée de sa zone GPS ou à la détection de son beacon. Le visiteur progresse sans jamais toucher son téléphone.

5. Mode "Quiet"

La sortie audio est forcée sur les lunettes via AudioRoutingPlugin, pas sur le haut-parleur téléphone. Respecte le silence des musées.


Mode proactif — comportement

proactiveModeEnabled glassesEnabled Comportement
false false Comportement app normal, pas de lunettes
false true Lunettes actives, TTS sur questions vocales et QR, pas de déclenchements auto
true true Tout actif : wake word + QR + géoloc/beacon auto

Recommandation : proposer le toggle du mode proactif à l'écran de démarrage de visite.


Multi-visiteur broadcast (V2)

Plusieurs visiteurs avec des lunettes dans la même instance peuvent recevoir simultanément un message du guide via Firebase.

Comment ça marchera :

  1. Le guide envoie un message depuis manager-app → push notification Firebase
  2. PushNotificationService reçoit la notification
  3. Un handler à ajouter dans initialize() pipe le corps du message vers GlassesTtsService
  4. Tous les visiteurs connectés entendent le message dans leurs lunettes

Le topic Firebase instance_{instanceId} est déjà en place.


Limitations SDK (developer preview, mai 2026)

Limitation Détail
App Meta AI requise Doit être installée et active — bridge Bluetooth obligatoire
Résolution caméra Max 720p/30fps via Bluetooth (contrainte protocole, pas hardware)
Publication App Store/Play Store Réservée aux partenaires Meta sélectionnés pour l'instant — distribution interne possible
Android uniquement pour meta_wearables_dat Le plugin Flutter iOS (meta_wearables) est en cours
iOS 26.0+ pour le SDK natif Si implémentation Swift directe (comme OpenGlasses)

Troubleshooting

Son dans le téléphone au lieu des lunettes

  • Vérifier que les lunettes sont bien en Bluetooth actif et appairées
  • Sur Android API < 31 : vérifier que startBluetoothSco() ne génère pas d'erreur de permission
  • Sur iOS : vérifier que AVAudioSession.setCategory est appelé avant just_audio.play()

Wake word ne répond pas

  • Vérifier que kPicovoiceAccessKey est bien injecté (non vide)
  • Vérifier que les fichiers .ppn sont bien dans assets/wake_words/ et déclarés dans pubspec.yaml
  • Les fichiers .ppn sont spécifiques Android/iOS — ne pas les inverser

Faux positifs wake word fréquents

  • Télécharger un modèle plus sensible (paramètre sensitivity de PorcupineManager)
  • Choisir une phrase wake word plus longue sur Picovoice Console

Scan QR échoue depuis les lunettes

  • Vérifier que le QR code est bien visible (lumière suffisante)
  • Le SDK DAT doit être en état connected ou streaming — vérifier MetaGlassesService.instance.state
  • Vérifier que la section scannée appartient bien à la configuration active (visitContext.sectionIds)

ElevenLabs retourne 401


Fichiers clés

Fichier Rôle
lib/Services/meta_glasses_service.dart SDK DAT lifecycle, photo capture
lib/Services/glasses_tts_service.dart ElevenLabs → audio Bluetooth
lib/Services/wake_word_service.dart Porcupine + dispatch commandes vocales
lib/Services/geo_beacon_trigger_service.dart Géofence GPS + beacons → TTS auto
lib/Services/glasses_qr_scanner_service.dart QR decode depuis photo capture lunettes
lib/PlatformChannels/audio_routing_channel.dart Canal Dart → natif pour routage Bluetooth
android/…/MainActivity.kt Plugin Android : AudioManager A2DP
ios/Runner/AudioRoutingPlugin.swift Plugin iOS : AVAudioSession Bluetooth
assets/wake_words/ Fichiers .ppn Porcupine (à générer)