""" backend/main.py --------------- FastAPI application entry point for Notiflow. Startup: 1. Loads .env file from project root (python-dotenv) 2. Configures logging 3. Mounts the notification API router 4. Exposes health check endpoint Run: uvicorn backend.main:app --reload The server expects to be started from the project root so that all relative imports (app/, agent/, services/, etc.) resolve correctly. """ from __future__ import annotations import logging import sys from pathlib import Path # --------------------------------------------------------------------------- # .env loader — must happen BEFORE any app.config import # --------------------------------------------------------------------------- try: from dotenv import load_dotenv _env_path = Path(__file__).parent.parent / ".env" load_dotenv(dotenv_path=_env_path, override=False) except ImportError: pass # python-dotenv not installed; env vars must be set externally # --------------------------------------------------------------------------- # Ensure project root is on sys.path when running via uvicorn # --------------------------------------------------------------------------- _PROJECT_ROOT = str(Path(__file__).parent.parent) if _PROJECT_ROOT not in sys.path: sys.path.insert(0, _PROJECT_ROOT) # --------------------------------------------------------------------------- # Logging # --------------------------------------------------------------------------- logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)-8s %(name)s — %(message)s", datefmt="%H:%M:%S", ) logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # FastAPI app # --------------------------------------------------------------------------- from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from api.notification_routes import router as notification_router app = FastAPI( title = "Notiflow API", description = ( "AI operations assistant for small businesses.\n\n" "Converts informal Hinglish business notifications into " "structured operations — powered by Amazon Nova 2 Lite." ), version = "1.0.0", docs_url = "/docs", redoc_url = "/redoc", ) # --------------------------------------------------------------------------- # CORS — allow all origins for hackathon demo # --------------------------------------------------------------------------- app.add_middleware( CORSMiddleware, allow_origins = ["*"], allow_credentials = True, allow_methods = ["*"], allow_headers = ["*"], ) # --------------------------------------------------------------------------- # Routers # --------------------------------------------------------------------------- app.include_router(notification_router) # --------------------------------------------------------------------------- # Health check # --------------------------------------------------------------------------- @app.get("/health", tags=["Meta"]) async def health(): """ Basic health check. Returns service status and configuration summary. """ from app.config import DEMO_MODE, BEDROCK_MODEL_ID, GEMINI_API_KEY, EXCEL_SYNC_FILE return { "status": "ok", "demo_mode": DEMO_MODE, "bedrock_model": BEDROCK_MODEL_ID, "gemini_enabled": bool(GEMINI_API_KEY), "excel_file": str(EXCEL_SYNC_FILE), } # --------------------------------------------------------------------------- # Frontend static files or root redirect # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # Frontend static files or root redirect # --------------------------------------------------------------------------- from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse _frontend_dist = Path(_PROJECT_ROOT) / "dashboard" / "dist" if _frontend_dist.is_dir(): # Serve Vite assets app.mount( "/assets", StaticFiles(directory=str(_frontend_dist / "assets")), name="assets" ) # Serve frontend index @app.get("/", include_in_schema=False) async def root(): return FileResponse(_frontend_dist / "index.html") else: @app.get("/", include_in_schema=False) async def root(): from fastapi.responses import RedirectResponse return RedirectResponse(url="/docs") # --------------------------------------------------------------------------- # Startup / shutdown events # --------------------------------------------------------------------------- @app.on_event("startup") async def on_startup(): from app.config import DEMO_MODE, GEMINI_API_KEY, EXCEL_SYNC_FILE logger.info("=" * 55) logger.info(" Notiflow API starting up") logger.info(" Demo mode : %s", DEMO_MODE) logger.info(" Gemini : %s", "enabled" if GEMINI_API_KEY else "disabled (no API key)") logger.info(" Excel file : %s", EXCEL_SYNC_FILE) logger.info("=" * 55) @app.on_event("shutdown") async def on_shutdown(): logger.info("Notiflow API shutting down.")