File size: 3,142 Bytes
4666cd3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de9aae0
 
4666cd3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de9aae0
 
 
4666cd3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
"""Push the project to its Hugging Face Space.

    uv run python scripts/deploy.py                    # upload and report status
    uv run python scripts/deploy.py -m "tweak layout"  # with a commit message
    uv run python scripts/deploy.py --watch            # also wait for it to come up

`hf upload` is not used here: it calls `create_repo` first, and on a free
account creating a Gradio Space returns 402 Payment Required — so the CLI fails
even though the Space already exists. `upload_folder` talks to the commit
endpoint directly and does not care.
"""

import argparse
import sys
import time

from huggingface_hub import HfApi
from huggingface_hub.errors import HfHubHTTPError
from requests.exceptions import RequestException

SPACE_ID = "Smomitya/flight-booking-agent"

# Everything that must never reach the Space. `.venv` alone is gigabytes, and
# `data/` is local state the Space reseeds for itself on startup.
IGNORE = [
    ".venv/**",
    "**/__pycache__/**",
    ".ruff_cache/**",
    ".pytest_cache/**",
    "data/**",
    ".git/**",
    "**/.DS_Store",
    "uv.lock",
]

SETTLED = {"RUNNING", "RUNTIME_ERROR", "BUILD_ERROR", "CONFIG_ERROR", "PAUSED"}


def watch(api: HfApi, space_id: str, minutes: int = 12) -> str:
    """Follow the Space until it settles, printing each stage change."""
    last = None
    deadline = time.time() + minutes * 60
    while time.time() < deadline:
        try:
            runtime = api.space_info(space_id).runtime
        except (HfHubHTTPError, RequestException) as error:
            # The hub drops long polls routinely; a failed read is not a
            # failed deploy, so keep watching rather than reporting an error.
            print(f"  (poll failed: {type(error).__name__}, retrying)")
            time.sleep(15)
            continue
        if runtime.stage != last:
            print(f"  [{time.strftime('%H:%M:%S')}] {runtime.stage}"
                  f"  hardware={runtime.hardware}")
            last = runtime.stage
        if runtime.stage in SETTLED:
            return runtime.stage
        time.sleep(15)
    return last or "UNKNOWN"


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("-m", "--message", default="Update from local checkout")
    parser.add_argument("--space", default=SPACE_ID)
    parser.add_argument("--watch", action="store_true",
                        help="wait for the Space to finish starting")
    args = parser.parse_args()

    api = HfApi()
    print(f"Uploading to {args.space} …")
    api.upload_folder(
        repo_id=args.space,
        repo_type="space",
        folder_path=".",
        ignore_patterns=IGNORE,
        commit_message=args.message,
    )
    print(f"  https://huggingface.co/spaces/{args.space}")

    if not args.watch:
        return 0

    stage = watch(api, args.space)
    print(f"final: {stage}")
    # A Space can report RUNNING while the app inside it is broken, so this is
    # a floor, not a guarantee — check the logs tab if behaviour looks wrong.
    return 0 if stage == "RUNNING" else 1


if __name__ == "__main__":
    sys.exit(main())