#!/usr/bin/env python3 """ scripts/heartbeat_ping.py — Health monitor, warmup probe, and latency benchmark for HF Spaces. Usage: python3 scripts/heartbeat_ping.py --url https://abalanescu-flow.hf.space python3 scripts/heartbeat_ping.py --url https://abalanescu-flow.hf.space --warmup python3 scripts/heartbeat_ping.py --url https://abalanescu-flow.hf.space --chat --stream """ import os import sys import time import json import argparse import urllib.request import urllib.error def make_request(url: str, headers: dict = None, data: dict = None, stream: bool = False): headers = headers or {} post_data = json.dumps(data).encode("utf-8") if data is not None else None if data is not None and "Content-Type" not in headers: headers["Content-Type"] = "application/json" req = urllib.request.Request(url, data=post_data, headers=headers) t0 = time.time() try: with urllib.request.urlopen(req, timeout=60) as resp: elapsed = round((time.time() - t0) * 1000, 2) if stream: print(f"[HTTP {resp.status}] Streaming response ({elapsed}ms TTFB):") full_text = [] for line in resp: decoded = line.decode("utf-8").strip() if not decoded: continue if decoded == "data: [DONE]": break if decoded.startswith("data: "): try: payload = json.loads(decoded[6:]) delta = payload.get("choices", [{}])[0].get("delta", {}) content = delta.get("content", "") if content: sys.stdout.write(content) sys.stdout.flush() full_text.append(content) except Exception: pass sys.stdout.write("\n") return {"status": resp.status, "latency_ms": elapsed, "streamed": "".join(full_text)} else: body = resp.read().decode("utf-8") try: parsed = json.loads(body) except Exception: parsed = body return {"status": resp.status, "latency_ms": elapsed, "data": parsed} except urllib.error.HTTPError as e: elapsed = round((time.time() - t0) * 1000, 2) err_body = e.read().decode("utf-8", errors="replace") return {"status": e.code, "latency_ms": elapsed, "error": err_body} except Exception as e: elapsed = round((time.time() - t0) * 1000, 2) return {"status": 0, "latency_ms": elapsed, "error": str(e)} def main(): parser = argparse.ArgumentParser(description="ZeroGPU Space Heartbeat and Latency Probe") parser.add_argument("--url", default="https://abalanescu-flow.hf.space", help="Base URL of HF Space") parser.add_argument("--key", default=None, help="Bearer auth token (defaults to FLOW_API_KEY or HF_TOKEN)") parser.add_argument("--warmup", action="store_true", help="Send 1-token warm-up probe") parser.add_argument("--chat", action="store_true", help="Send a test chat completion prompt") parser.add_argument("--prompt", default="Hello! Identify yourself and your model architecture in one short sentence.", help="Prompt for chat probe") parser.add_argument("--stream", action="store_true", help="Test streaming response via SSE") parser.add_argument("--model", default=None, help="Model ID override") args = parser.parse_args() base_url = args.url.rstrip("/") token = args.key or os.environ.get("FLOW_API_KEY") or os.environ.get("HF_TOKEN") headers = {"Authorization": f"Bearer {token}"} if token else {} print(f"=== ZeroGPU Space Probe: {base_url} ===") # 1. Health Probe health_url = f"{base_url}/v1/health" print(f"\n[1/3] Checking Health ({health_url})...") health_res = make_request(health_url) print(f"Status: HTTP {health_res['status']} in {health_res['latency_ms']}ms") if "data" in health_res: print(f"Data: {json.dumps(health_res['data'], indent=2)}") # 2. Models List models_url = f"{base_url}/v1/models" print(f"\n[2/3] Querying Models ({models_url})...") models_res = make_request(models_url, headers=headers) print(f"Status: HTTP {models_res['status']} in {models_res['latency_ms']}ms") models = [] if "data" in models_res and isinstance(models_res["data"], dict): models = [m.get("id") for m in models_res["data"].get("data", [])] print(f"Available Models ({len(models)}): {', '.join(models[:5])}") # 3. Warmup or Chat if args.warmup: warmup_url = f"{base_url}/v1/warmup" print(f"\n[3/3] Sending Warmup Probe ({warmup_url})...") warm_res = make_request(warmup_url, headers=headers, data={}) print(f"Status: HTTP {warm_res['status']} in {warm_res['latency_ms']}ms") if "data" in warm_res: print(f"Warmup Result: {json.dumps(warm_res['data'], indent=2)}") if args.chat: chat_url = f"{base_url}/v1/chat/completions" target_model = args.model or (models[0] if models else "default") print(f"\n[3/3] Chat Completion Probe on '{target_model}' (stream={args.stream})...") payload = { "model": target_model, "messages": [{"role": "user", "content": args.prompt}], "temperature": 0.7, "max_tokens": 128, "stream": args.stream, } chat_res = make_request(chat_url, headers=headers, data=payload, stream=args.stream) if not args.stream: print(f"Status: HTTP {chat_res['status']} in {chat_res['latency_ms']}ms") if "data" in chat_res: print(f"Response:\n{json.dumps(chat_res['data'], indent=2)}") elif "error" in chat_res: print(f"Error: {chat_res['error']}") print("\n=== Probe Finished ===") if __name__ == "__main__": main()