from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from fastapi.middleware.cors import CORSMiddleware import uvicorn import os from pathlib import Path import mimetypes from utils import log from chat_handler import router as chat_router # ← start_session & chat from admin_routes import router as admin_router, start_cleanup_task from spark_startup import run_in_thread from session import session_store, start_session_cleanup from config_provider import ConfigProvider # ===================== Environment Setup ===================== def setup_environment(): """Setup environment based on work_mode""" cfg = ConfigProvider.get() log("=" * 60) log(f"🚀 Flare Starting in {cfg.global_config.work_mode.upper()} mode") log("=" * 60) if cfg.global_config.is_cloud_mode(): log("☁️ Cloud Mode: Using HuggingFace Secrets") log("📌 Required secrets: JWT_SECRET, FLARE_TOKEN_KEY, SPARK_TOKEN") else: log("🏢 On-Premise Mode: Using .env file") if not Path(".env").exists(): log("⚠️ WARNING: .env file not found!") log("📌 Copy .env.example to .env and configure it") # Run setup setup_environment() # Fix MIME types for JavaScript files mimetypes.add_type("application/javascript", ".js") mimetypes.add_type("text/css", ".css") app = FastAPI( title="Flare Orchestration Service", version="0.1.0", description="LLM-driven intent & API flow engine (bootstrap)", ) # CORS for development if os.getenv("ENVIRONMENT") == "development": app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:4200"], # Angular dev server allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) log("🔧 CORS enabled for development") run_in_thread() start_cleanup_task() # Activity log cleanup # ---------------- Core chat/session routes -------------------------- app.include_router(chat_router, prefix="/api") # ---------------- Admin API routes ---------------------------------- app.include_router(admin_router) # ---------------- Health probe (HF Spaces watchdog) ----------------- @app.get("/") def health_check(): return {"status": "ok"} # ---------------- Serve Angular UI if exists ------------------------ static_path = Path("static") log(f"🔍 Checking for static directory at: {static_path.absolute()}") log(f"🔍 Static directory exists: {static_path.exists()}") if static_path.exists() and static_path.is_dir(): # List files in static directory files = list(static_path.iterdir()) log(f"📁 Files in static directory: {[f.name for f in files]}") # Check for index.html index_path = static_path / "index.html" log(f"🔍 index.html exists: {index_path.exists()}") # Mount entire static directory app.mount("/static", StaticFiles(directory="static"), name="static") # Serve static files (Angular assets) - only if assets directory exists assets_path = static_path / "assets" if assets_path.exists() and assets_path.is_dir(): app.mount("/assets", StaticFiles(directory=str(assets_path)), name="assets") # Root path - serve index.html @app.get("/") async def serve_root(): index_path = static_path / "index.html" if index_path.exists(): log("📄 Serving index.html") return FileResponse(str(index_path), media_type="text/html") log("⚠️ index.html not found, returning health check") return {"status": "ok", "sessions": len(session_store._sessions)} # Fallback to health check # Serve JS files with correct MIME type @app.get("/{filename:path}.js") async def serve_js(filename: str): js_path = static_path / f"{filename}.js" if js_path.exists(): return FileResponse(str(js_path), media_type="application/javascript") return {"error": "JS file not found"}, 404 # Serve CSS files with correct MIME type @app.get("/{filename:path}.css") async def serve_css(filename: str): css_path = static_path / f"{filename}.css" if css_path.exists(): return FileResponse(str(css_path), media_type="text/css") return {"error": "CSS file not found"}, 404 # Catch-all route for Angular routing (must be last!) @app.get("/{full_path:path}") async def serve_angular(full_path: str): # Don't catch API routes if full_path.startswith("api/") or full_path in ["start_session", "chat", "health"]: return {"error": "Not found"}, 404 # Return Angular index.html for all other routes index_path = static_path / "index.html" if index_path.exists(): return FileResponse(str(index_path), media_type="text/html") return {"error": "UI not found"}, 404 else: log("⚠️ Static directory not found") # No UI built, just health endpoint @app.get("/") def health_check(): return {"status": "ok", "message": "UI not found. Build Angular app first."} if __name__ == "__main__": log("🌐 Starting Flare backend …") uvicorn.run(app, host="0.0.0.0", port=7860)