# Hearthwave v2.25.0 — Portainer stack (pre-built images, no source required) # # QUICK START # ----------- # 0. On the Docker host, populate the volumes with models and voices FIRST: # bash prereq.sh # (Download prereq.sh from https://github.com/Xpiatio/Hearthwave/blob/master/prereq.sh # or check out the repo. Requires only docker — no Python needed on the host.) # # 1. In Portainer: Volumes → Add volume (one for each of the three below). # prereq.sh creates them automatically, so this step is already done if you ran it. # # Volume name | What goes inside # -------------------- | ----------------------------------------------- # hearthwave-data | Config, contacts, users, tokens, journals (auto-created on first run) # hearthwave-voices | Piper ONNX voice files (*.onnx + *.onnx.json) # hearthwave-models | faster-whisper model dir(s) — streaming + optional final-pass # # TWO-TIER (higher RX accuracy): prereq.sh stages a second, larger model for # the full-utterance final pass alongside the streaming model. The default is # large-v3-turbo (~1.6 GB) — the model "auto" prefers: # bash prereq.sh # small.en + large-v3-turbo # bash prereq.sh --final-model distil-large-v3 # faster on long overs # bash prereq.sh --final-model none # single-pass RX # New installs default whisper_model_final="auto" and pick the staged model # up automatically (turbo > distil > large-v3); a persisted "" (explicit # off) stays off until set to "auto" or a model name in Settings. # It lazy-loads on the first finalized utterance and adds ~1.5 GB RAM only # while active — keep that in mind for any backend memory limit you set. # # 2. Set PULSE_UID to your host user's UID (run 'id -u' on the host to check). # The default below is 1000. In Portainer: Stack → Environment variables → add PULSE_UID. # Or edit the volume line directly: - /run/user//pulse:/run/pulse:ro # # 3. Stacks → Add stack → Web editor → paste this file → Deploy. # # FIRST RUN # --------- # Visit http:// — you'll see the Setup screen to create the admin account. # Or set RADIO_TTY_ADMIN_PASS on the backend service to bootstrap headlessly: # environment: # - RADIO_TTY_ADMIN_PASS=your-initial-password # Remove that variable after first startup; the account is persisted in the data volume. # # UPDATING # -------- # Pull new images (change the tag below), then in Portainer: open the stack → Update. # # CUDA (GPU) VARIANT # ------------------ # If the host has an NVIDIA GPU, swap the backend image tag to the -cuda suffix: # image: ghcr.io/xpiatio/hearthwave-backend:v2.25.0-cuda # The CUDA image uses onnxruntime-gpu for accelerated Whisper inference. # Requires the NVIDIA Container Toolkit on the host and the `deploy` section: # deploy: # resources: # reservations: # devices: # - driver: nvidia # count: 1 # capabilities: [gpu] services: backend: image: ghcr.io/xpiatio/hearthwave-backend:v2.25.0 volumes: - hearthwave-data:/data - hearthwave-voices:/app/Voices:ro - hearthwave-models:/app/backend/Models:ro - /run/user/${PULSE_UID:-1000}/pulse:/run/pulse:ro # Host timezone, so times spoken on air and embedded in reports/journals # are local (the container otherwise runs UTC). Non-Linux hosts: remove # this line and set a TZ environment variable instead (e.g. TZ=America/Detroit). - /etc/localtime:/etc/localtime:ro environment: - PULSE_SERVER=unix:/run/pulse/native # Uncomment to create the admin account headlessly on first run: # - RADIO_TTY_ADMIN_PASS=change-me devices: - /dev/snd:/dev/snd restart: unless-stopped networks: - radio healthcheck: test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8765/health')"] interval: 10s timeout: 5s retries: 5 start_period: 30s frontend: image: ghcr.io/xpiatio/hearthwave-frontend:v2.25.0 ports: - "80:8080" volumes: - hearthwave-data:/data:ro depends_on: backend: condition: service_started restart: unless-stopped networks: - radio networks: radio: driver: bridge volumes: hearthwave-data: hearthwave-voices: hearthwave-models: # TO ADD MORE VOICES AFTER DEPLOY: # Re-run prereq.sh with the --voice-only flag: # bash prereq.sh --voice-only # # Or copy a .onnx + .onnx.json pair directly into the volume: # docker run --rm \ # -v hearthwave-voices:/v \ # -v "$(pwd):/src" \ # alpine cp /src/myvoice.onnx /src/myvoice.onnx.json /v/ # # Browse available Piper voices: https://huggingface.co/rhasspy/piper-voices