Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Version control
.git
.gitignore

# Desktop/native (not needed for Docker)
tauri/
apps/
landing/

# Python artifacts
backend/venv/
backend/__pycache__/
backend/**/__pycache__/
backend/*.pyc
backend/*.spec
backend/data/

# Node artifacts
node_modules/
app/node_modules/
web/node_modules/
web/dist/

# Build artifacts
dist/
*.egg-info/

# IDE/OS
.vscode/
.idea/
.DS_Store

# Docs
docs/
*.md
!backend/requirements*.txt
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Self-documenting help system with `make help`
- Colored output for better readability
- Supports parallel development server execution
- **Docker Support** - Dockerfile and docker-compose.yml for containerized deployment
- Three compose configurations: full stack, backend-only, and web-only
- NVIDIA GPU support with optional CUDA acceleration
- Persistent volumes for data and HuggingFace model cache
- Health check endpoint integration

### Changed
- **README** - Added Makefile reference and updated Quick Start with Makefile-based setup instructions alongside manual setup
Expand Down
31 changes: 31 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM pytorch/pytorch:2.6.0-cuda12.6-cudnn9-runtime

# System dependencies:
# git - required for pip install from GitHub (qwen-tts)
# libsndfile1 - required by soundfile (audio I/O)
# ffmpeg - required by librosa (audio processing)
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
libsndfile1 \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

ENV PYTHONUNBUFFERED=1
ENV HF_HOME=/root/.cache/huggingface

# Install Python dependencies
COPY backend/requirements.txt backend/requirements.txt
RUN pip install --no-cache-dir -r backend/requirements.txt \
&& pip install --no-cache-dir git+https://github.com/QwenLM/Qwen3-TTS.git

# Copy backend source
COPY backend/ backend/

# Data volume mount point
RUN mkdir -p /app/data

EXPOSE 8000

ENTRYPOINT ["python", "-m", "backend.main", "--host", "0.0.0.0", "--port", "8000", "--data-dir", "/app/data"]
34 changes: 34 additions & 0 deletions Dockerfile.web
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Stage 1: Build the web frontend
FROM oven/bun:1 AS build

WORKDIR /app

# Copy workspace root config
COPY package.json bun.lock ./

# Copy the workspaces needed for the build
COPY app/ app/
COPY web/ web/

# Create stub package.json for workspaces we don't need but bun requires
RUN mkdir -p tauri && echo '{"name":"@voicebox/tauri","version":"0.0.0","private":true}' > tauri/package.json
RUN mkdir -p landing && echo '{"name":"@voicebox/landing","version":"0.0.0","private":true}' > landing/package.json

# Install dependencies
RUN bun install

# Build the web frontend (skip tsc type checking — Vite transpiles independently)
RUN cd web && bunx vite build

# Stage 2: Serve with Nginx
FROM nginx:stable-alpine

# Copy built assets
COPY --from=build /app/web/dist /usr/share/nginx/html

# Copy Nginx config and entrypoint
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY docker/web-entrypoint.sh /docker-entrypoint.d/40-backend-url.sh
RUN chmod +x /docker-entrypoint.d/40-backend-url.sh

EXPOSE 3000
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,79 @@ Voicebox is available now for macOS and Windows.

---

## Docker

Run Voicebox in Docker — no Python, Bun, or system dependencies required.

### Quick Start

```bash
# Clone and start both backend + web UI
git clone https://github.com/jamiepine/voicebox.git
cd voicebox
docker compose up -d
```

- **API**: http://localhost:8000 (Swagger docs at http://localhost:8000/docs)
- **Web UI**: http://localhost:3000

Verify the backend is running:

```bash
curl http://localhost:8000/health
```

### Compose Configurations

| Configuration | Command | Description |
|---------------|---------|-------------|
| **Full stack** | `docker compose up -d` | Backend + Web UI |
| **Backend only** | `docker compose -f docker-compose.backend.yml up -d` | API server only |
| **Web only** | `BACKEND_URL=http://my-server:8000 docker compose -f docker-compose.web.yml up -d` | Frontend pointing to existing backend |

### GPU Support

For NVIDIA GPU acceleration, install the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html), then uncomment the `deploy` section in `docker-compose.yml`:

```yaml
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
```

The backend auto-detects GPU availability at runtime — it works on CPU without any changes.

### Data Persistence

| Volume | Purpose |
|--------|---------|
| `voicebox-data` | Database, voice profiles, and generated audio |
| `huggingface-cache` | Downloaded ML models (Qwen3-TTS, Whisper) |

Data persists across `docker compose down` / `docker compose up` cycles.

### Connecting Clients

**Desktop app** — Use Remote Server mode and point to `http://<host>:8000`.

**API** — The full REST API is available at port 8000:

```bash
# List voice profiles
curl http://localhost:8000/profiles

# Generate speech
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"text": "Hello from Docker", "profile_id": "your-profile-id", "language": "en"}'
```

---

## Features

### Voice Cloning with Qwen3-TTS
Expand Down
27 changes: 27 additions & 0 deletions docker-compose.backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
services:
backend:
build: .
ports:
- "8000:8000"
volumes:
- voicebox-data:/app/data
- huggingface-cache:/root/.cache/huggingface
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# Uncomment the following to enable NVIDIA GPU support:
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]

volumes:
voicebox-data:
huggingface-cache:
10 changes: 10 additions & 0 deletions docker-compose.web.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "3000:3000"
environment:
- BACKEND_URL=${BACKEND_URL:-http://localhost:8000}
restart: unless-stopped
40 changes: 40 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
services:
backend:
build: .
ports:
- "8000:8000"
volumes:
- voicebox-data:/app/data
- huggingface-cache:/root/.cache/huggingface
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# Uncomment the following to enable NVIDIA GPU support:
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]

web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "3000:3000"
environment:
- BACKEND_URL=http://localhost:8000
depends_on:
backend:
condition: service_healthy
restart: unless-stopped

volumes:
voicebox-data:
huggingface-cache:
14 changes: 14 additions & 0 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
server {
listen 3000;
root /usr/share/nginx/html;
index index.html;

location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}

location / {
try_files $uri $uri/ /index.html;
}
}
6 changes: 6 additions & 0 deletions docker/web-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
# Replace the hardcoded dev backend URL with the configured BACKEND_URL
# in all built JS assets at container startup.
BACKEND_URL="${BACKEND_URL:-http://localhost:8000}"
find /usr/share/nginx/html/assets -name '*.js' \
-exec sed -i "s|http://localhost:17493|${BACKEND_URL}|g" {} +