blindspot / deploy /entrypoint.py
yashwrites's picture
entrypoint: fetch volumetric files
ecd292c verified
Raw History Blame Contribute Delete
3.97 kB
"""Container entrypoint (deploy/Dockerfile): fetch data if missing → ensure the SQLite schema → exec uvicorn.
1. If `$BLINDSPOT_DATA_DIR/processed/cases.jsonl` is missing, download the processed-data bundle from the PRIVATE
Hugging Face dataset repo `$BLINDSPOT_DATA_REPO` (made by deploy/make_data_bundle.py --upload) with `$HF_TOKEN`
into `$BLINDSPOT_DATA_DIR/processed`. The image itself never contains dataset files.
2. Create the SQLite schema at `$BLINDSPOT_DB_PATH` (default /data/blindspot.sqlite). Without a persistent volume
it starts empty on every restart; that is expected for the demo.
3. Optional: `BLINDSPOT_SEED_DEMO=1` seeds the demo learner + playlist (offline templates; no API call).
4. exec uvicorn on 0.0.0.0:$PORT (7860 on Hugging Face), trusting X-Forwarded-* from the proxy.
Never prints secrets (HF_TOKEN, ANTHROPIC_API_KEY, access codes).
"""
from __future__ import annotations
import os
import subprocess
import sys
import time
from pathlib import Path
APP_DIR = Path(__file__).resolve().parents[1]
def log(msg: str) -> None:
print(f"[entrypoint] {msg}", flush=True)
def data_dir() -> Path:
p = Path(os.environ.get("BLINDSPOT_DATA_DIR", "/data"))
return p if p.is_absolute() else (APP_DIR / p).resolve()
def has_data(processed: Path) -> bool:
return (processed / "cases.jsonl").is_file() and (processed / "images").is_dir()
def fetch_data(processed: Path) -> None:
repo = os.environ.get("BLINDSPOT_DATA_REPO", "").strip()
if not repo:
log("BLINDSPOT_DATA_REPO is not set and no data is mounted; the API will start with 0 cases.")
return
token = os.environ.get("HF_TOKEN") or None
from huggingface_hub import snapshot_download
processed.mkdir(parents=True, exist_ok=True)
t0 = time.time()
log(f"downloading dataset repo {repo} into {processed} (private; token {'set' if token else 'NOT set'})")
snapshot_download(
repo_id=repo,
repo_type="dataset",
local_dir=str(processed),
token=token,
max_workers=8,
allow_patterns=[
"cases.jsonl",
"cases_msd.jsonl",
"splits.json",
"*.json",
"images/*",
"masks/*",
"zones/*",
"volumes/*",
"zones3d/*",
"previews/*",
],
)
n = sum(1 for _ in (processed / "cases.jsonl").open()) if (processed / "cases.jsonl").exists() else 0
log(f"data ready: {n} cases in {time.time() - t0:.0f} s")
def ensure_db() -> None:
subprocess.run([sys.executable, "-m", "backend.app.db"], cwd=APP_DIR, check=True)
if os.environ.get("BLINDSPOT_SEED_DEMO", "").strip() in ("1", "true", "yes"):
env = dict(os.environ, BLINDSPOT_OFFLINE="1") # seeding never makes live calls
r = subprocess.run([sys.executable, "-m", "backend.app.demo_seed"], cwd=APP_DIR, env=env)
log(f"demo seed exit code {r.returncode}")
def main() -> None:
processed = data_dir() / "processed"
if not has_data(processed):
try:
fetch_data(processed)
except Exception as e: # noqa: BLE001 — start anyway; /api/health reports cases=0
log(f"data download failed: {type(e).__name__}: {e}")
else:
log(f"data present at {processed}")
ensure_db()
port = os.environ.get("PORT", "7860")
log(f"starting uvicorn on :{port} base={os.environ.get('BLINDSPOT_BASE_PATH', '') or '/'}")
os.chdir(APP_DIR)
os.execvp(
sys.executable,
[
sys.executable,
"-m",
"uvicorn",
"backend.app.main:app",
"--host",
os.environ.get("HOST", "0.0.0.0"),
"--port",
port,
"--proxy-headers",
"--forwarded-allow-ips",
"*",
"--workers",
os.environ.get("WEB_CONCURRENCY", "1"),
],
)
if __name__ == "__main__":
main()