| |
| """Create/update the private Hugging Face Space used for evidence generation.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import os |
| from pathlib import Path |
| import shutil |
| import sys |
|
|
| from huggingface_hub import HfApi |
|
|
|
|
| ROOT = Path(__file__).resolve().parents[1] |
|
|
|
|
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description="Deploy the PolyGuard evidence-only Hugging Face Space.") |
| parser.add_argument("--repo-id", default="TheJackBright/polyguard-openenv-evidence") |
| parser.add_argument("--artifact-repo-id", default="TheJackBright/polyguard-openenv-training-full-artifacts") |
| parser.add_argument("--training-space-url", default="https://thejackbright-polyguard-openenv-training-full.hf.space") |
| parser.add_argument("--models", default="qwen-qwen2-5-0-5b-instruct,qwen-qwen2-5-1-5b-instruct") |
| parser.add_argument("--episodes", type=int, default=8) |
| parser.add_argument("--hardware", default="cpu-basic") |
| parser.add_argument("--sleep-time", type=int, default=3600) |
| parser.add_argument("--bundle-dir", default="/tmp/polyguard-openenv-evidence-space") |
| parser.add_argument("--public", action="store_true") |
| parser.add_argument("--skip-upload", action="store_true") |
| parser.add_argument("--bundle-only", action="store_true") |
| return parser.parse_args() |
|
|
|
|
| def _ignore(_dir: str, names: list[str]) -> set[str]: |
| ignored = { |
| ".git", |
| ".venv", |
| "__pycache__", |
| ".pytest_cache", |
| ".mypy_cache", |
| ".ruff_cache", |
| "outputs", |
| "checkpoints", |
| "polyguard_rl.egg-info", |
| "dist", |
| "build", |
| } |
| return { |
| name |
| for name in names |
| if name in ignored |
| or name.endswith(".pyc") |
| or name == "node_modules" |
| or name == ".DS_Store" |
| } |
|
|
|
|
| def build_bundle(bundle_dir: Path) -> None: |
| if bundle_dir.exists(): |
| shutil.rmtree(bundle_dir) |
| shutil.copytree(ROOT, bundle_dir, ignore=_ignore) |
| dockerfile = bundle_dir / "Dockerfile" |
| dockerfile.write_text( |
| """FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime |
| |
| WORKDIR /app |
| |
| ENV PYTHONUNBUFFERED=1 \\ |
| PIP_DISABLE_PIP_VERSION_CHECK=1 \\ |
| TOKENIZERS_PARALLELISM=false \\ |
| POLYGUARD_EVIDENCE_AUTORUN=1 |
| |
| COPY . . |
| |
| RUN python -m pip install --upgrade pip setuptools wheel \\ |
| && python -m pip install --no-cache-dir -r requirements.txt \\ |
| && python -m pip install --no-cache-dir --no-build-isolation -e . |
| |
| EXPOSE 7860 |
| |
| CMD ["python", "-m", "app.hf_space.evidence_runner"] |
| """, |
| encoding="utf-8", |
| ) |
| project_readme = bundle_dir / "PROJECT_README.md" |
| if (bundle_dir / "README.md").exists(): |
| (bundle_dir / "README.md").replace(project_readme) |
| (bundle_dir / "README.md").write_text( |
| """--- |
| title: PolyGuard Evidence Runner |
| sdk: docker |
| app_port: 7860 |
| pinned: false |
| --- |
| |
| # PolyGuard Evidence Runner |
| |
| Private Docker Space for generating PolyGuard submission evidence without retraining. |
| |
| The original project README is included as `PROJECT_README.md`. |
| """, |
| encoding="utf-8", |
| ) |
|
|
|
|
| def main() -> None: |
| args = parse_args() |
| bundle_dir = Path(args.bundle_dir) |
| build_bundle(bundle_dir) |
| if args.bundle_only: |
| print(f"bundle_dir={bundle_dir}") |
| return |
|
|
| token = os.getenv("HF_TOKEN") |
| api = HfApi(token=token) |
| whoami = api.whoami(token=token) |
| username = str(whoami.get("name") or whoami.get("fullname") or "") |
| if username and not args.repo_id.startswith(f"{username}/"): |
| print(f"[deploy_evidence_space] authenticated as {username}; target={args.repo_id}") |
|
|
| space_variables = [ |
| {"key": "POLYGUARD_EVIDENCE_MODELS", "value": args.models}, |
| {"key": "POLYGUARD_EVIDENCE_EPISODES", "value": str(args.episodes)}, |
| {"key": "POLYGUARD_EVIDENCE_AUTORUN", "value": "1"}, |
| {"key": "POLYGUARD_ARTIFACT_REPO_ID", "value": args.artifact_repo_id}, |
| {"key": "POLYGUARD_TRAINING_SPACE_URL", "value": args.training_space_url}, |
| {"key": "POLYGUARD_SPACE_REPO_ID", "value": args.repo_id}, |
| ] |
| space_secrets = [{"key": "HF_TOKEN", "value": token}] if token else None |
|
|
| api.create_repo(repo_id=args.artifact_repo_id, repo_type="model", private=True, exist_ok=True) |
| api.create_repo( |
| repo_id=args.repo_id, |
| repo_type="space", |
| space_sdk="docker", |
| private=not args.public, |
| exist_ok=True, |
| space_hardware=args.hardware, |
| space_sleep_time=args.sleep_time, |
| space_variables=space_variables, |
| space_secrets=space_secrets, |
| ) |
|
|
| for variable in space_variables: |
| api.add_space_variable(repo_id=args.repo_id, key=variable["key"], value=variable["value"]) |
| if token: |
| api.add_space_secret(repo_id=args.repo_id, key="HF_TOKEN", value=token) |
| if not args.skip_upload: |
| api.upload_folder( |
| repo_id=args.repo_id, |
| repo_type="space", |
| folder_path=str(bundle_dir), |
| commit_message="Deploy PolyGuard evidence-only Space", |
| ignore_patterns=[ |
| ".git/*", |
| ".venv/*", |
| "**/node_modules/*", |
| "outputs/*", |
| "checkpoints/*", |
| "**/__pycache__/*", |
| "*.pyc", |
| ".DS_Store", |
| "**/.DS_Store", |
| ], |
| ) |
|
|
| try: |
| api.request_space_hardware(repo_id=args.repo_id, hardware=args.hardware, sleep_time=args.sleep_time) |
| except Exception as exc: |
| print(f"hardware_request_warning={exc}", file=sys.stderr) |
|
|
| print(f"space_url=https://huggingface.co/spaces/{args.repo_id}") |
| print(f"artifact_repo=https://huggingface.co/{args.artifact_repo_id}") |
| print(f"bundle_dir={bundle_dir}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|