From 613c7efc66d8b333cde1369d73448aad37cd542d Mon Sep 17 00:00:00 2001 From: Kazeia Team Date: Thu, 18 Jun 2026 23:40:42 +0200 Subject: [PATCH] =?UTF-8?q?fix(tts):=20repli=20sur=20la=20voix=20par=20d?= =?UTF-8?q?=C3=A9faut=20si=20le=20.cvps=20configur=C3=A9=20est=20absent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Incident device : profil actif PatientTest a voice_id=zelda, mais seuls damien.cvps + elodie.cvps sont déployés → voiceHandleOrThrow() levait « aucune voix chargée ('zelda') » → speakText catch → TTS MUET (aucun son), alors que STT + LLM fonctionnaient. voiceHandleOrThrow bascule désormais sur defaultVoiceId (damien, toujours livré) quand la voix demandée n'a pas de .cvps, au lieu de couper toute parole. Une voix manquante dégrade gracieusement au lieu de rendre Kazeia muet. Note (hors scope) : l'endpoint /voices reflète l'inventaire LEGACY Qwen3 (WAV+.bin), pas les .cvps CosyVoice → l'admin peut sélectionner une voix non déployée. À réconcilier séparément. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../main/java/com/kazeia/tts/CosyVoiceTtsEngine.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kazeia-android/app/src/main/java/com/kazeia/tts/CosyVoiceTtsEngine.kt b/kazeia-android/app/src/main/java/com/kazeia/tts/CosyVoiceTtsEngine.kt index 3bb524f..a6c7b08 100644 --- a/kazeia-android/app/src/main/java/com/kazeia/tts/CosyVoiceTtsEngine.kt +++ b/kazeia-android/app/src/main/java/com/kazeia/tts/CosyVoiceTtsEngine.kt @@ -104,8 +104,18 @@ class CosyVoiceTtsEngine( private fun voiceHandleOrThrow(): Long { require(handle != 0L) { "CosyVoice: not loaded" } - val v = voices[currentVoiceId] ?: ensureVoice(currentVoiceId) - require(v != 0L) { "CosyVoice: aucune voix chargée ('$currentVoiceId')" } + var v = voices[currentVoiceId] ?: ensureVoice(currentVoiceId) + // Repli gracieux : une voix configurée mais non déployée (.cvps absent) ne + // doit JAMAIS rendre le TTS muet — on bascule sur la voix par défaut + // (toujours livrée). Sinon un profil pointant une voix manquante coupe + // toute parole en silence (cf. incident "zelda" non déployé). + if (v == 0L && currentVoiceId != defaultVoiceId) { + log("voix '$currentVoiceId' indisponible → repli sur défaut '$defaultVoiceId'") + v = voices[defaultVoiceId] ?: ensureVoice(defaultVoiceId) + } + require(v != 0L) { + "CosyVoice: aucune voix chargée ('$currentVoiceId' ni défaut '$defaultVoiceId')" + } return v }