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>
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)
- Aller sur https://console.picovoice.ai/
- Créer un compte → Wake Word → Create a keyword
- Keyword :
Hey MyVisit(ou autre phrase de votre choix) - Exporter pour Android → sauvegarder dans
assets/wake_words/hey_myvisit_android.ppn - Exporter pour iOS → sauvegarder dans
assets/wake_words/hey_myvisit_ios.ppn - 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)
- Porcupine détecte "Hey MyVisit"
speech_to_texttranscrit : "Qui a peint ce tableau ?"AssistantService.chat("Qui a peint ce tableau ?")→ backend MyInfoMate- Réponse texte →
GlassesTtsService.speak() - 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 :
- Les lunettes capturent une photo
GlassesQrScannerServicedécode le QR (même regex que le scanner téléphone)- Si la section appartient à la configuration courante, l'assistant la résume en 3 phrases
- 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 :
- Le guide envoie un message depuis
manager-app→ push notification Firebase PushNotificationServicereçoit la notification- Un handler à ajouter dans
initialize()pipe le corps du message versGlassesTtsService - 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.setCategoryest appelé avantjust_audio.play()
Wake word ne répond pas
- Vérifier que
kPicovoiceAccessKeyest bien injecté (non vide) - Vérifier que les fichiers
.ppnsont bien dansassets/wake_words/et déclarés danspubspec.yaml - Les fichiers
.ppnsont spécifiques Android/iOS — ne pas les inverser
Faux positifs wake word fréquents
- Télécharger un modèle plus sensible (paramètre
sensitivitydePorcupineManager) - 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
connectedoustreaming— vérifierMetaGlassesService.instance.state - Vérifier que la section scannée appartient bien à la configuration active (
visitContext.sectionIds)
ElevenLabs retourne 401
- Clé API expirée ou quota dépassé — vérifier sur https://elevenlabs.io/speech-synthesis
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) |