2026-08-10 00:42:37 -03:00
# syntax=docker/dockerfile:1
# dockerfiles/Dockerfile.hermes-jetson-tts
FROM python:3.11-slim-bookworm@sha256:d29f48a31a8b408ed19272ca1e7b10ebae13b240a27e862d3d4217c528e2e0c3
RUN python -m pip install --no-cache-dir piper-tts= = 1.5.0
# Pin the voice data in the image so synthesis has no runtime dependency on
# Hugging Face or mutable model metadata.
ADD --checksum= sha256:4cabf7c3a638017137f34a1516522032d4fe3f38228a843cc9b764ddcbcd9e09 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/high/en_US-lessac-high.onnx?download= true \
/opt/models/piper/en_US-lessac-high.onnx
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
2026-08-10 01:21:51 -03:00
ADD --checksum= sha256:5efe09e69902187827af646e1a6e9d269dee769f9877d17b16b1b46eeaaf019f --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/medium/en_US-lessac-medium.onnx?download= true \
/opt/models/piper/en_US-lessac-medium.onnx
ADD --checksum= sha256:efe19c417bed055f2d69908248c6ba650fa135bc868b0e6abb3da181dab690a0 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/medium/en_US-lessac-medium.onnx.json?download= true \
/opt/models/piper/en_US-lessac-medium.onnx.json
ADD --checksum= sha256:f7d01dde371555732c4c314111ac79672b1a5ce2fc19266ab42178fd8df7f375 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/low/en_US-lessac-low.onnx?download= true \
/opt/models/piper/en_US-lessac-low.onnx
ADD --checksum= sha256:45754dfdebb3b8661c3fc564713772deec6e064feeb5b4e9594857dc7305193a --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/lessac/low/en_US-lessac-low.onnx.json?download= true \
/opt/models/piper/en_US-lessac-low.onnx.json
2026-08-20 18:53:43 +00:00
# Multilingual chat voice policy: English -> amy, Russian -> irina, Spanish ->
# claude (Mexican Spanish, the only "claude" voice rhasspy/piper-voices
# publishes; there is no es_ES-claude).
ADD --checksum= sha256:b3a6e47b57b8c7fbe6a0ce2518161a50f59a9cdd8a50835c02cb02bdd6206c18 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/amy/medium/en_US-amy-medium.onnx?download= true \
/opt/models/piper/en_US-amy-medium.onnx
ADD --checksum= sha256:95a23eb4d42909d38df73bb9ac7f45f597dbfcde2d1bf9526fdeaf5466977d77 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/en/en_US/amy/medium/en_US-amy-medium.onnx.json?download= true \
/opt/models/piper/en_US-amy-medium.onnx.json
ADD --checksum= sha256:8ff38212d23da300bbe3705c645e6e5b9475f0bfde01558eb17813e22acaaaaa --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/ru/ru_RU/irina/medium/ru_RU-irina-medium.onnx?download= true \
/opt/models/piper/ru_RU-irina-medium.onnx
ADD --checksum= sha256:c2ec28bb38e2b59e93b959b3e40348c1afebbd272f30fed5d41205d08e98a9d7 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/ru/ru_RU/irina/medium/ru_RU-irina-medium.onnx.json?download= true \
/opt/models/piper/ru_RU-irina-medium.onnx.json
ADD --checksum= sha256:3ef40a71ea63852cd8ab7e6fa7d2ecdcfa67a0b47c9c48e3f10e02ee02083ea0 --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/es/es_MX/claude/high/es_MX-claude-high.onnx?download= true \
/opt/models/piper/es_MX-claude-high.onnx
ADD --checksum= sha256:1afc81f703c0e4cb3b4d7c0dca096b8b54a98806807f0170cf5eb5557723c12d --chmod= 0444 \
https://huggingface.co/rhasspy/piper-voices/resolve/ea046e8458f6acd997706d6e6066a022b42f6fb1/es/es_MX/claude/high/es_MX-claude-high.onnx.json?download= true \
/opt/models/piper/es_MX-claude-high.onnx.json
2026-08-10 01:00:20 -03:00
RUN chmod 0555 /opt/models /opt/models/piper
2026-08-10 00:42:37 -03:00
COPY dockerfiles/hermes-jetson-tts-server.py /opt/atlas/hermes-jetson-tts-server.py
2026-08-23 22:13:52 -03:00
COPY dockerfiles/hermes_jetson_tts_cues.py /opt/atlas/hermes_jetson_tts_cues.py
RUN chmod 0555 /opt/atlas/hermes-jetson-tts-server.py /opt/atlas/hermes_jetson_tts_cues.py
2026-08-10 00:42:37 -03:00
2026-08-20 18:53:43 +00:00
# Load every pinned voice during the ARM64 build, including the three baked
# for the multilingual chat policy. This catches package or model-format
# drift before the image can reach Flux.
RUN python -c "import stat; from pathlib import Path; from piper import PiperVoice; p=Path('/opt/models/piper'); models=[p/'en_US-lessac-high.onnx',p/'en_US-lessac-medium.onnx',p/'en_US-lessac-low.onnx',p/'en_US-amy-medium.onnx',p/'ru_RU-irina-medium.onnx',p/'es_MX-claude-high.onnx']; assert stat.S_IMODE(p.stat().st_mode)==0o555; assert all(stat.S_IMODE(model.stat().st_mode)==0o444 for model in models); voices=[PiperVoice.load(model,Path(str(model)+'.json'),use_cuda=False,download_dir=p) for model in models]; assert all(voice.config.sample_rate>0 for voice in voices)"
2026-08-10 00:42:37 -03:00
ENV HERMES_TTS_HOST = 0 .0.0.0 \
HERMES_TTS_PORT = 9001 \
2026-08-20 18:53:43 +00:00
HERMES_TTS_VOICE = en_US-amy-medium \
2026-08-10 00:42:37 -03:00
HERMES_TTS_CACHE = /opt/models/piper \
OMP_NUM_THREADS = 2 \
PYTHONDONTWRITEBYTECODE = 1 \
PYTHONUNBUFFERED = 1
EXPOSE 9001
ENTRYPOINT [ "python" , "/opt/atlas/hermes-jetson-tts-server.py" ]