File size: 3,544 Bytes
28dbedc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8aeaae5
 
 
07f2e54
 
28dbedc
 
 
 
 
 
8aeaae5
 
28dbedc
 
 
 
 
 
 
 
07f2e54
 
8e0d79f
28dbedc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""Build an explicit allowlist archive; never upload it or include weights/secrets."""
import argparse
import hashlib
import json
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile

from verify_ui import fingerprint

ROOT = Path(__file__).resolve().parents[1]


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("output", type=Path)
    args = parser.parse_args()
    if args.output.exists():
        raise SystemExit("Output already exists; choose a new archive path.")
    args.output.parent.mkdir(parents=True, exist_ok=True)
    lock = ROOT / "docs/ui_case_pool_22_lock.json"
    if not lock.exists():
        lock = ROOT / "docs/ui_studio_r8_lock.json"
    if not lock.exists():
        lock = ROOT / "docs/ui_paper_r7_lock.json"
    if not lock.exists():
        lock = ROOT / "docs/ui_lock.json"
    if fingerprint(ROOT) != json.loads(lock.read_text()):
        raise ValueError("Original UI/assets/case contract changed; inspect before packaging.")
    rows = json.loads((ROOT / "data/cases.json").read_text())
    case_keys = {"id", "route", "route_title", "title", "prompt", "expected", "image",
                 "source", "image_sha256", "difficulty", "validation", "image_size",
                 "expected_available", "gt_coord", "gt", "visual_prompt"}
    public_rows = [{k: v for k, v in row.items() if k in case_keys} for row in rows]
    top = ["app.py", "space_app.py", "README.md", "LICENSE_PENDING.md", "requirements.txt", "constraints-app.txt", ".gitignore", ".env.example",
           "docs/ui_lock.json", "docs/HF_SPACE_DEPLOYMENT.md", "docs/ZEROGPU_DEPLOYMENT.md",
           "docs/VERIFICATION.md", "scripts/start.sh", "scripts/verify_ui.py",
           "scripts/preflight_model.py", "scripts/smoke_structure.py", "scripts/build_bundle.py",
           "scripts/prepare_model_repo.py", "scripts/validate_gradio.py"]
    paths = [ROOT / name for name in top]
    paths.extend([lock, ROOT / "docs/UI_PAPER_R7.md"])
    if (ROOT / "docs/UI_STUDIO_R8.md").exists():
        paths.append(ROOT / "docs/UI_STUDIO_R8.md")
    for folder, suffixes in {"assets": {".css", ".js", ".png", ".ttf", ".otf", ".txt", ".md"},
                             "grounding_demo": {".py"}, "tests": {".py"}}.items():
        paths.extend(p for p in (ROOT / folder).rglob("*") if p.is_file() and p.suffix in suffixes)
    for row, public_row in zip(rows, public_rows, strict=True):
        path = (ROOT / row["image"]).resolve(strict=True)
        if not path.is_relative_to((ROOT / "cases").resolve()):
            raise ValueError("Case image escapes cases directory")
        # Legacy image_sha256 hashes SOURCE bytes, before the original demo's
        # JPEG re-encoding. Preserve that field and add a separate artifact hash.
        public_row["artifact_image_sha256"] = hashlib.sha256(path.read_bytes()).hexdigest()
        paths.append(path)
    with ZipFile(args.output, "x", ZIP_DEFLATED) as archive:
        for path in sorted(set(paths)):
            if path.is_symlink() or not path.resolve().is_relative_to(ROOT.resolve()):
                raise ValueError(f"Unexpected source path: {path.name}")
            archive.write(path, path.relative_to(ROOT))
        archive.writestr("data/cases.json", json.dumps(public_rows, ensure_ascii=False, indent=2) + "\n")
    print(json.dumps({"archive": str(args.output), "case_count": len(rows),
                      "sha256": hashlib.sha256(args.output.read_bytes()).hexdigest()}, indent=2))


if __name__ == "__main__":
    main()