91 lines
4.3 KiB
Markdown
91 lines
4.3 KiB
Markdown
# PROFILE_LANGUAGE_SPEC — langue par profil patient (pipeline STT/LLM/TTS)
|
|
|
|
> **Destinataire : dev de l'app patiente `com.kazeia`.**
|
|
> **Auteur : Kazeia-central.** Stack figée (`FROZEN.md`) → changement décrit ici, livré.
|
|
>
|
|
> **Objet** : la langue du pipeline doit être **choisie par patient** (porté par le
|
|
> profil), pas figée en `"fr"`. Kazeia-central gère/édite la langue par profil et la
|
|
> pousse ; l'app doit l'**exposer** (provider) et l'**appliquer** (pipeline).
|
|
|
|
---
|
|
|
|
## 0. État observé (vérifié)
|
|
|
|
- Le pipeline est **déjà paramétré par langue** : `KazeiaPipeline` passe `context.language`
|
|
à `sttEngine.transcribe(audio, context.language)` et `ttsEngine.synthesizeAndPlay(text,
|
|
context.language, …)`. `OmniVoiceTtsEngine.langCode()` résout un nom/alias → code (646
|
|
langues). `WhisperHybridEngine.transcribe(audio, language)` prend aussi la langue.
|
|
- **MAIS la langue est codée en dur `"fr"`** : `KazeiaService` appelle
|
|
`stt.transcribe(audioSnapshot, language = "fr")` (≈ lignes **1100** et **1351**) ;
|
|
`core/Pipeline.kt` a `language: String = "fr"` par défaut. La langue **n'est pas lue
|
|
depuis le profil**.
|
|
- `Profile` (`profiles/Profile.kt`) **n'a aucun champ langue** : `id, displayName,
|
|
avatarColor, voiceId, systemPromptOverride, pinHash, createdAt, lastUsedAt, notes,
|
|
isDefault`.
|
|
- `KazeiaService` a **déjà** l'accès au profil actif et y réagit :
|
|
`ProfileStore.get(ctx).activeProfile()` ; `onProfileStoreChanged()` applique déjà
|
|
`activeProfile().voiceId → setVoice`. **C'est exactement là** qu'il faut résoudre la
|
|
langue.
|
|
|
|
---
|
|
|
|
## 1. Adaptation demandée
|
|
|
|
### 1.1 `Profile` — nouveau champ `language`
|
|
`profiles/Profile.kt` : ajouter
|
|
```kotlin
|
|
val language: String = "fr", // code/nom résolu par OmniVoiceTtsEngine.langCode() (déf. fr)
|
|
```
|
|
- `toJson()` : `put("language", language)`.
|
|
- `fromJson()` : `language = js.optString("language", "fr")` (rétro-compat : profils
|
|
existants sans le champ → `"fr"`).
|
|
- Valeur : un **code court** (`fr`, `en`, `de`, `es`, `it`, `pt`, `ar`, `zh`, …) ou un
|
|
nom que `langCode()` sait résoudre. Kazeia-central enverra un code court.
|
|
|
|
### 1.2 Provider `/profiles` — exposer + accepter `language`
|
|
- `voicesCursor`/`profilesCursor` : ajouter la colonne **`language`** (déf. `"fr"`).
|
|
- `upsertProfile(ContentValues)` : lire la clé `language` si présente (sinon conserver
|
|
l'existant / défaut `"fr"`). Ajout additif → compat ascendante.
|
|
- (Le canal d'écriture riche `profile_upsert_json` du `PROVIDER_RPC_SPEC §4.4` doit aussi
|
|
inclure `language` quand il sera implémenté ; en attendant, `update /profiles` avec la
|
|
clé `language` suffit pour ce champ simple.)
|
|
|
|
### 1.3 `KazeiaService` — appliquer la langue du profil actif
|
|
Remplacer le `"fr"` figé par la langue du profil actif (avec repli `"fr"`) :
|
|
```kotlin
|
|
val lang = ProfileStore.get(applicationContext).activeProfile()?.language ?: "fr"
|
|
// … construire le PipelineContext avec language = lang ;
|
|
// … stt.transcribe(audio, language = lang) aux ~l.1100 et ~l.1351.
|
|
```
|
|
- À recalculer sur changement de profil actif (`onProfileStoreChanged()`, déjà le point
|
|
où la voix est ré-appliquée) — pour qu'un changement de patient change la langue à chaud.
|
|
|
|
---
|
|
|
|
## 2. Ce que fait Kazeia-central (pour info — pas côté app)
|
|
|
|
- Édite la langue par profil et la **pousse** (via `update /profiles` / futur
|
|
`profile_upsert_json`).
|
|
- Tient la **fiche patient complète** (identité civile, contact/référent, clinique) dans
|
|
son **store chiffré**, clé `(serial, profile_id)`. **Cette fiche ne va PAS sur la
|
|
tablette** (PII clinique, minimisation on-device). Seul l'**opérationnel** (langue,
|
|
voix, prompt) concerne le device.
|
|
|
|
---
|
|
|
|
## 3. Récap
|
|
|
|
| # | Adaptation app | Criticité |
|
|
| --- | --- | --- |
|
|
| 1 | `Profile.language` (+ toJson/fromJson, déf. `"fr"`) | requis |
|
|
| 2 | `/profiles` expose + accepte `language` | requis |
|
|
| 3 | `KazeiaService` : `context.language = activeProfile.language ?: "fr"` (remplace le `"fr"` figé), ré-appliqué au changement de profil | requis |
|
|
|
|
Changement borné : le pipeline sait déjà gérer la langue ; il ne manque que **la
|
|
relier au profil**.
|
|
|
|
---
|
|
|
|
*Source de vérité : `Profile.kt`, `KazeiaService.kt` (~l.1100/1351), `KazeiaPipeline.kt`,
|
|
`OmniVoiceTtsEngine.langCode()`, `WhisperHybridEngine.transcribe()`. Vérifié le 2026-06-23.*
|