import os os.environ['EXCEPTIONGROUP_NO_PATCH']='1' import os import logging import time import sys import uuid from dotenv import load_dotenv from logging.handlers import RotatingFileHandler from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from starlette.middleware.sessions import SessionMiddleware from fastapi.staticfiles import StaticFiles from tplbot.initializer import initialize from tplbot.routes import router from tplbot.metrics import router as metrics_router from tplbot.admin.views import router as admin_router # ── 1) Load env & configure logging ─────────────────────────────────────── load_dotenv() # ── 1) Configure logging to stdout only ───────────────────────────────── logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s [%(request_id)s] %(message)s", stream=sys.stdout, force=True ) logger = logging.getLogger() # root logger class RequestIdFilter(logging.Filter): def filter(self, record): if not hasattr(record, "request_id"): record.request_id = "N/A" return True logger.addFilter(RequestIdFilter()) # ── End stdout-only logging setup ──────────────────────────────────────── # ── 2) Create app & add middleware ──────────────────────────────────────── app = FastAPI() app.include_router(metrics_router, prefix="") app.include_router(admin_router) # 2a) CORS, sessions, static as before app.add_middleware( CORSMiddleware, allow_origin_regex=".*", # ← works with credentials allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.add_middleware( SessionMiddleware, secret_key = os.getenv("SESSION_SECRET", "change-me-change-me"), # ≥16 bytes same_site = "none", # third-party cookie allowed in HF iframe https_only = True, # sets the Secure flag # max_age = 60*60*24*14 # (optional) 14-day default ) app.mount("/static", StaticFiles(directory="static"), name="static") # 2b) Logging middleware @app.middleware("http") async def log_requests(request: Request, call_next): rid = uuid.uuid4().hex[:8] request.state.request_id = rid logger.info(f"→ {request.method} {request.url.path}", extra={"request_id": rid}) start = time.perf_counter() response = await call_next(request) elapsed_ms = (time.perf_counter() - start) * 1000 logger.info( f"← {request.method} {request.url.path} {response.status_code} in {elapsed_ms:.1f}ms", extra={"request_id": rid} ) return response # ── 3) Initialize and mount routes ──────────────────────────────────────── initialize() app.include_router(router) # ── 4) UVicorn entrypoint ───────────────────────────────────────────────── if __name__ == "__main__": import uvicorn uvicorn.run("app:app", host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), reload=True)