From 7e14abedb8b6169aa518099bd0cef8db5b456ea3 Mon Sep 17 00:00:00 2001 From: jenkins Date: Mon, 10 Aug 2026 01:00:20 -0300 Subject: [PATCH] fix(hermes): expose baked voice models to runtimes --- dockerfiles/Dockerfile.hermes-jetson-stt | 3 ++- dockerfiles/Dockerfile.hermes-jetson-tts | 3 ++- services/hermes/voice-deployment.yaml | 4 ++-- testing/tests/test_hermes_chat_quality.py | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dockerfiles/Dockerfile.hermes-jetson-stt b/dockerfiles/Dockerfile.hermes-jetson-stt index 0e4c6db96..fef9bd6c7 100644 --- a/dockerfiles/Dockerfile.hermes-jetson-stt +++ b/dockerfiles/Dockerfile.hermes-jetson-stt @@ -14,6 +14,7 @@ RUN python3 -m pip install --no-cache-dir --force-reinstall --no-deps \ ADD --checksum=sha256:aff26ae408abcba5fbf8813c21e62b0941638c5f6eebfb145be0c9839262a19a --chmod=0444 \ https://openaipublic.azureedge.net/main/whisper/models/aff26ae408abcba5fbf8813c21e62b0941638c5f6eebfb145be0c9839262a19a/large-v3-turbo.pt \ /opt/models/whisper/large-v3-turbo.pt +RUN chmod 0555 /opt/models /opt/models/whisper COPY dockerfiles/hermes-jetson-stt-server.py /opt/atlas/hermes-jetson-stt-server.py RUN chmod 0555 /opt/atlas/hermes-jetson-stt-server.py @@ -24,7 +25,7 @@ WORKDIR /opt/atlas # Import the Xavier CUDA stack and confirm Whisper resolves the baked artifact. # Full GPU warm-up is covered by the Kubernetes startup probe on titan-21. -RUN python3 -c "from pathlib import Path; import torch, whisper; print(whisper.__file__, whisper.__version__, whisper.available_models()); assert 'large-v3-turbo' in whisper.available_models(); assert Path('/opt/models/whisper/large-v3-turbo.pt').is_file(); print(torch.__version__)" +RUN python3 -c "import stat; from pathlib import Path; import torch, whisper; p=Path('/opt/models/whisper'); print(whisper.__file__, whisper.__version__, whisper.available_models()); assert 'large-v3-turbo' in whisper.available_models(); assert stat.S_IMODE(p.stat().st_mode)==0o555; assert stat.S_IMODE((p/'large-v3-turbo.pt').stat().st_mode)==0o444; print(torch.__version__)" ENV HERMES_STT_HOST=0.0.0.0 \ HERMES_STT_PORT=9000 \ diff --git a/dockerfiles/Dockerfile.hermes-jetson-tts b/dockerfiles/Dockerfile.hermes-jetson-tts index abd29cbec..cf313ea25 100644 --- a/dockerfiles/Dockerfile.hermes-jetson-tts +++ b/dockerfiles/Dockerfile.hermes-jetson-tts @@ -12,13 +12,14 @@ ADD --checksum=sha256:4cabf7c3a638017137f34a1516522032d4fe3f38228a843cc9b764ddcb ADD --checksum=sha256:db42b97d9859f257bc1561b8ed980e7fb2398402050a74ddd6cbec931a92412f --chmod=0444 \ https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/high/en_US-lessac-high.onnx.json?download=true \ /opt/models/piper/en_US-lessac-high.onnx.json +RUN chmod 0555 /opt/models /opt/models/piper COPY dockerfiles/hermes-jetson-tts-server.py /opt/atlas/hermes-jetson-tts-server.py RUN chmod 0555 /opt/atlas/hermes-jetson-tts-server.py # Load the actual pinned voice during the ARM64 build. This catches package or # model-format drift before the image can reach Flux. -RUN python -c "from pathlib import Path; from piper import PiperVoice; p=Path('/opt/models/piper'); v=PiperVoice.load(p/'en_US-lessac-high.onnx', p/'en_US-lessac-high.onnx.json', use_cuda=False, download_dir=p); assert v.config.sample_rate > 0" +RUN python -c "import stat; from pathlib import Path; from piper import PiperVoice; p=Path('/opt/models/piper'); assert stat.S_IMODE(p.stat().st_mode)==0o555; assert stat.S_IMODE((p/'en_US-lessac-high.onnx').stat().st_mode)==0o444; v=PiperVoice.load(p/'en_US-lessac-high.onnx', p/'en_US-lessac-high.onnx.json', use_cuda=False, download_dir=p); assert v.config.sample_rate > 0" ENV HERMES_TTS_HOST=0.0.0.0 \ HERMES_TTS_PORT=9001 \ diff --git a/services/hermes/voice-deployment.yaml b/services/hermes/voice-deployment.yaml index a65854f5b..1f249032b 100644 --- a/services/hermes/voice-deployment.yaml +++ b/services/hermes/voice-deployment.yaml @@ -29,7 +29,7 @@ spec: kubernetes.io/hostname: titan-21 containers: - name: stt - image: registry.bstein.dev/bstein/hermes-jetson-stt@sha256:a67494014716a65152b7595122b1717a742db206c6f556c740fecc110452f65b + image: registry.bstein.dev/bstein/hermes-jetson-stt@sha256:d70bc0892bfce7dc474b24c62d2427a22c6022d0d406c349fcb83d82130de768 imagePullPolicy: IfNotPresent ports: - {name: http, containerPort: 9000, protocol: TCP} @@ -121,7 +121,7 @@ spec: kubernetes.io/hostname: titan-20 containers: - name: tts - image: registry.bstein.dev/bstein/hermes-jetson-tts@sha256:6483ca4e89d0663c770b7b3e3c9c9ff85d457ae877f2e83c55765cadc901d9b7 + image: registry.bstein.dev/bstein/hermes-jetson-tts@sha256:1020a73e8941932dd071e5dcc66b5583ebb9376f9ee2fd1711b50e026eb88467 imagePullPolicy: IfNotPresent ports: - {name: http, containerPort: 9001, protocol: TCP} diff --git a/testing/tests/test_hermes_chat_quality.py b/testing/tests/test_hermes_chat_quality.py index 2453209ba..9f65f105c 100644 --- a/testing/tests/test_hermes_chat_quality.py +++ b/testing/tests/test_hermes_chat_quality.py @@ -190,10 +190,12 @@ def test_voice_models_are_baked_and_runtime_has_no_public_egress(): tts_dockerfile = (ROOT / "dockerfiles" / "Dockerfile.hermes-jetson-tts").read_text() assert "ADD --checksum=sha256:aff26ae4" in stt_dockerfile assert "--chmod=0444" in stt_dockerfile + assert "chmod 0555 /opt/models /opt/models/whisper" in stt_dockerfile assert "HERMES_STT_CACHE=/opt/models/whisper" in stt_dockerfile assert "ADD --checksum=sha256:4cabf7c3" in tts_dockerfile assert "ADD --checksum=sha256:db42b97d" in tts_dockerfile assert tts_dockerfile.count("--chmod=0444") == 2 + assert "chmod 0555 /opt/models /opt/models/piper" in tts_dockerfile assert "HERMES_TTS_CACHE=/opt/models/piper" in tts_dockerfile tts_server = (ROOT / "dockerfiles" / "hermes-jetson-tts-server.py").read_text() assert "download_voice" not in tts_server