API
This commit is contained in:
65
app/main.py
Normal file
65
app/main.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from app.config import settings
|
||||
from app.routers import analytics, auth, distractions, proactive, sessions, steps, tasks
|
||||
from app.services.db import close_pool, get_pool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
await get_pool()
|
||||
print(f"APNs config → KEY_ID={settings.APNS_KEY_ID or '(empty)'!r} "
|
||||
f"TEAM_ID={settings.APNS_TEAM_ID or '(empty)'!r} "
|
||||
f"P8_PATH={settings.APNS_P8_PATH or '(empty)'!r} "
|
||||
f"SANDBOX={settings.APNS_SANDBOX} "
|
||||
f"BUNDLE={settings.APPLE_BUNDLE_ID}")
|
||||
yield
|
||||
await close_pool()
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="LockInBro API",
|
||||
version="1.0.0",
|
||||
root_path="/api/v1",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
@app.exception_handler(Exception)
|
||||
async def llm_error_handler(request: Request, exc: Exception):
|
||||
# Surface LLM provider errors as 502 instead of 500
|
||||
exc_name = type(exc).__name__
|
||||
if "ClientError" in exc_name or "APIError" in exc_name or "APIConnectionError" in exc_name:
|
||||
return JSONResponse(status_code=502, content={"detail": f"LLM provider error: {exc}"})
|
||||
if isinstance(exc, RuntimeError) and "No LLM API key" in str(exc):
|
||||
return JSONResponse(status_code=503, content={"detail": str(exc)})
|
||||
raise exc
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def log_client_info(request: Request, call_next):
|
||||
real_ip = request.headers.get("cf-connecting-ip", request.headers.get("x-forwarded-for", "unknown"))
|
||||
ua = request.headers.get("user-agent", "unknown")
|
||||
response = await call_next(request)
|
||||
if request.url.path != "/api/v1/health":
|
||||
print(f"[REQ] {request.method} {request.url.path} → {response.status_code} | ip={real_ip} ua={ua[:80]}")
|
||||
return response
|
||||
|
||||
|
||||
app.include_router(auth.router)
|
||||
app.include_router(tasks.router)
|
||||
app.include_router(steps.router)
|
||||
app.include_router(sessions.router)
|
||||
app.include_router(distractions.router)
|
||||
app.include_router(proactive.router)
|
||||
app.include_router(analytics.router)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {"status": "ok"}
|
||||
Reference in New Issue
Block a user