BioinstLab/gmass-demo
0
1"""Prepare a Hugging Face Space deployment bundle for the Gradio app."""2 3from __future__ import annotations4 5import argparse6import os7import shutil8import stat9from pathlib import Path10 11 12ROOT = Path(__file__).resolve().parents[1]13APP_DIR = ROOT / "app"14DEFAULT_OUTPUT_DIR = ROOT / "dist" / "hf_space"15COMBINED_RESULTS = ROOT / "data" / "eval_outputs" / "combined" / "all_models_scored.jsonl"16SOURCE_DIRS = ("configs", "core", "models", "probes", "scorer", "scripts", "translation")17SOURCE_FILES = ("run_bilingual_eval.py",)18 19 20def copy_file(src: Path, dst: Path) -> None:21 dst.parent.mkdir(parents=True, exist_ok=True)22 shutil.copy2(src, dst)23 print(f"copied {src.relative_to(ROOT)} -> {dst.relative_to(ROOT)}")24 25 26def copy_tree(src: Path, dst: Path) -> None:27 if dst.exists():28 remove_tree(dst)29 shutil.copytree(30 src,31 dst,32 ignore=shutil.ignore_patterns(33 "__pycache__",34 "*.pyc",35 "*.pyo",36 "logs",37 "*.log",38 "run_codespaces_app.sh",39 ),40 )41 print(f"copied {src.relative_to(ROOT)} -> {dst.relative_to(ROOT)}")42 43 44def handle_remove_readonly(func, path, _exc_info) -> None:45 os.chmod(path, stat.S_IWRITE)46 func(path)47 48 49def remove_tree(path: Path) -> None:50 shutil.rmtree(path, onerror=handle_remove_readonly)51 52 53def prepare_space_bundle(output_dir: Path, include_results: bool = False) -> Path:54 if output_dir.exists():55 remove_tree(output_dir)56 output_dir.mkdir(parents=True)57 58 copy_file(APP_DIR / "app.py", output_dir / "app.py")59 copy_file(APP_DIR / "gmass_app.py", output_dir / "gmass_app.py")60 copy_file(APP_DIR / "spaces_README.md", output_dir / "README.md")61 copy_file(APP_DIR / "spaces_requirements.txt", output_dir / "requirements.txt")62 if (ROOT / "LICENSE").exists():63 copy_file(ROOT / "LICENSE", output_dir / "LICENSE")64 for source_dir in SOURCE_DIRS:65 copy_tree(ROOT / source_dir, output_dir / source_dir)66 for source_file in SOURCE_FILES:67 copy_file(ROOT / source_file, output_dir / source_file)68 (output_dir / ".gitignore").write_text(69 "\n".join(70 [71 "__pycache__/",72 "*.py[cod]",73 ".env",74 ".env.*",75 "logs/",76 "*.log",77 "",78 ]79 ),80 encoding="utf-8",81 )82 print(f"wrote {output_dir.relative_to(ROOT) / '.gitignore'}")83 84 PUBLIC_METRICS = ROOT / "data" / "public_metrics" / "benchmark_summary.json"85 if PUBLIC_METRICS.exists():86 copy_file(PUBLIC_METRICS, output_dir / PUBLIC_METRICS.relative_to(ROOT))87 88 if include_results:89 if not COMBINED_RESULTS.exists():90 raise FileNotFoundError(91 f"Cannot include benchmark results; missing {COMBINED_RESULTS.relative_to(ROOT)}"92 )93 copy_file(COMBINED_RESULTS, output_dir / COMBINED_RESULTS.relative_to(ROOT))94 95 print("")96 print(f"Space bundle ready at: {output_dir}")97 print("Next: copy or push that directory to your Hugging Face Space repository.")98 return output_dir99 100 101def main() -> None:102 parser = argparse.ArgumentParser(description="Prepare the Hugging Face Space bundle.")103 parser.add_argument(104 "--output-dir",105 default=str(DEFAULT_OUTPUT_DIR),106 help="Output directory for the generated Space bundle.",107 )108 parser.add_argument(109 "--include-results",110 action="store_true",111 help="Include precomputed combined benchmark results if available.",112 )113 args = parser.parse_args()114 115 prepare_space_bundle(Path(args.output_dir).resolve(), include_results=args.include_results)116 117 118if __name__ == "__main__":119 main()120 