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>
285 lines
12 KiB
Markdown
285 lines
12 KiB
Markdown
# 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 :
|
|
```yaml
|
|
# 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 Word** → **Create 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) :**
|
|
```bash
|
|
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 :**
|
|
```bash
|
|
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) :**
|
|
```bash
|
|
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) :**
|
|
```bash
|
|
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)
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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**
|
|
- 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) |
|