Testoo / app.py
Mustafa-albakkar's picture
Rename hf_space_app.py to app.py
cfd121c verified
Raw
History Blame Contribute Delete
3.87 kB
"""
Minimal HF Space for testing ONLY (no bot logic).
Deploy this as app.py in a new, throwaway HF Space (SDK: Gradio).
requirements.txt for this Space:
gradio
httpx
"""
import asyncio
import json
import os
import threading
from datetime import datetime, timezone
import gradio as gr
import httpx
# --- CONFIG: edit these two lines --------------------------------------
NORTHFLANK_BASE_URL = os.environ.get("NORTHFLANK_TEST_URL", "https://your-service.northflank.app")
TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "") # optional
INTERVAL_SECONDS = 300
# -------------------------------------------------------------------------
LOG_FILE = "connectivity_log.jsonl"
results_lock = threading.Lock()
latest_results = [] # kept in memory for the UI
async def check(name: str, url: str, timeout: float = 10.0) -> dict:
entry = {"check": name, "url": url, "time_utc": datetime.now(timezone.utc).isoformat()}
try:
async with httpx.AsyncClient(timeout=timeout) as client:
resp = await client.get(url)
entry["status"] = "ok" if resp.status_code == 200 else "http_error"
entry["http_status"] = resp.status_code
except Exception as e:
entry["status"] = "connect_error"
entry["error"] = f"{type(e).__name__}: {e}"
return entry
async def run_once() -> list[dict]:
checks = [
check("hf_to_northflank_ping", f"{NORTHFLANK_BASE_URL}/ping"),
check("hf_to_northflank_telegram_relay", f"{NORTHFLANK_BASE_URL}/check-telegram"),
]
if TELEGRAM_BOT_TOKEN:
checks.append(
check("hf_to_telegram_direct", f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getMe")
)
return await asyncio.gather(*checks)
def append_log(entries: list[dict]) -> None:
with open(LOG_FILE, "a", encoding="utf-8") as f:
for entry in entries:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
def background_loop():
async def loop():
while True:
results = await run_once()
append_log(results)
with results_lock:
latest_results.clear()
latest_results.extend(results)
await asyncio.sleep(INTERVAL_SECONDS)
asyncio.run(loop())
def get_status_text() -> str:
with results_lock:
if not latest_results:
return "لسه ما بدأ أول فحص... انتظر بضع ثواني وحدّث الصفحة."
lines = []
for r in latest_results:
line = f"**{r['check']}**: `{r['status']}`"
if "http_status" in r:
line += f" (HTTP {r['http_status']})"
if "error" in r:
line += f" — {r['error']}"
line += f" \n_{r['time_utc']}_"
lines.append(line)
return "\n\n".join(lines)
def get_log_tail() -> str:
if not os.path.exists(LOG_FILE):
return "لا يوجد سجل بعد."
with open(LOG_FILE, "r", encoding="utf-8") as f:
lines = f.readlines()
return "".join(lines[-30:]) or "لا يوجد سجل بعد."
threading.Thread(target=background_loop, daemon=True).start()
with gr.Blocks(title="Connectivity Test: HF <-> Northflank <-> Telegram") as demo:
gr.Markdown("## اختبار الاتصال الدوري: HF ↔ Northflank ↔ تيليجرام")
gr.Markdown(f"يفحص كل {INTERVAL_SECONDS} ثانية. اضغط تحديث لرؤية آخر نتيجة.")
status_box = gr.Markdown()
refresh_btn = gr.Button("تحديث النتائج")
log_box = gr.Textbox(label="آخر 30 سطر من السجل", lines=15)
refresh_btn.click(fn=get_status_text, outputs=status_box)
refresh_btn.click(fn=get_log_tail, outputs=log_box)
demo.load(fn=get_status_text, outputs=status_box)
demo.load(fn=get_log_tail, outputs=log_box)
demo.launch()