| |
| """Space entrypoint: fetch the index, then hand off to src/serve.py. |
| |
| WHY THE INDEX IS NOT IN THIS REPO |
| --------------------------------- |
| It lives in a separate HF Dataset. Pushing a rebuilt index into the Space repo |
| would trigger a full Docker rebuild (~10 min, and it re-bakes 2.3 GB of models) |
| where a restart (~40 s) is all that is actually needed. The split also keeps the |
| Space's build context small enough to push over a hotel wifi. |
| |
| Configuration is entirely environment variables, because that is what the Space |
| settings UI gives you: |
| |
| VOICERAG_INDEX_REPO required HF dataset holding index/ -- "you/voicerag-index" |
| ELEVENLABS_API_KEY required requirement 1; set it as a SECRET, not a variable |
| VOICERAG_CORS optional origin of the Vercel page |
| VOICERAG_LANGS optional subset to serve; default = everything in the manifest |
| VOICERAG_PREWARM optional langs to warm TTS for, or "all" |
| HF_TOKEN optional only if the dataset is private |
| """ |
| from __future__ import annotations |
|
|
| import os |
| import pathlib |
| import subprocess |
| import sys |
| import time |
|
|
| ROOT = pathlib.Path(os.environ.get("VOICERAG_ROOT", "/home/user/app/data")) |
| INDEX_REPO = os.environ.get("VOICERAG_INDEX_REPO", "").strip() |
|
|
|
|
| def fetch_index() -> None: |
| manifest = ROOT / "index" / "manifest.json" |
| if manifest.exists(): |
| print(f"==> index already at {ROOT}, skipping download") |
| return |
| if not INDEX_REPO: |
| sys.exit( |
| "!! VOICERAG_INDEX_REPO is not set.\n" |
| " Build the index with notebooks/build_index.ipynb, push it to an\n" |
| " HF dataset, then set VOICERAG_INDEX_REPO in the Space settings." |
| ) |
| from huggingface_hub import snapshot_download |
|
|
| t0 = time.time() |
| print(f"==> pulling index from {INDEX_REPO}") |
| ROOT.mkdir(parents=True, exist_ok=True) |
| snapshot_download(repo_id=INDEX_REPO, repo_type="dataset", |
| local_dir=str(ROOT), |
| token=os.environ.get("HF_TOKEN") or None) |
| if not manifest.exists(): |
| sys.exit(f"!! {INDEX_REPO} has no index/manifest.json -- wrong repo?") |
| mb = sum(f.stat().st_size for f in (ROOT / "index").rglob("*")) / 2**20 |
| print(f"==> {mb:.0f} MB in {time.time() - t0:.1f}s") |
|
|
|
|
| def build_cmd(env: dict, python: str = sys.executable) -> list[str]: |
| """serve.py's argv, assembled from Space environment variables. |
| |
| An unset variable must not become an empty flag: `--cors ""` reaches |
| argparse as a real value and CORSMiddleware would be installed with an |
| empty origin list, which blocks the Vercel page as surely as no middleware |
| at all -- but silently, and only in the browser. |
| """ |
| cmd = [python, "src/serve.py", |
| "--host", "0.0.0.0", |
| "--port", env.get("PORT", "7860")] |
| for name, flag in (("VOICERAG_LANGS", "--langs"), |
| ("VOICERAG_CORS", "--cors"), |
| ("VOICERAG_PREWARM", "--prewarm-tts")): |
| if env.get(name, "").strip(): |
| cmd += [flag, env[name].strip()] |
| return cmd |
|
|
|
|
| def main() -> int: |
| fetch_index() |
|
|
| if not os.environ.get("ELEVENLABS_API_KEY"): |
| |
| |
| print("!! ELEVENLABS_API_KEY unset -- voice input will return an error") |
|
|
| cmd = build_cmd(dict(os.environ)) |
| print("==>", " ".join(cmd), flush=True) |
| return subprocess.call(cmd) |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|