Files
FabledScribe/Dockerfile
T
bvandeusen 4a9d8eaa2d fix(docker): download piper voices via Python urllib (curl not in slim)
python:3.14-slim doesn't ship curl or wget. The previous voice-download
step assumed it did and failed with "curl: not found" (exit 127) in
build stage 8.

Replaced with a Docker BuildKit heredoc that runs python3 directly,
using urllib.request.urlretrieve. Python is already installed (it's
the base image), so this needs no additional apt packages and keeps
the image footprint identical. The `# syntax=docker/dockerfile:1`
directive at the top of this file already pulls in a BuildKit
frontend that supports heredoc syntax.

The download itself is unchanged: en_US-amy-medium and en_US-ryan-medium
into /opt/piper-voices, with both .onnx and .onnx.json sidecar files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 08:06:28 -04:00

84 lines
3.1 KiB
Docker

# syntax=docker/dockerfile:1
# Stage 1: Build Vue frontend
FROM node:22-alpine AS build-frontend
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci --quiet
COPY frontend/ .
RUN npm run build
# Stage 2: Python runtime
# Tracks CI image (ci-python:3.14) so test results stay representative.
FROM python:3.14-slim AS runtime
WORKDIR /app
COPY pyproject.toml .
COPY src/ src/
RUN --mount=type=cache,target=/root/.cache/pip \
pip install .
# Speech-to-text (faster-whisper + soundfile). faster-whisper is pure
# Python; the actual inference engine is ctranslate2 (C++) which has
# cp314 wheels as of v4.7.2 (2026-05-19). No torch needed — ctranslate2
# does its own CPU inference. Image add: ~150 MB.
RUN --mount=type=cache,target=/root/.cache/pip \
pip install faster-whisper soundfile
# Text-to-speech (piper-tts). Replaces kokoro, which has been
# stale upstream since April 2025 (requires_python<3.13). Piper depends
# only on onnxruntime (already pulled in for STT via faster-whisper) and
# pathvalidate — total Python overhead is tiny. Voice models are separate
# .onnx + .onnx.json files bundled below.
RUN --mount=type=cache,target=/root/.cache/pip \
pip install piper-tts
# Bundle two default voices in the image so first-run TTS works offline.
# Additional voices can be downloaded at runtime into /data/voices via the
# admin UI (see services/tts.py for the voice-discovery logic).
# Voice catalog: https://huggingface.co/rhasspy/piper-voices
#
# Using Python's urllib instead of curl/wget because python:3.14-slim
# ships neither; python is obviously available. The heredoc requires
# the BuildKit Dockerfile 1.3+ frontend, which the `# syntax=...:1`
# directive at the top of this file already pulls in.
RUN <<'PYEOF' python3
import os, urllib.request
VOICES = ["en_US-amy-medium", "en_US-ryan-medium"]
BASE = "https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US"
TARGET = "/opt/piper-voices"
os.makedirs(TARGET, exist_ok=True)
for v in VOICES:
dataset = v.split("-")[1]
for ext in ("onnx", "onnx.json"):
url = f"{BASE}/{dataset}/medium/{v}.{ext}"
path = os.path.join(TARGET, f"{v}.{ext}")
print(f"Downloading {url}", flush=True)
urllib.request.urlretrieve(url, path)
size = os.path.getsize(path)
print(f" -> {path} ({size:,} bytes)", flush=True)
PYEOF
# Build the fable-mcp wheel so it can be served for download
COPY fable-mcp/ fable-mcp/
RUN --mount=type=cache,target=/root/.cache/pip \
pip install build hatchling \
&& python -m build --wheel ./fable-mcp --outdir /app/dist/ \
&& pip uninstall -y build \
&& rm -rf fable-mcp/
COPY --from=build-frontend /build/dist/ src/fabledassistant/static/
COPY alembic.ini .
COPY alembic/ alembic/
# Ensure Python finds the source tree (where static files live) before site-packages
ENV PYTHONPATH=/app/src
# Version is injected at build time via --build-arg BUILD_VERSION=YY.MM.DD.N
# Falls back to "dev" for local / untagged builds
ARG BUILD_VERSION=dev
ENV APP_VERSION=$BUILD_VERSION
EXPOSE 5000
CMD ["sh", "-c", "alembic upgrade head && hypercorn 'fabledassistant.app:create_app()' --bind 0.0.0.0:5000 --keep-alive 600"]