# servr.py — FastAPI entrypoint (HF Spaces friendly) # - Start bot (botsinyal/botsignal) # - Start summary guard ala /lb dari summary_daily.py (cek tiap 15 menit; kirim H-1 sekali setelah >=06:00 WIB) # - Sediakan endpoint /summary/force untuk trigger manual import os import asyncio from datetime import date, timedelta, datetime from zoneinfo import ZoneInfo from fastapi import FastAPI, HTTPException, Query # ========= Import bot core (dukung dua nama modul) ========= client = None start_bot_background = None _last_import_err = None for mod in ("botsinyal", "botsignal"): try: m = __import__(mod, fromlist=["*"]) client = getattr(m, "client", None) start_bot_background = getattr(m, "start_bot_background", None) if client is not None and start_bot_background is not None: print(f"[SERVER] imported bot core from {mod}") break except Exception as e: _last_import_err = e if client is None or start_bot_background is None: raise RuntimeError(f"Cannot import bot client/startup ({_last_import_err})") # ========= Import summary guard dari summary_daily ========= try: from summary_daily import start_summary_guard, compute_summary_for_date, render_telegram_html except Exception as e: raise RuntimeError(f"Cannot import summary helpers: {e}") app = FastAPI(title="Telegram Curator Health (HF Spaces)") # ====== ENV ====== JAKARTA_TZ = ZoneInfo("Asia/Jakarta") SUMMARY_CHAT_ID = os.environ.get("SUMMARY_CHAT_ID") # contoh: -100123..., atau @nama_channel TARGET_CHANNEL_FALLBACK = os.environ.get("TARGET_CHANNEL", "@MidasTouchsignalll") # ====== Startup ====== @app.on_event("startup") async def startup(): # 1) start bot utama (listener, autotrack, dsb) await start_bot_background() # 2) aktifkan guard loop ala /lb (cek tiap 15 menit, idempotent) asyncio.create_task(start_summary_guard(client, interval_sec=900, fallback_chat=TARGET_CHANNEL_FALLBACK)) print("[SERVER] ready (summary guard armed)") # ====== Routes ====== @app.get("/") async def root(): return {"status": "ok"} @app.get("/health") async def health(): return {"healthy": True} @app.post("/summary/force") async def force_summary(day: str | None = Query(default=None, description="YYYY-MM-DD (lokal WIB), default H-1")): """ Trigger kirim summary manual. - Tanpa 'day' -> rekap H-1 (lokal WIB) - Format 'day' = 'YYYY-MM-DD' """ if not SUMMARY_CHAT_ID and not TARGET_CHANNEL_FALLBACK: raise HTTPException(status_code=400, detail="No SUMMARY_CHAT_ID or TARGET_CHANNEL set.") try: if day: target_day = date.fromisoformat(day) else: target_day = (datetime.now(JAKARTA_TZ) - timedelta(days=1)).date() data = compute_summary_for_date(target_day) text = render_telegram_html(data, label_date=target_day.strftime("%Y-%m-%d")) await client.send_message( entity=SUMMARY_CHAT_ID or TARGET_CHANNEL_FALLBACK, message=text, parse_mode="html" ) return {"ok": True, "sent_for": target_day.isoformat()} except Exception as e: raise HTTPException(status_code=500, detail=str(e))