tts: seed extension-less voice copies so tripit's bare stems resolve
All checks were successful
ci/woodpecker/push/default Pipeline was successful
ci/woodpecker/push/build-cli Pipeline was successful

First live drain failed all 27 queued narrations with 404 'Voice file
'Emily' not found': tripit's catalog sends bare stems (Emily) but the
devnen server resolves the voice as a literal filename (Emily.wav) in
predefined_voices_path then reference_audio — no stem fallback exists
upstream (HEAD == our pinned sha), and symlinks can't bridge it because
safe_resolve_within() resolves them out of the containment check.

New initContainer on the chatterbox deployment copies the 28 bundled
voices to /data/reference_audio/<stem> on the PVC (second lookup path).
Same image as the main container so no extra pull; idempotent; ~15 MB.
Verified live before committing: an extension-less copy synthesizes
200 audio/mp3 (5.3s warm) where voice=Emily 404'd.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-06-12 20:41:50 +00:00
parent bb0f9f59ef
commit 98f1f7fc24

View file

@ -374,6 +374,36 @@ resource "kubernetes_deployment" "chatterbox" {
name = kubernetes_secret.ghcr_credentials.metadata[0].name
}
# tripit's voice catalog sends bare stems ("Emily"); the server resolves
# the voice as a LITERAL filename in predefined_voices_path THEN in
# reference_audio (404 otherwise, observed 2026-06-12: all 27 queued
# narrations failed with "Voice file 'Emily' not found"). Upstream HEAD
# (= our pinned sha) has no stem fallback, and symlinks can't bridge it
# because safe_resolve_within() .resolve()s them out of the containment
# check. So seed REAL extension-less copies of the bundled voices into
# reference_audio on the PVC (the second lookup path). Same image as the
# main container = no extra pull; idempotent; ~15 MB once. The engine
# sniffs audio content, not extensions.
init_container {
name = "seed-stem-voices"
image = local.image
command = ["sh", "-c", <<-EOC
set -eu
mkdir -p /data/reference_audio
for f in /app/voices/*.wav /app/voices/*.mp3; do
[ -e "$f" ] || continue
stem="$(basename "$f")"; stem="$${stem%.*}"
[ -e "/data/reference_audio/$stem" ] || cp "$f" "/data/reference_audio/$stem"
done
echo "reference_audio seeded:"; ls /data/reference_audio
EOC
]
volume_mount {
name = "models"
mount_path = "/data"
}
}
container {
name = "chatterbox-tts"
image = local.image