""" LLM Monitor - Dashboard to monitor Ollama models. FastAPI application entry point. """ import logging from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.docs import get_redoc_html from pathlib import Path import os # Logging configuration logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Import API routes from app.api.health import router as health_router from app.api.models import router as models_router from app.config import settings # Create FastAPI app app = FastAPI( title="LLM Monitor API", description="Dashboard and API for monitoring Ollama LLM models", version="1.0.0", docs_url="/docs", redoc_url=None, openapi_url="/openapi.json" ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS.split(","), allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Register API routes app.include_router(health_router, prefix="/api/v1", tags=["health"]) app.include_router(models_router, prefix="/api/v1", tags=["models"]) # Serve static files static_path = Path(__file__).parent / "app" / "web" / "static" if static_path.exists(): app.mount("/static", StaticFiles(directory=static_path), name="static") # Serve web pages templates_path = Path(__file__).parent / "app" / "web" / "templates" @app.get("/") async def root(): """Primary page: models currently loaded in memory (ollama ps).""" return FileResponse(templates_path / "models_running.html") @app.get("/dashboard") async def dashboard(): """Legacy alias for the primary page.""" return FileResponse(templates_path / "models_running.html") @app.get("/models-available") async def models_available_page(): """Page listing models available on disk.""" return FileResponse(templates_path / "index.html") @app.get("/models-running") async def models_running_page(): """Page dedicated to models resident in memory (ollama ps).""" return FileResponse(templates_path / "models_running.html") @app.get("/manifest.webmanifest", include_in_schema=False) async def web_manifest(): """PWA web manifest.""" return FileResponse(static_path / "manifest.webmanifest", media_type="application/manifest+json") @app.get("/service-worker.js", include_in_schema=False) async def service_worker(): """PWA service worker with root scope.""" return FileResponse(static_path / "js" / "service-worker.js", media_type="application/javascript") @app.get("/redoc", include_in_schema=False) async def redoc_html(): """ReDoc documentation using a stable bundle.""" return get_redoc_html( openapi_url=app.openapi_url, title=f"{app.title} - ReDoc", redoc_js_url="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js", with_google_fonts=False, ) @app.get("/favicon.ico", include_in_schema=False) async def favicon(): """Application favicon.""" return FileResponse(static_path / "favicon.ico") # Event hooks @app.on_event("startup") async def startup_event(): logger.info("LLM Monitor started") logger.info(f"Ollama host: {settings.OLLAMA_HOST}") @app.on_event("shutdown") async def shutdown_event(): logger.info("LLM Monitor stopped") if __name__ == "__main__": import uvicorn uvicorn.run( "main:app", host=settings.API_HOST, port=settings.API_PORT, reload=settings.ENVIRONMENT == "development", log_level=settings.LOG_LEVEL.lower() )