Spaces:
Sleeping
Sleeping
| # 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 ====== | |
| 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 ====== | |
| async def root(): | |
| return {"status": "ok"} | |
| async def health(): | |
| return {"healthy": True} | |
| 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)) | |