File size: 3,401 Bytes
91e3cb8
3247df2
91e3cb8
 
 
3247df2
 
 
dc055c2
3247df2
 
 
 
 
 
 
dc055c2
57abcef
91e3cb8
 
3247df2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1e2dca
3247df2
b1e2dca
3247df2
 
 
 
 
 
 
 
b1e2dca
3247df2
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
94
95
96
97
98
from fastapi import FastAPI
import os, time, requests

app = FastAPI()

# === CONFIG ===
BASE = os.getenv("DB3_BASE_URL", "https://alesamodio-db3-update.hf.space")  # receiver base URL
CRON_SECRET = os.getenv("CRON_SECRET", "")          # receiver's /run secret (set in receiver Space)
HF_TOKEN = os.getenv("HF_TOKEN", "")        # READ token if receiver is PRIVATE (set in this trigger Space)

# Timings (tune if needed; can also override via query params)
DEFAULT_WARMUP_WAIT_S = int(os.getenv("WARMUP_WAIT_S", "180"))   # quiet wait after first wake
READY_INTERVAL_S      = int(os.getenv("READY_INTERVAL_S", "20")) # poll cadence
READY_MAX_ATTEMPTS    = int(os.getenv("READY_MAX_ATTEMPTS", "15"))  # ~5 min total

def _headers():
    return {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}

@app.get("/")
def home():
    return {"status": "running", "message": "HF trigger alive"}

@app.get("/run")
def run():
    """
    Wake receiver once -> quiet wait -> poll /ready -> fire /run?secret=...
    Optional query overrides:
      warmup_wait (int seconds), max_attempts, interval
    """
    log = []
    warmup_wait = int(os.getenv("WARMUP_WAIT_S", str(DEFAULT_WARMUP_WAIT_S)))
    # allow query overrides without importing FastAPI Request
    try:
        import starlette.requests
        # no-op; just to avoid extra dependency notes
    except Exception:
        pass

    # simple query parsing without typing Request
    from fastapi import Request
    def get_query():
        # tiny helper because we didn't annotate Request in signature
        import inspect
        frame = inspect.currentframe().f_back
        req = frame.f_locals.get('request')  # not available in this simple handler
        return {}
    # actual overrides via os env only to keep it minimal
    max_attempts = READY_MAX_ATTEMPTS
    interval = READY_INTERVAL_S

    # --- 1) Wake once (GET /) ---
    try:
        r = requests.get(f"{BASE}/", headers=_headers(), timeout=10)
        log.append(f"wake: {r.status_code}")
    except Exception as e:
        log.append(f"wake_err: {e}")

    # --- 2) Quiet wait to let models load ---
    time.sleep(warmup_wait)
    log.append(f"quiet_wait_done: {warmup_wait}s")

    # --- 3) Poll /ready ---
    ready = False
    last_text = ""
    for i in range(1, max_attempts + 1):
        try:
            rr = requests.get(f"{BASE}/ready", headers=_headers(), timeout=10)
            last_text = rr.text
            if rr.ok and '"ready"' in rr.text:
                log.append(f"ready_yes_at_attempt:{i}")
                ready = True
                break
            else:
                log.append(f"ready_no_{i}: {rr.status_code} {rr.text[:80]}")
        except Exception as e:
            log.append(f"ready_err_{i}: {e}")
        time.sleep(interval)

    if not ready:
        return {
            "status": "not_ready",
            "last_ready_response": last_text[:200],
            "log": log
        }

    # --- 4) Fire /run with secret ---
    try:
        run_url = f"{BASE}/run?secret={CRON_SECRET}"
        final = requests.get(run_url, headers=_headers(), timeout=600)
        return {
            "status": "ok",
            "code": final.status_code,
            "body": (final.text[:2000] if final.text else ""),
            "log": log
        }
    except Exception as e:
        return {"status": "run_error", "error": str(e), "log": log}