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