# frank-tts — the cloned-voice speech façade (dankclaw/voiceservice/app.py). # # Standard library only, so there is nothing to pip-install and nothing to # compile: the image is a python runtime plus ffmpeg (the one binary the app # shells out to, for response_format=mp3) plus one COPY of app.py. Rebuild to # ship a new app.py. # # Build on dankclaw (deploy-remote.sh build_compose_image frank-tts does this, # including --format docker, which the fleet's other local builds also pass): # podman build --format docker -t franksdank/frank-tts:latest \ # -f dankclaw/voiceservice/Containerfile . # # BASE PINNED BY DIGEST, like every other image this fleet runs from a # registry: a tag moves under a rebuild and a voice endpoint that changes # python or ffmpeg mid-week is a debug session nobody asked for. The digest is # the multi-arch INDEX of python:3.12-alpine as published 2026-10-18 (amd64 + # arm64 on linux); Dankclaw resolves the amd64 entry. # # WHY 3.12: the fleet's ceiling for this app is python <= 3.12 (single file, # no build step); the alpine flavour also keeps the image in the tens of MB # and ships busybox `wget`, which is what the quadlet unit's HealthCmd runs — # so no HEALTHCHECK belongs here (the probe lives in the unit, as in # alertmanager/prometheus; only distroless bases need it baked in). FROM docker.io/library/python:3.12-alpine@sha256:1b668429b3511ab407d8e00648891631b0b1a4d7e15e3ca70f38ab5b91ad4ab4 # ffmpeg: mp3 output. The app always asks the upstream for wav and re-encodes # on the way out, so ffmpeg is the only external program in the picture. RUN apk add --no-cache ffmpeg # Unbuffered stdout: the unit's journal must show the "listening on" line (and # any backend error) the moment it happens, not when the buffer fills. ENV PYTHONUNBUFFERED=1 COPY dankclaw/voiceservice/app.py /app/app.py # Non-root. The voice packs are bind-mounted read-only, so this user only ever # reads them — they must be world-readable (the pack builder writes 644/755). # The one thing it writes is its per-request temp dir under /tmp. RUN adduser -D -u 10000 -h /app -s /sbin/nologin shim USER shim EXPOSE 7772 CMD ["python3", "/app/app.py"]