github-actions[bot] commited on
Commit
1384ff1
·
1 Parent(s): d33ca97

deploy: switch to chatterbox requirements @ a2451a8

Browse files
Files changed (7) hide show
  1. .dockerignore +0 -10
  2. .env.example +6 -0
  3. .gitattributes +10 -0
  4. Dockerfile +0 -32
  5. README.md +34 -1
  6. SPLIT_STRATEGY.md +0 -113
  7. deploy.sh +0 -178
.dockerignore DELETED
@@ -1,10 +0,0 @@
1
- frontend/
2
- tmp/
3
- data/
4
- batch_outputs/
5
- uploads/
6
- outputs/
7
- .venv/
8
- .git/
9
- *.mp4
10
- wiki/
 
 
 
 
 
 
 
 
 
 
 
.env.example CHANGED
@@ -4,6 +4,12 @@
4
  # Server port (default 8000)
5
  PORT=8000
6
 
 
 
 
 
 
 
7
  # OpenAI API key (for translation step)
8
  OPENAI_API_KEY=sk-...
9
 
 
4
  # Server port (default 8000)
5
  PORT=8000
6
 
7
+ # Where per-job artifact folders get written. On HF Spaces this is resolved
8
+ # automatically (/data/jobs with persistent storage, /tmp/videovoice_jobs
9
+ # without). For local dev, set this to ./data so jobs land next to the repo
10
+ # — same layout the old `main` used.
11
+ ARTIFACTS_ROOT=./data
12
+
13
  # OpenAI API key (for translation step)
14
  OPENAI_API_KEY=sk-...
15
 
.gitattributes ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Files in this repo that are dev-only and must NOT ship to the HF Spaces.
2
+ # `deploy.sh` honors this via `git archive --worktree-attributes`.
3
+ # Rule of thumb: if HF Spaces would never import/execute it, export-ignore it.
4
+ # Do NOT export-ignore server.py — app.py imports from it at runtime on HF.
5
+
6
+ .github/ export-ignore
7
+ SPLIT_STRATEGY.md export-ignore
8
+ deploy.sh export-ignore
9
+ Dockerfile export-ignore
10
+ .dockerignore export-ignore
Dockerfile DELETED
@@ -1,32 +0,0 @@
1
- FROM python:3.11-slim-bookworm
2
-
3
- RUN apt-get update && apt-get install -y --no-install-recommends \
4
- ffmpeg \
5
- git \
6
- curl \
7
- build-essential \
8
- libsndfile1 \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- RUN curl -LsSf https://astral.sh/uv/install.sh | sh && ln -s /root/.local/bin/uv /usr/local/bin/uv
12
-
13
- WORKDIR /app
14
-
15
- COPY pyproject.toml uv.lock ./
16
- RUN uv sync --frozen --no-dev
17
-
18
- COPY scripts/prefetch_models.py /app/scripts/prefetch_models.py
19
- ARG PREFETCH_MODELS=1
20
- RUN if [ "$PREFETCH_MODELS" = "1" ]; then HF_HOME=/data/hf-cache uv run python scripts/prefetch_models.py; fi
21
-
22
- COPY . /app
23
-
24
- ENV HF_HOME=/data/hf-cache \
25
- PORT=7860 \
26
- ARTIFACTS_ROOT=/data/jobs
27
-
28
- RUN mkdir -p /data/hf-cache /data/jobs
29
-
30
- EXPOSE 7860
31
-
32
- CMD ["uv", "run", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -77,6 +77,8 @@ uv run python server.py
77
 
78
  The app will be available at [http://localhost:8000](http://localhost:8000).
79
 
 
 
80
  ### CLI Usage
81
 
82
  You can also run the pipeline directly:
@@ -268,9 +270,40 @@ VideoVoice/
268
 
269
  ---
270
 
 
 
 
 
 
 
 
 
 
 
 
271
  ## Deployment
272
 
273
- ### AWS (Recommended for GPU)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
  ```bash
276
  # On a g4dn.xlarge instance
 
77
 
78
  The app will be available at [http://localhost:8000](http://localhost:8000).
79
 
80
+ Per-job artifacts (uploads, intermediate audio, outputs) land in `ARTIFACTS_ROOT`. Set `ARTIFACTS_ROOT=./data` in your `.env` to match the layout the repo used historically — each job gets its own `data/<job_id>/` folder with every pipeline file.
81
+
82
  ### CLI Usage
83
 
84
  You can also run the pipeline directly:
 
270
 
271
  ---
272
 
273
+ ## Entrypoints
274
+
275
+ Two files intentionally exist, run in different contexts, but **ship the same code**:
276
+
277
+ | File | When it runs | What it does |
278
+ |------|-------------|--------------|
279
+ | `server.py` | Local dev (`uv run python server.py`) | Plain FastAPI app — defines every `/api/*` route. |
280
+ | `app.py` | Hugging Face Spaces | Gradio Server that imports `server.py`'s router and wraps it with `@spaces.GPU` for ZeroGPU. |
281
+
282
+ `app.py` depends on `server.py`, so server.py must ship to HF. Do not strip it.
283
+
284
  ## Deployment
285
 
286
+ ### Hugging Face Spaces (production)
287
+
288
+ Push to `main` → GitHub Actions runs `.github/workflows/deploy-hf.yml` → both Spaces (`Rafii/videovoice` and `Rafii/videovoice-omni`) redeploy automatically. No manual step.
289
+
290
+ One-time CI setup:
291
+ 1. Create an HF access token with write access to both Spaces: https://huggingface.co/settings/tokens
292
+ 2. Add it as `HF_TOKEN` under **Settings → Secrets and variables → Actions** in the GitHub repo.
293
+
294
+ Manual fallback (from a local clean checkout with `space` and `space-omni` remotes configured):
295
+ ```bash
296
+ ./deploy.sh # skips if remote is already at HEAD
297
+ ./deploy.sh --force # always redeploy
298
+ ```
299
+
300
+ Files filtered out of every Space deploy are listed in `.gitattributes` (`export-ignore`).
301
+
302
+ ### Branching
303
+
304
+ `main` is canonical. Use short-lived `feat/<thing>` branches, open a PR, merge, delete. Never maintain a parallel deploy branch — every change on main reaches both Spaces via CI.
305
+
306
+ ### AWS (alternative GPU host)
307
 
308
  ```bash
309
  # On a g4dn.xlarge instance
SPLIT_STRATEGY.md DELETED
@@ -1,113 +0,0 @@
1
- # TTS Backend Split Implementation
2
-
3
- ## Summary
4
-
5
- Successfully implemented the TTS backend split strategy to resolve the dependency conflict between `chatterbox-tts` (requires `transformers==5.2.0`) and `omnivoice` (requires `transformers>=4.57.3`).
6
-
7
- ## Changes Made
8
-
9
- ### 1. Split Requirements Files
10
- - **`requirements-cbox.txt`** — All dependencies + `chatterbox-tts==0.1.7 --no-deps`
11
- - **`requirements-omni.txt`** — All dependencies + `omnivoice>=0.1.4`
12
- - **`deploy.sh`** — Deploy script that swaps requirements.txt before pushing to each HF Space
13
-
14
- ### 2. Updated `pyproject.toml`
15
- - Removed `chatterbox-tts` and `omnivoice` from base dependencies
16
- - Added `[project.optional-dependencies]` with `chatterbox`, `omnivoice`, and `all` groups
17
- - Removed the transformers override (now directly in base dependencies)
18
-
19
- ### 3. Updated `app.py`
20
- - Removed the hacky `--no-deps` pip install at startup
21
- - Added `TTS_ENGINE` env var validation at import time
22
- - Imports are now guarded based on `TTS_ENGINE` value
23
- - Space landing page shows which engine is configured
24
-
25
- ### 4. Updated `server.py`
26
- - Added `TTS_ENGINE` env var handling
27
- - `/api/config` now returns only the configured TTS engine
28
- - Validation endpoints check against `TTS_ENGINE` instead of hardcoded list
29
- - Removed `preview_both` mode handling (single-engine Spaces don't need it)
30
-
31
- ### 5. Updated `steps/s4_tts.py`
32
- - Added `TTS_ENGINE` env var handling
33
- - Conditional imports: only imports `chatterbox` if `TTS_ENGINE==chatterbox`
34
- - `synthesise_segments()` validates that requested model matches configured engine
35
-
36
- ### 6. Updated `steps/s4_preview.py`
37
- - Added `TTS_ENGINE` env var handling
38
- - Conditional imports based on `TTS_ENGINE`
39
- - `generate_previews()` only generates preview for configured engine
40
-
41
- ### 7. Updated `pipeline.py`
42
- - Removed `preview` voice mode (no more preview_both flow)
43
- - Pipeline now respects `TTS_ENGINE` env var in Space deployments
44
- - Simplified step counting (no conditional preview steps)
45
-
46
- ## Deployment
47
-
48
- ### First-Time Setup
49
-
50
- 1. Add HF Space remotes (if not already configured):
51
- ```bash
52
- git remote add space https://huggingface.co/spaces/YOUR_USERNAME/videovoice
53
- git remote add space-omni https://huggingface.co/spaces/YOUR_USERNAME/videovoice-omni
54
- ```
55
-
56
- 2. Set up the two HF Spaces:
57
- - `videovoice` — Set `TTS_ENGINE=chatterbox` in Space Secrets
58
- - `videovoice-omni` — Set `TTS_ENGINE=omnivoice` in Space Secrets
59
-
60
- ### Deploying
61
-
62
- ```bash
63
- ./deploy.sh
64
- ```
65
-
66
- This script will:
67
- 1. Copy `requirements-cbox.txt` → `requirements.txt` and push to `space` remote
68
- 2. Copy `requirements-omni.txt` → `requirements.txt` and push to `space-omni` remote
69
- 3. Restore the original `requirements.txt`
70
-
71
- ## Frontend Changes Needed
72
-
73
- The React frontend should check `/api/config` to determine which TTS engines are available:
74
-
75
- ```javascript
76
- const config = await fetch('/api/config').then(r => r.json());
77
- const availableEngine = config.tts_engine; // "chatterbox" or "omnivoice"
78
- const availableEngines = config.tts_models; // Array with single engine
79
- ```
80
-
81
- The frontend can then route API calls to the appropriate Space based on user selection:
82
- - Chatterbox: `https://videovoice.hf.space`
83
- - OmniVoice: `https://videovoice-omni.hf.space`
84
-
85
- ## Local Development
86
-
87
- For local development with both engines:
88
-
89
- ```bash
90
- # Install with both TTS engines
91
- pip install -e ".[all]"
92
-
93
- # Or just one
94
- pip install -e ".[chatterbox]"
95
- ```
96
-
97
- The CLI still accepts `--voice-mode chatterbox|omnivoice` for local testing.
98
-
99
- ## Files Changed
100
-
101
- - `pyproject.toml`
102
- - `app.py`
103
- - `server.py`
104
- - `steps/s4_tts.py`
105
- - `steps/s4_preview.py`
106
- - `pipeline.py`
107
-
108
- ## Files Added
109
-
110
- - `requirements-cbox.txt`
111
- - `requirements-omni.txt`
112
- - `deploy.sh`
113
- - `SPLIT_STRATEGY.md` (this file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
deploy.sh DELETED
@@ -1,178 +0,0 @@
1
- #!/bin/bash
2
- # deploy.sh — push to both HuggingFace Spaces with the correct requirements.txt
3
- # Usage: ./deploy.sh [--force]
4
- #
5
- # This script exports the current commit while excluding large media folders,
6
- # then updates each Space repo on top of its current main branch so commit
7
- # history is preserved.
8
-
9
- set -e
10
-
11
- # Colors for output
12
- RED='\033[0;31m'
13
- GREEN='\033[0;32m'
14
- YELLOW='\033[1;33m'
15
- BLUE='\033[0;34m'
16
- NC='\033[0m' # No Color
17
-
18
- FORCE_DEPLOY=false
19
- if [ "$1" == "--force" ]; then
20
- FORCE_DEPLOY=true
21
- fi
22
-
23
- echo -e "${YELLOW}VideoVoice Dual-Space Deploy Script${NC}"
24
- echo ""
25
-
26
- # Ensure we're in the right directory
27
- if [ ! -f "app.py" ] || [ ! -d "steps" ]; then
28
- echo -e "${RED}Error: Must run from VideoVoice-be root directory${NC}"
29
- exit 1
30
- fi
31
-
32
- # Check for uncommitted changes
33
- if [ -n "$(git status --porcelain)" ]; then
34
- echo -e "${YELLOW}Warning: You have uncommitted changes.${NC}"
35
- echo "Commit to origin first, then run this deploy script."
36
- git status --short
37
- echo ""
38
- read -p "Continue anyway? (y/N) " -n 1 -r
39
- echo
40
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
41
- exit 1
42
- fi
43
- fi
44
-
45
- REPO_ROOT=$(git rev-parse --show-toplevel)
46
- LOCAL_SHA=$(git rev-parse HEAD)
47
-
48
- # Verify remotes exist
49
- if ! git remote | grep -q "^space$"; then
50
- echo -e "${RED}Error: Missing 'space' remote for Chatterbox Space${NC}"
51
- echo "Add it with: git remote add space https://huggingface.co/spaces/Rafii/videovoice"
52
- exit 1
53
- fi
54
-
55
- if ! git remote | grep -q "^space-omni$"; then
56
- echo -e "${RED}Error: Missing 'space-omni' remote for OmniVoice Space${NC}"
57
- echo "Add it with: git remote add space-omni https://huggingface.co/spaces/Rafii/videovoice-omni"
58
- exit 1
59
- fi
60
-
61
- echo -e "${GREEN}Remotes configured:${NC}"
62
- git remote -v | grep -E "^(space|space-omni)"
63
- echo ""
64
-
65
- # Get space URLs for pushing
66
- SPACE_URL=$(git remote get-url space)
67
- SPACE_OMNI_URL=$(git remote get-url space-omni)
68
-
69
- # Function to check if Space needs update
70
- _needs_update() {
71
- local remote_url=$1
72
-
73
- # Try to get the remote HEAD SHA
74
- local remote_sha
75
- remote_sha=$(git ls-remote "$remote_url" HEAD 2>/dev/null | awk '{print $1}')
76
-
77
- if [ -z "$remote_sha" ]; then
78
- # Can't determine, assume needs update
79
- return 0
80
- fi
81
-
82
- # Compare with local SHA (if equal, no update needed)
83
- if [ "$remote_sha" == "$LOCAL_SHA" ]; then
84
- return 1
85
- fi
86
-
87
- return 0
88
- }
89
-
90
- # Deploy to one Space while preserving commit history
91
- _deploy_space() {
92
- local target_name=$1
93
- local target_url=$2
94
- local export_dir_name=$3
95
- local source_requirements=$4
96
- local commit_message=$5
97
- local strip_path=$6
98
-
99
- echo "Creating clean export excluding media files..."
100
-
101
- local temp_dir
102
- temp_dir=$(mktemp -d)
103
- local export_dir="$temp_dir/$export_dir_name"
104
- mkdir -p "$export_dir"
105
-
106
- # Export current HEAD
107
- git archive --format=tar HEAD | tar -C "$export_dir" -xf -
108
-
109
- # Remove any lingering media directories
110
- rm -rf "$export_dir/data" \
111
- "$export_dir/uploads" \
112
- "$export_dir/outputs" \
113
- "$export_dir/tmp" 2>/dev/null || true
114
-
115
- if [ -n "$strip_path" ]; then
116
- rm -rf "$export_dir/$strip_path"
117
- fi
118
-
119
- local repo_dir="$temp_dir/${export_dir_name}-repo"
120
-
121
- # Clone remote so we keep full history instead of force-replacing it
122
- git clone "$target_url" "$repo_dir"
123
- cd "$repo_dir"
124
-
125
- # Ensure we are on main and up to date
126
- git checkout -B main origin/main 2>/dev/null || git checkout -b main
127
- git pull --ff-only origin main 2>/dev/null || true
128
-
129
- # Replace tracked files with clean export content
130
- find . -mindepth 1 -maxdepth 1 \
131
- ! -name .git \
132
- ! -name .gitattributes \
133
- -exec rm -rf {} +
134
-
135
- cp -R "$export_dir"/. .
136
-
137
- # Apply target requirements variant
138
- cp "$source_requirements" requirements.txt
139
-
140
- git add -A
141
-
142
- if git diff --cached --quiet; then
143
- echo -e "${BLUE} No file changes for ${target_name}, skipping push.${NC}"
144
- else
145
- git commit -m "$commit_message @ ${LOCAL_SHA:0:7}" --no-verify
146
- git push "$target_url" HEAD:main
147
- echo -e "${GREEN}✓ ${target_name} deployed${NC}"
148
- fi
149
-
150
- cd "$REPO_ROOT"
151
- rm -rf "$temp_dir"
152
- }
153
-
154
- # Deploy to Chatterbox Space
155
- echo -e "${YELLOW}>>> Checking Chatterbox Space (videovoice)...${NC}"
156
- if ! $FORCE_DEPLOY && ! _needs_update "$SPACE_URL"; then
157
- echo -e "${BLUE} Chatterbox Space is already at commit ${LOCAL_SHA:0:7}, skipping.${NC}"
158
- echo -e "${BLUE} Use --force to redeploy anyway.${NC}"
159
- else
160
- _deploy_space "Chatterbox Space" "$SPACE_URL" "videovoice-deploy" "requirements-cbox.txt" "deploy: switch to chatterbox requirements" ""
161
- fi
162
- echo ""
163
-
164
- # Deploy to OmniVoice Space
165
- echo -e "${YELLOW}>>> Checking OmniVoice Space (videovoice-omni)...${NC}"
166
- if ! $FORCE_DEPLOY && ! _needs_update "$SPACE_OMNI_URL"; then
167
- echo -e "${BLUE} OmniVoice Space is already at commit ${LOCAL_SHA:0:7}, skipping.${NC}"
168
- echo -e "${BLUE} Use --force to redeploy anyway.${NC}"
169
- else
170
- _deploy_space "OmniVoice Space" "$SPACE_OMNI_URL" "videovoice-omni-deploy" "requirements-omni.txt" "deploy: switch to omnivoice requirements" "chatterbox"
171
- fi
172
- echo ""
173
-
174
- echo -e "${GREEN}✓ Deploy check complete!${NC}"
175
- echo ""
176
- echo "Space URLs:"
177
- echo " - Chatterbox: https://huggingface.co/spaces/Rafii/videovoice"
178
- echo " - OmniVoice: https://huggingface.co/spaces/Rafii/videovoice-omni"