Initial commit: core-api service extraction from portainer-core
Build and Push / build (release) Successful in 43s
Build and Push / build (release) Successful in 43s
This commit is contained in:
+177
@@ -0,0 +1,177 @@
|
||||
"""
|
||||
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.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.
|
||||
|
||||
### 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) # /web-scraper/scrape
|
||||
app.include_router(infrastructure_controller.router) # /infrastructure/*
|
||||
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__
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user