""" Main FastAPI application for Core Code API """ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from contextlib import asynccontextmanager from src.config import get_settings from src.logging_config import setup_logging, get_logger from src.models.ollama_client import get_ollama_client, close_ollama_client from src.controllers.infrastructure_controller import infrastructure_controller from src.controllers.tools_controller import tools_controller from src.controllers.health_controller import health_controller from src.controllers.static_controller import static_controller from src.controllers.ai_controller import router as ai_router from src.controllers.housekeeping_controller import housekeeping_controller from src.security import initialize_oidc # Initialize settings settings = get_settings() # Setup logging setup_logging(settings.log_level) logger = get_logger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """ Application lifespan manager for startup/shutdown events Args: app: FastAPI application instance """ # Startup logger.info("=" * 60) logger.info(f"Starting {settings.app_name} v{settings.app_version}") logger.info(f"Debug mode: {settings.debug}") logger.info(f"Log level: {settings.log_level}") logger.info(f"Ollama URL: {settings.ollama_base_url}") logger.info("=" * 60) # Check Ollama connectivity ollama_client = get_ollama_client() ollama_healthy = await ollama_client.health_check() if ollama_healthy: logger.info("✓ Ollama connection successful") else: logger.warning("✗ Ollama connection failed - AI features may not work") # Initialize security (OIDC authentication) initialize_oidc(settings) yield # Shutdown logger.info("Shutting down application") await close_ollama_client() # Create FastAPI application app = FastAPI( title=settings.app_name, version=settings.app_version, description=""" Core Code API provides OpenAPI-compatible functions and AI orchestration for Open WebUI. ## Features ### OpenAI-Compatible API (v1) - `/v1/chat/completions` - Chat completions with streaming support - `/v1/models` - List available models Compatible with OpenAI client libraries and Open WebUI. ### Conversation Memory (Phase 2) - `/v1/conversations/{id}` - Get conversation history - `/v1/conversations/{id}/search` - Semantic search within conversation - `/v1/conversations/search` - Search across all conversations - `/v1/conversations/{id}/stats` - Get conversation statistics - `/v1/conversations/{id}/consolidate` - Manual consolidation - `DELETE /v1/conversations/{id}` - Delete conversation Multi-tier memory system: - **Tier 1**: Fast in-memory buffer (last 10 turns) - **Tier 2/3**: Unified Qdrant storage (persistent + semantic search) ### Infrastructure Management **Read Endpoints:** - `GET /infrastructure/health` - Check Portainer & NPM connectivity - `GET /infrastructure/services` - List all deployed services - `GET /infrastructure/services/{name}` - Get service details - `GET /infrastructure/ports` - List allocated ports - `GET /infrastructure/domains` - List configured domains **Write Endpoints (Admin Only):** - `POST /infrastructure/services` - Deploy new service from compose YAML - `PUT /infrastructure/services/{name}` - Update existing service - `DELETE /infrastructure/services/{name}` - Remove service and stack - `POST /infrastructure/proxy` - Create proxy host with optional SSL Automates infrastructure operations via Portainer and Nginx Proxy Manager APIs. ### Home Automation (Housekeeping) **Read Endpoints:** - `GET /housekeeping/health` - Check Home Assistant connectivity - `GET /housekeeping/devices` - List devices (filter by domain, area) - `GET /housekeeping/devices/{entity_id}` - Get device details - `GET /housekeeping/areas` - List areas/rooms - `GET /housekeeping/scenes` - List scenes - `GET /housekeeping/scripts` - List scripts - `GET /housekeeping/automations` - List automations - `GET /housekeeping/history` - Get state history **Write Endpoints (Admin Only):** - `POST /housekeeping/devices/{entity_id}/control` - Control device - `POST /housekeeping/scenes/{scene_id}/activate` - Activate scene - `POST /housekeeping/scripts/{script_id}/run` - Run script - `POST /housekeeping/automations/{automation_id}/toggle` - Enable/disable automation Abstracts Home Assistant for the Tatlock Housekeeper agent and other consumers. ### Web Scraper Intelligent web scraping with main content extraction. Perfect for extracting articles, documentation, and blog posts for LLM consumption. ## Authentication When OIDC authentication is enabled (oidc_enabled=true in config): - Infrastructure write endpoints require authentication - Use OAuth2/OIDC bearer token from Authentik - Admin group membership required for infrastructure operations ## Integration This API is designed to integrate with: - **Open WebUI**: Direct OpenAI API compatibility - **Open WebUI Functions**: Import via OpenAPI spec - **Open WebUI Pipelines**: Use as data source - **LangChain**: Compatible with standard HTTP tools ## Documentation - **OpenAPI Spec**: `/openapi.json` - **Swagger UI**: `/docs` - **ReDoc**: `/redoc` """, docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", lifespan=lifespan, debug=settings.debug, swagger_ui_init_oauth={ "clientId": settings.oidc_audience, "usePkceWithAuthorizationCodeGrant": True, } if settings.oidc_enabled else None ) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=settings.cors_credentials, allow_methods=settings.cors_methods, allow_headers=settings.cors_headers, ) # Include controller routers app.include_router(health_controller.router) # / and /health app.include_router(tools_controller.router) # /tools/* app.include_router(infrastructure_controller.router) # /infrastructure/* app.include_router(housekeeping_controller.router) # /housekeeping/* app.include_router(static_controller.router) # /static/* app.include_router(ai_router) # /ai/* # Global exception handler @app.exception_handler(Exception) async def global_exception_handler(request, exc): """ Catch-all exception handler for unhandled errors Args: request: The request that caused the exception exc: The exception instance Returns: JSON error response """ logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) return JSONResponse( status_code=500, content={ "detail": "Internal server error", "type": type(exc).__name__ } )