fix(voices): /voices reflète l'inventaire CosyVoice (.cvps), pas les vestiges Qwen3
voicesCursor() marquait une voix « ready » dès que ses embeddings Qwen3 (_voice_prefix/suffix.bin) existaient — des vestiges morts depuis la bascule CosyVoice → des voix fantômes « prête » sans aucun .cvps (incident zelda). Désormais : union (WAV = « à convertir ») ∪ (cosyvoice/*.cvps = « prête ») ; les .bin Qwen3 ne sont plus comptés ; nouvelle colonne cvps_exists (additive). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
613c7efc66
commit
8bcf9f8ebe
|
|
@ -79,6 +79,11 @@ class KazeiaTelemetryProvider : ContentProvider() {
|
||||||
get() = "${com.kazeia.KazeiaApplication.MODELS_DIR}/qwen3-tts-npu"
|
get() = "${com.kazeia.KazeiaApplication.MODELS_DIR}/qwen3-tts-npu"
|
||||||
private const val PREFIX_SUFFIX = "_voice_prefix.bin"
|
private const val PREFIX_SUFFIX = "_voice_prefix.bin"
|
||||||
private const val SUFFIX_SUFFIX = "_voice_suffix.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 {
|
private val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
|
||||||
|
|
@ -526,26 +531,32 @@ class KazeiaTelemetryProvider : ContentProvider() {
|
||||||
private fun voicesCursor(): Cursor {
|
private fun voicesCursor(): Cursor {
|
||||||
val cols = arrayOf(
|
val cols = arrayOf(
|
||||||
"id", "name", "state",
|
"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"
|
"wav_size_bytes", "wav_duration_seconds", "wav_path", "created_at"
|
||||||
)
|
)
|
||||||
val cursor = MatrixCursor(cols)
|
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 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())
|
val wavIds = (wavDir.listFiles { f -> f.name.endsWith(".wav") } ?: emptyArray())
|
||||||
.associateBy { it.nameWithoutExtension.lowercase() }
|
.associateBy { it.nameWithoutExtension.lowercase() }
|
||||||
val prefixIds = (embDir.listFiles { f -> f.name.endsWith(PREFIX_SUFFIX) } ?: emptyArray())
|
val cvpsIds = (cvpsDir.listFiles { f -> f.name.endsWith(CVPS_SUFFIX) } ?: emptyArray())
|
||||||
.associateBy { it.name.removeSuffix(PREFIX_SUFFIX).lowercase() }
|
.associateBy { it.name.removeSuffix(CVPS_SUFFIX).lowercase() }
|
||||||
val ids = (wavIds.keys + prefixIds.keys).sorted()
|
val ids = (wavIds.keys + cvpsIds.keys).sorted()
|
||||||
|
|
||||||
for (id in ids) {
|
for (id in ids) {
|
||||||
val wav = wavIds[id]
|
val wav = wavIds[id]
|
||||||
|
val cvps = cvpsIds[id]
|
||||||
val prefix = File(VOICE_EMB_DIR, "${id}$PREFIX_SUFFIX")
|
val prefix = File(VOICE_EMB_DIR, "${id}$PREFIX_SUFFIX")
|
||||||
val suffix = File(VOICE_EMB_DIR, "${id}$SUFFIX_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 {
|
val state = when {
|
||||||
prefix.exists() && suffix.exists() -> "ready"
|
cvps != null -> "ready"
|
||||||
wav != null -> "recorded"
|
wav != null -> "recorded"
|
||||||
else -> "error"
|
else -> "error"
|
||||||
}
|
}
|
||||||
|
|
@ -557,10 +568,11 @@ class KazeiaTelemetryProvider : ContentProvider() {
|
||||||
if (wav != null) 1 else 0,
|
if (wav != null) 1 else 0,
|
||||||
if (prefix.exists()) 1 else 0,
|
if (prefix.exists()) 1 else 0,
|
||||||
if (suffix.exists()) 1 else 0,
|
if (suffix.exists()) 1 else 0,
|
||||||
|
if (cvps != null) 1 else 0,
|
||||||
wav?.length() ?: 0L,
|
wav?.length() ?: 0L,
|
||||||
durSec,
|
durSec,
|
||||||
wav?.absolutePath ?: "",
|
wav?.absolutePath ?: "",
|
||||||
wav?.lastModified() ?: prefix.lastModified()
|
wav?.lastModified() ?: cvps?.lastModified() ?: 0L
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
return cursor
|
return cursor
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue