perf(tts): NE PAS streamer LLM→CosyVoice (contention CPU) — documenté — v0.1.9
« Reste optionnel » : tenté le streaming LLM→TTS pour CosyVoice (synthèse de la 1ʳᵉ phrase pendant que le LLM décode, comme le chemin Qwen TTS-B). Mesuré device : CONTRE-PRODUCTIF. LLM decode (6 threads CPU) et synthèse CosyVoice (8 threads CPU) saturent tous les cœurs ; les chevaucher écroule le LLM (17 → 0,55 tok/s, tour 1,1s → 41s, 1er son à 43s). Reverté. Le streaming LLM→TTS n'a de sens que si les 2 étages utilisent des compute distincts (Qwen3 NPU + TTS CPU). Pour CosyVoice (tout CPU) : laisser le LLM finir vite PUIS synthesizeAndPlay, qui streame déjà phrase-par-phrase EN INTERNE (synthèse N+1 pendant lecture N, sans contention). Net diff = un commentaire garde-fou dans KazeiaService pour ne pas re-tenter ; code de streaming retiré. Re-validé batch : LLM 17,1 tok/s (1,9s), TTS 1er son ~8s (RTF CosyVoice inhérent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b822974b99
commit
db0e56b26c
|
|
@ -44,8 +44,8 @@ android {
|
||||||
applicationId = "com.kazeia"
|
applicationId = "com.kazeia"
|
||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 9
|
versionCode = 10
|
||||||
versionName = "0.1.8"
|
versionName = "0.1.9"
|
||||||
|
|
||||||
// WebDAV de distribution — injecté depuis local.properties.
|
// WebDAV de distribution — injecté depuis local.properties.
|
||||||
buildConfigField("String", "WEBDAV_BASE", "\"${localProp("webdav.base")}\"")
|
buildConfigField("String", "WEBDAV_BASE", "\"${localProp("webdav.base")}\"")
|
||||||
|
|
|
||||||
|
|
@ -1837,6 +1837,11 @@ Pas d'introduction, pas d'explication. Juste les 4 lignes en francais. /no_think
|
||||||
// the enqueueSentence plumbing fall through to the legacy post-LLM
|
// the enqueueSentence plumbing fall through to the legacy post-LLM
|
||||||
// pipeline.speakText batch call.
|
// pipeline.speakText batch call.
|
||||||
val qwen = tts as? com.kazeia.tts.Qwen3TtsEngine
|
val qwen = tts as? com.kazeia.tts.Qwen3TtsEngine
|
||||||
|
// NB CosyVoice : PAS de streaming LLM→TTS. LLM decode et synthèse CosyVoice
|
||||||
|
// sont tous deux CPU-bound (saturent les cœurs) ; les chevaucher étrangle le
|
||||||
|
// LLM (mesuré : 17→0,55 tok/s, tour 1,1s→41s). On laisse le LLM finir vite
|
||||||
|
// (session ~1,1s) PUIS synthesizeAndPlay (chemin legacy) qui streame déjà
|
||||||
|
// phrase-par-phrase EN INTERNE (synthèse N+1 pendant lecture N, sans contention).
|
||||||
// Bulle vide + signal Thinking sur le visualizer : la couleur de l'orbe
|
// Bulle vide + signal Thinking sur le visualizer : la couleur de l'orbe
|
||||||
// pulse pendant que le LLM réfléchit, plus de "..." textuels parasites.
|
// pulse pendant que le LLM réfléchit, plus de "..." textuels parasites.
|
||||||
// L'écran reveal mot-par-mot s'enchaîne quand le premier audio joue.
|
// L'écran reveal mot-par-mot s'enchaîne quand le premier audio joue.
|
||||||
|
|
@ -1899,6 +1904,8 @@ Pas d'introduction, pas d'explication. Juste les 4 lignes en francais. /no_think
|
||||||
val sentenceCounter = java.util.concurrent.atomic.AtomicInteger(0)
|
val sentenceCounter = java.util.concurrent.atomic.AtomicInteger(0)
|
||||||
// TTS coupé (llmOnly) → pas de session de synthèse ouverte ; la bulle
|
// TTS coupé (llmOnly) → pas de session de synthèse ouverte ; la bulle
|
||||||
// se remplit token par token dans onToken (voir plus bas).
|
// se remplit token par token dans onToken (voir plus bas).
|
||||||
|
// Streaming LLM→TTS réservé à Qwen3 (NPU/Hexagon : pas de contention CPU avec
|
||||||
|
// le LLM). CosyVoice (CPU) passe par le chemin batch (voir note plus haut).
|
||||||
val ttsStreamer: com.kazeia.tts.SentenceStreamer? =
|
val ttsStreamer: com.kazeia.tts.SentenceStreamer? =
|
||||||
if (qwen != null && !llmOnly) {
|
if (qwen != null && !llmOnly) {
|
||||||
qwen.onSegmentPlaying = onSegPlay
|
qwen.onSegmentPlaying = onSegPlay
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue