# Deployment Guide — YouTube Translator & Speaker (hardened v2) Two supported ways to run this. **Docker Space is recommended** (bakes in a pinned deno runtime → no cold-start download, no `curl|sh` supply-chain risk). The plain Gradio SDK path still works as a fallback (`app.py` auto-installs deno on first boot). --- ## Required Space Secrets (both deployment types) Set these under **Settings → Variables and secrets → New secret** (they must be **Secrets**, not public Variables): | Secret | Value | |---|---| | `WEBSHARE_PROXY_UN` | your Webshare proxy username | | `WEBSHARE_PROXY_PW` | your Webshare proxy password | | `ELEVENLABS_API_KEY` | your ElevenLabs API key | --- ## Option A — Docker Space (recommended) ### What you do, step by step 1. In your Space, go to **Settings**. Under **Space SDK**, change it from `Gradio` to `Docker`. (Equivalently, set `sdk: docker` in the `README.md` metadata header — see the header block below.) 2. Upload these three files to the Space repo root: - `Dockerfile` - `requirements.txt` - `app.py` 3. Add the three Secrets above. 4. The Space rebuilds automatically. Docker builds take a few minutes (it builds a full image once); after that, startup is fast because deno is already baked in. ### Space README.md metadata header (top of your Space's README.md) ``` --- title: YouTube Translator And Speaker emoji: 🎧 colorFrom: blue colorTo: indigo sdk: docker app_port: 7860 pinned: false --- ``` ### Why this is the cleaner option - deno (pinned to 2.9.3) and yt-dlp (pinned to 2026.7.4) are installed at **build time** → no 30s runtime install, no dependence on deno.land at boot. - No `curl | sh` executed on every restart → removes that supply-chain risk. --- ## Option B — Gradio SDK Space (fallback) ### What you do 1. Keep the Space SDK as `Gradio`. 2. Upload `requirements.txt` and `app.py` (no Dockerfile needed). 3. Add the three Secrets above. ### Tradeoffs - `app.py` installs deno into `/tmp` on first boot (~30s cold start, re-runs on each Space restart) and executes the deno.land install script at runtime. - Works, but is slower to start and less locked-down than the Docker option. --- ## Maintenance — the one thing to watch `yt-dlp` is pinned in `requirements.txt`. YouTube periodically changes its extraction and breaks older yt-dlp versions. When transcripts start failing: 1. Bump the `yt-dlp==` pin to the latest release. 2. Redeploy and test one known video. Do **not** leave yt-dlp unpinned/floating in production — a surprise upstream change could silently break the Space. --- ## Known dependency pins & why (do not unpin) Every version in `requirements.txt` is pinned deliberately. Two pins in particular exist to prevent *silent dependency drift* — cases where your own code never changes but an unpinned upstream package updates and breaks the Space on the next rebuild. If someone "cleans up" these pins, the Space will break again. | Pin | Why it's locked | |---|---| | `pydantic==2.10.6` | **Critical — do not unpin.** `gradio==4.44.1` only requires `pydantic>=2.0` (open-ended) and ships `gradio-client==1.3.0`. pydantic 2.11.x emits JSON schemas with bare booleans (`additionalProperties: true`) that `gradio-client` 1.3.0 cannot parse. Result: `TypeError: argument of type 'bool' is not iterable` in `get_api_info()` at startup. 2.10.6 is the last known-good release for this gradio combo. Refs: [Gradio #10649](https://github.com/gradio-app/gradio/issues/10649), [Gradio #11722](https://github.com/gradio-app/gradio/issues/11722), [HF Forums](https://discuss.huggingface.co/t/gradio-space-crashing-on-startup-typeerror-argument-of-type-bool-is-not-iterable/154601). | | `fastapi==0.112.4` + `starlette==0.38.6` | **Critical — do not unpin.** `gradio==4.44.1` only requires `fastapi<1.0` (no lower bound). On rebuild pip pulled fastapi 1.x → starlette 1.x, which changed the `TemplateResponse` signature (first positional arg is now the request, not the template name). gradio 4.44.1 still calls the old `TemplateResponse(name, context)` form, so the context **dict** is passed as the template name → jinja2 tries to hash a dict → `TypeError: unhashable type: 'dict'`, a 500 on every page (which also surfaces as the `share=True` / "localhost not accessible" `ValueError` at launch). These two are pinned as a consistent pre-1.0 pair (fastapi 0.112.4 requires `starlette>=0.37.2,<0.39.0`). Refs: [FastAPI #15198](https://github.com/fastapi/fastapi/discussions/15198), [HF Space fix commit](https://huggingface.co/spaces/surindersinghssj/gurbani-kirtan-asr-v4/commit/84ff1e0afab32a4ae55d8485fc723971059c887e). | | `yt-dlp==2026.7.4` | YouTube periodically changes extraction and breaks older yt-dlp. This is the **one pin you bump deliberately** (see Maintenance above) — but always to a specific release, never floating. | | `gradio==4.44.1` | The app's `gr.Interface` uses `allow_flagging="never"`, which is the 4.x parameter name. Upgrading to gradio 5.x renames it to `flagging_mode="never"` and can change Interface/Dropdown behavior. Stay on 4.44.1 unless you deliberately migrate and re-test. | | `torch==2.4.1`, `transformers==4.44.2`, `sentencepiece`, `sacremoses`, `accelerate` | NLLB translation stack. Locked together as a tested set — bumping torch/transformers independently can pull incompatible CUDA/tokenizer combos. | **Rule of thumb:** if transcripts break → bump `yt-dlp` only. If the Space crashes at *startup* with a schema/`bool`/`get_api_info` traceback after a rebuild → check `pydantic` first. If it 500s on every page with `unhashable type: 'dict'` (jinja2/TemplateResponse) → check `fastapi`/`starlette`. All three are symptoms of the same root cause: gradio 4.44.1's open-ended pins on pydantic, fastapi, and starlette let newer, incompatible versions slip in on rebuild. Keep all three pinned. --- ## What was verified before shipping (against video `vd0fMpAIs1s`) - English transcript fetched through the SOCKS5 proxy: ✅ (1,925 chars) - French native caption fetched in the same single extraction: ✅ (2,259 chars) - Arabic auto-translated caption fetched: ✅ (earlier run, 1,755 chars) - Input validation (URL → ID, bad-ID rejection): ✅ - Proxy credentials scrubbed from logs/errors: ✅ - deno auto-install on a clean boot (Gradio fallback path): ✅