diff --git a/kazeia-android/app/src/main/java/com/kazeia/telemetry/KazeiaTelemetryProvider.kt b/kazeia-android/app/src/main/java/com/kazeia/telemetry/KazeiaTelemetryProvider.kt index 0f0203a..49dff1c 100644 --- a/kazeia-android/app/src/main/java/com/kazeia/telemetry/KazeiaTelemetryProvider.kt +++ b/kazeia-android/app/src/main/java/com/kazeia/telemetry/KazeiaTelemetryProvider.kt @@ -79,6 +79,11 @@ class KazeiaTelemetryProvider : ContentProvider() { get() = "${com.kazeia.KazeiaApplication.MODELS_DIR}/qwen3-tts-npu" private const val PREFIX_SUFFIX = "_voice_prefix.bin" private const val SUFFIX_SUFFIX = "_voice_suffix.bin" + // Voix CosyVoice (prod) : artefacts `.cvps` enrôlés. C'est l'inventaire réel + // depuis la bascule ; les `_voice_*.bin` ci-dessus sont des vestiges Qwen3. + private val VOICE_CVPS_DIR: String + get() = "${com.kazeia.KazeiaApplication.MODELS_DIR}/cosyvoice" + private const val CVPS_SUFFIX = ".cvps" } private val matcher = UriMatcher(UriMatcher.NO_MATCH).apply { @@ -526,26 +531,32 @@ class KazeiaTelemetryProvider : ContentProvider() { private fun voicesCursor(): Cursor { val cols = arrayOf( "id", "name", "state", - "wav_exists", "prefix_exists", "suffix_exists", + "wav_exists", "prefix_exists", "suffix_exists", "cvps_exists", "wav_size_bytes", "wav_duration_seconds", "wav_path", "created_at" ) val cursor = MatrixCursor(cols) - // Set des ids = union (wav basenames) ∪ (prefix bin basenames) + // Inventaire = réalité CosyVoice : union (WAV = « à convertir ») ∪ + // (`.cvps` = « prête »). Les embeddings Qwen3 (`_voice_*.bin`) NE sont plus + // comptés dans l'union : vestiges morts depuis la bascule, ils faisaient + // apparaître des voix « prête » fantômes sans aucun `.cvps`. val wavDir = File(VOICE_WAV_DIR) - val embDir = File(VOICE_EMB_DIR) + val cvpsDir = File(VOICE_CVPS_DIR) val wavIds = (wavDir.listFiles { f -> f.name.endsWith(".wav") } ?: emptyArray()) .associateBy { it.nameWithoutExtension.lowercase() } - val prefixIds = (embDir.listFiles { f -> f.name.endsWith(PREFIX_SUFFIX) } ?: emptyArray()) - .associateBy { it.name.removeSuffix(PREFIX_SUFFIX).lowercase() } - val ids = (wavIds.keys + prefixIds.keys).sorted() + val cvpsIds = (cvpsDir.listFiles { f -> f.name.endsWith(CVPS_SUFFIX) } ?: emptyArray()) + .associateBy { it.name.removeSuffix(CVPS_SUFFIX).lowercase() } + val ids = (wavIds.keys + cvpsIds.keys).sorted() for (id in ids) { val wav = wavIds[id] + val cvps = cvpsIds[id] val prefix = File(VOICE_EMB_DIR, "${id}$PREFIX_SUFFIX") val suffix = File(VOICE_EMB_DIR, "${id}$SUFFIX_SUFFIX") + // « ready » = `.cvps` déployé (jouable par CosyVoice) ; « recorded » = + // WAV seul (à convertir/enrôler par Kazeia-central) ; sinon « error ». val state = when { - prefix.exists() && suffix.exists() -> "ready" + cvps != null -> "ready" wav != null -> "recorded" else -> "error" } @@ -557,10 +568,11 @@ class KazeiaTelemetryProvider : ContentProvider() { if (wav != null) 1 else 0, if (prefix.exists()) 1 else 0, if (suffix.exists()) 1 else 0, + if (cvps != null) 1 else 0, wav?.length() ?: 0L, durSec, wav?.absolutePath ?: "", - wav?.lastModified() ?: prefix.lastModified() + wav?.lastModified() ?: cvps?.lastModified() ?: 0L )) } return cursor