WIP: fix(hermes-voice): switch Atlas Piper TTS to hfc_female, bake amy as alternate #24

Closed
hermes-automation wants to merge 1 commits from hermes/tts-voice-hfc-female into main

Summary

Brad's 2026-08-20 decision: switch the private Atlas Piper TTS voice for the
Hermes chat WebUI from Lessac to a warmer, pleasant feminine voice.

  • Default: en_US-hfc_female-medium
  • Alternate baked into the same image: en_US-amy-medium (selectable later
    without another Jenkins build)
  • Lessac models (high/medium/low) are kept, not deleted — this
    wasn't required for image size. Image growth: +120.6 MiB
    (2 new medium voices x (onnx + onnx.json), checksummed against the same
    pinned rhasspy/piper-voices@ea046e8458f6acd997706d6e6066a022b42f6fb1
    revision already used for Lessac). All four new sha256 checksums were
    verified locally against the freshly downloaded upstream files before
    being pinned in the Dockerfile.

Verified behaviour — read before merging

The Piper server (dockerfiles/hermes-jetson-tts-server.py:59-72) reads
only input/text and speed from the POST body. The "voice" field
the WebUI sends is ignored by the server. The audible voice is
determined solely by the HERMES_TTS_VOICE env var at process start.
The WebUI's hardcoded voice string is updated here for honesty (it no longer
claims Lessac), but HERMES_TTS_VOICE remains the effective control
changing the WebUI string alone does nothing to the audio.

Sites changed

  1. dockerfiles/Dockerfile.hermes-jetson-tts — added checksum-pinned
    en_US-hfc_female-medium and en_US-amy-medium (onnx + onnx.json) from
    the existing pinned revision; updated ENV HERMES_TTS_VOICE default;
    extended the build-time PiperVoice.load assertion to cover all 5 models
    (3 Lessac + hfc_female + amy).
  2. dockerfiles/hermes-jetson-tts-server.py:20VOICE_NAME default
    aligned from en_US-lessac-high (which disagreed with the Dockerfile's
    prior default of en_US-lessac-medium) to en_US-hfc_female-medium.
  3. services/hermes/voice-deployment.yamlHERMES_TTS_VOICE env var and
    the ai.bstein.dev/model annotation updated to hfc_female.
  4. dockerfiles/hermes-webui-atlas-patch.py:66 — hardcoded voice string
    aligned (fail-closed replace_exact patching preserved).
  5. testing/tests/test_hermes_chat_quality.py — updated assertions for the
    new default voice, checksum count, and the 4 new checksums.

Grepped the whole repo for lessac post-change: every remaining hit is in
Dockerfile.hermes-jetson-tts (the retained Lessac ADD/assert lines) — no
doc/catalog (including services/hermes/NOTES.md) names the voice.

Rollout-coupling hazard — required merge sequence

The server fails closed if HERMES_TTS_VOICE names a model not baked
into the image (hermes-jetson-tts-server.py:99-100, "baked Piper voice is
missing"). voice-deployment.yaml:126 pins the TTS image by digest, so
the env var change here and the new image digest must roll out together,
or image-first — never env-first. If the env var reaches the cluster before
an image containing en_US-hfc_female-medium does, the TTS pod crash-loops.

Required sequence after this PR is approved and merged:

  1. Merge this PR into main.
  2. Jenkins builds hermes-jetson-tts from the new Dockerfile and publishes a
    new image digest.
  3. Bump the digest pin in services/hermes/voice-deployment.yaml:126 to the
    new build (separate follow-up commit/PR, since the digest isn't known
    until the build completes).
  4. Flux reconciles the digest bump and the env var together in the same
    apply.

Do not let the env var change here reach the cluster ahead of a
hermes-jetson-tts image that actually contains en_US-hfc_female-medium.

Verification

  • .venv/bin/python -m pytest testing/tests/test_hermes_chat_quality.py -q
    — 12 passed.
  • .venv/bin/python -m pytest testing/ -q — 2537 passed, 4 skipped
    (environment-gated: no read-only cluster access, no visudo), 4 failed —
    all 4 failures reproduce identically on origin/main with none of this
    branch's changes applied (live-cluster CPU-request drift in
    test_hermes_agent_layout.py, a flaky HTTP-error-path assertion in
    test_hermes_gitea_pr_integration.py, and a live kanban config drift in
    test_hermes_kanban_supervisor.py) — unrelated to this change.
  • kustomize build services/hermes — succeeds; rendered output confirms
    HERMES_TTS_VOICE=en_US-hfc_female-medium and the updated model
    annotation.
  • sha256 checksums for the 2 new voices were verified against fresh
    downloads from the pinned Hugging Face revision (deterministic, confirmed
    by re-downloading and re-hashing).

🤖 Generated with Claude Code

## Summary Brad's 2026-08-20 decision: switch the private Atlas Piper TTS voice for the Hermes chat WebUI from Lessac to a warmer, pleasant feminine voice. - Default: `en_US-hfc_female-medium` - Alternate baked into the same image: `en_US-amy-medium` (selectable later without another Jenkins build) - Lessac models (`high`/`medium`/`low`) are **kept, not deleted** — this wasn't required for image size. Image growth: **+120.6 MiB** (2 new medium voices x (onnx + onnx.json), checksummed against the same pinned `rhasspy/piper-voices@ea046e8458f6acd997706d6e6066a022b42f6fb1` revision already used for Lessac). All four new sha256 checksums were verified locally against the freshly downloaded upstream files before being pinned in the Dockerfile. ## Verified behaviour — read before merging The Piper server (`dockerfiles/hermes-jetson-tts-server.py:59-72`) reads **only** `input`/`text` and `speed` from the POST body. The `"voice"` field the WebUI sends is **ignored** by the server. The audible voice is determined **solely** by the `HERMES_TTS_VOICE` env var at process start. The WebUI's hardcoded voice string is updated here for honesty (it no longer claims Lessac), but **`HERMES_TTS_VOICE` remains the effective control** — changing the WebUI string alone does nothing to the audio. ## Sites changed 1. `dockerfiles/Dockerfile.hermes-jetson-tts` — added checksum-pinned `en_US-hfc_female-medium` and `en_US-amy-medium` (onnx + onnx.json) from the existing pinned revision; updated `ENV HERMES_TTS_VOICE` default; extended the build-time `PiperVoice.load` assertion to cover all 5 models (3 Lessac + hfc_female + amy). 2. `dockerfiles/hermes-jetson-tts-server.py:20` — `VOICE_NAME` default aligned from `en_US-lessac-high` (which disagreed with the Dockerfile's prior default of `en_US-lessac-medium`) to `en_US-hfc_female-medium`. 3. `services/hermes/voice-deployment.yaml` — `HERMES_TTS_VOICE` env var and the `ai.bstein.dev/model` annotation updated to `hfc_female`. 4. `dockerfiles/hermes-webui-atlas-patch.py:66` — hardcoded voice string aligned (fail-closed `replace_exact` patching preserved). 5. `testing/tests/test_hermes_chat_quality.py` — updated assertions for the new default voice, checksum count, and the 4 new checksums. Grepped the whole repo for `lessac` post-change: every remaining hit is in `Dockerfile.hermes-jetson-tts` (the retained Lessac ADD/assert lines) — no doc/catalog (including `services/hermes/NOTES.md`) names the voice. ## Rollout-coupling hazard — required merge sequence The server **fails closed** if `HERMES_TTS_VOICE` names a model not baked into the image (`hermes-jetson-tts-server.py:99-100`, "baked Piper voice is missing"). `voice-deployment.yaml:126` pins the TTS image **by digest**, so the env var change here and the new image digest **must roll out together**, or image-first — never env-first. If the env var reaches the cluster before an image containing `en_US-hfc_female-medium` does, the TTS pod crash-loops. Required sequence after this PR is approved and merged: 1. Merge this PR into `main`. 2. Jenkins builds `hermes-jetson-tts` from the new Dockerfile and publishes a new image digest. 3. Bump the digest pin in `services/hermes/voice-deployment.yaml:126` to the new build (separate follow-up commit/PR, since the digest isn't known until the build completes). 4. Flux reconciles the digest bump and the env var together in the same apply. Do **not** let the env var change here reach the cluster ahead of a `hermes-jetson-tts` image that actually contains `en_US-hfc_female-medium`. ## Verification - `.venv/bin/python -m pytest testing/tests/test_hermes_chat_quality.py -q` — 12 passed. - `.venv/bin/python -m pytest testing/ -q` — 2537 passed, 4 skipped (environment-gated: no read-only cluster access, no `visudo`), 4 failed — all 4 failures reproduce identically on `origin/main` with none of this branch's changes applied (live-cluster CPU-request drift in `test_hermes_agent_layout.py`, a flaky HTTP-error-path assertion in `test_hermes_gitea_pr_integration.py`, and a live kanban config drift in `test_hermes_kanban_supervisor.py`) — unrelated to this change. - `kustomize build services/hermes` — succeeds; rendered output confirms `HERMES_TTS_VOICE=en_US-hfc_female-medium` and the updated model annotation. - sha256 checksums for the 2 new voices were verified against fresh downloads from the pinned Hugging Face revision (deterministic, confirmed by re-downloading and re-hashing). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hermes-automation added 1 commit 2026-08-20 17:38:45 +00:00
Brad's 2026-08-20 decision: default the private Hermes chat TTS voice to a
warmer, pleasant feminine voice (en_US-hfc_female-medium) instead of Lessac.
en_US-amy-medium is baked into the same image as a selectable alternate so
the choice can be revisited without another Jenkins build. Lessac models are
kept (not deleted) since the task didn't require reclaiming image size; the
image grows by ~120.6 MiB (2 medium voices, onnx+json, from the pinned
rhasspy/piper-voices revision already used for lessac).

The Piper server only reads HERMES_TTS_VOICE at process start; the "voice"
field in the WebUI's request body is not consulted by the server
(dockerfiles/hermes-jetson-tts-server.py:59-72). That WebUI string is aligned
here for honesty, but the env var remains the effective control -- align
image digest and env var rollout order (see PR description).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Owner

Amy should be english primary voice

Amy should be english primary voice
bstein closed this pull request 2026-08-20 18:19:47 +00:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: titan/atlas-iac#24
No description provided.