-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: add Docker + web deployment support #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
|
|
||
|
Comment on lines
+11
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify mount + host directory writeability prerequisites.
set -e
echo "Checking compose mount definition..."
rg -n '^\s*-\s*\./output:/app/data/generations' docker-compose.yml
echo "Checking explicit user override in compose..."
rg -n '^\s*user:\s*' docker-compose.yml || true
echo "Checking host output directory permissions (if present)..."
if [ -d output ]; then
stat -c '%u:%g %a %n' output
[ -w output ] && echo "output is writable by current host user" || echo "output is NOT writable by current host user"
else
echo "output directory is missing (Docker may create it with root ownership depending on host setup)."
fiRepository: jamiepine/voicebox Length of output: 341 🏁 Script executed: git ls-files | grep -i dockerfileRepository: jamiepine/voicebox Length of output: 72 🏁 Script executed: cat -n DockerfileRepository: jamiepine/voicebox Length of output: 2957 🏁 Script executed: cat -n docker-compose.ymlRepository: jamiepine/voicebox Length of output: 1277 Fix bind-mount write permissions for generated audio output. The container runs as non-root user Ensure 🤖 Prompt for AI Agents |
||
| # 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 | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| networks: | ||
| - voicebox-net | ||
|
|
||
| deploy: | ||
| resources: | ||
| limits: | ||
| cpus: '4' | ||
| memory: 8G | ||
|
|
||
| networks: | ||
| voicebox-net: | ||
| driver: bridge | ||
|
|
||
| volumes: | ||
| voicebox-data: | ||
| huggingface-cache: | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: jamiepine/voicebox
Length of output: 326
Pin GitHub dependencies to immutable refs across the repository.
Line 37 in the Dockerfile and lines 21-22 in backend/requirements.txt install from moving branches/HEAD, which makes builds non-reproducible and weakens supply-chain guarantees.
All three instances require pinning to a commit SHA:
Dockerfile:37:git+https://github.com/QwenLM/Qwen3-TTS.gitbackend/requirements.txt:21:linacodec @ git+https://github.com/ysharma3501/LinaCodec.gitbackend/requirements.txt:22:Zipvoice @ git+https://github.com/ysharma3501/LuxTTS.git🔧 Proposed fix example (Dockerfile)
For requirements.txt, append
@<commit-sha>to each URL.🤖 Prompt for AI Agents