diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e0c4637 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# Version control +.git +.github +.gitignore + +# Desktop-only (not needed in web container) +tauri/ +landing/ +docs/ +mlx-test/ +scripts/ + +# Dependencies & build artifacts (rebuilt in Docker) +node_modules/ +__pycache__/ +*.pyc +*.pyo +*.egg-info/ +dist/ +build/ +*.spec + +# Data (will be bind-mounted) +data/ +backend/data/ + +# IDE & OS +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store +Thumbs.db + +# Config files not needed in container +biome.json +.biomeignore +.bumpversion.cfg +.npmrc +Makefile +CHANGELOG.md +CONTRIBUTING.md +SECURITY.md +LICENSE +README.md +backend/README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4705f98 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,79 @@ +# ============================================================ +# Voicebox — Local TTS Server with Web UI (CPU) +# 3-stage build: Frontend → Python deps → Runtime +# ============================================================ + +# === Stage 1: Build frontend === +FROM oven/bun:1 AS frontend + +WORKDIR /build + +# Copy workspace config and frontend source +COPY package.json bun.lock ./ +COPY app/ ./app/ +COPY web/ ./web/ + +# Strip workspaces not needed for web build, and fix trailing comma +RUN sed -i '/"tauri"/d; /"landing"/d' package.json && \ + sed -i -z 's/,\n ]/\n ]/' package.json +RUN bun install --no-save +# Build frontend (skip tsc — upstream has pre-existing type errors) +RUN cd web && bunx --bun vite build + + +# === Stage 2: Build Python dependencies === +FROM python:3.11-slim AS backend-builder + +WORKDIR /build + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +COPY backend/requirements.txt . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt +RUN pip install --no-cache-dir --prefix=/install \ + git+https://github.com/QwenLM/Qwen3-TTS.git + + +# === Stage 3: Runtime === +FROM python:3.11-slim + +# Create non-root user for security +RUN groupadd -r voicebox && \ + useradd -r -g voicebox -m -s /bin/bash voicebox + +WORKDIR /app + +# Install only runtime system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ffmpeg \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Copy installed Python packages from builder stage +COPY --from=backend-builder /install /usr/local + +# Copy backend application code +COPY --chown=voicebox:voicebox backend/ /app/backend/ + +# Copy built frontend from frontend stage +COPY --from=frontend --chown=voicebox:voicebox /build/web/dist /app/frontend/ + +# Create data directories owned by non-root user +RUN mkdir -p /app/data/generations /app/data/profiles /app/data/cache \ + && chown -R voicebox:voicebox /app/data + +# Switch to non-root user +USER voicebox + +# Expose the API port +EXPOSE 17493 + +# Health check — auto-restart if the server hangs +HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \ + CMD curl -f http://localhost:17493/health || exit 1 + +# Start the FastAPI server +CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "17493"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0a6fe36 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +services: + voicebox: + build: . + container_name: voicebox + restart: unless-stopped + + ports: + # Bind to localhost only for security + - "127.0.0.1:17493:17493" + + volumes: + # Bind-mount for generated audio (customize the host path as needed) + # Host side: ./output/ + # Container side: /app/data/generations/ + - ./output:/app/data/generations + + # Named volume for profiles, DB, cache (persists across container restarts) + - voicebox-data:/app/data + + # HuggingFace model cache (so models aren't re-downloaded on rebuild) + - huggingface-cache:/home/voicebox/.cache/huggingface + + environment: + - TTS_MODE=local + - LOG_LEVEL=info + + networks: + - voicebox-net + + deploy: + resources: + limits: + cpus: '4' + memory: 8G + +networks: + voicebox-net: + driver: bridge + +volumes: + voicebox-data: + huggingface-cache: