import os os.environ["NUMEXPR_MAX_THREADS"] = "12" from fastapi import FastAPI, HTTPException, Depends, Body, status, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse, FileResponse from fastapi.staticfiles import StaticFiles from fastapi.security import OAuth2PasswordRequestForm import uvicorn from typing import Dict, Any import logging from logging.handlers import RotatingFileHandler from datetime import timedelta import pathlib from modules.utility import APP_CONFIG from modules.gateway_interface import get_gateway_interface # Import auth module from modules.auth import ( create_access_token, get_current_active_user, get_user_context, ACCESS_TOKEN_EXPIRE_MINUTES ) # Import models - generisch importieren zur INITIALISIERUNG, auch wenn dummy! import modules.gateway_model as gateway_model import modules.lucydom_interface as lucydom_model def init_logging(): # Get log level from config (default to INFO if not found) log_level_name = APP_CONFIG.get("APP_LOG_LEVEL", "INFO") log_level = getattr(logging, log_level_name) # Configure handlers based on config handlers = [] # Add console handler if enabled if APP_CONFIG.get("Logging_CONSOLE_ENABLED", True): console_handler = logging.StreamHandler() handlers.append(console_handler) # Add file handler if enabled if APP_CONFIG.get("Logging_FILE_ENABLED", True): log_file = APP_CONFIG.get("APP_LOG_FILE", "app.log") rotation_size = int(APP_CONFIG.get("Logging_ROTATION_SIZE", 10485760)) # Default: 10MB backup_count = int(APP_CONFIG.get("Logging_BACKUP_COUNT", 5)) file_handler = RotatingFileHandler( log_file, maxBytes=rotation_size, backupCount=backup_count ) handlers.append(file_handler) # Configure the logger logging.basicConfig( level=log_level, format=APP_CONFIG.get("Logging_FORMAT", "%(asctime)s - %(levelname)s - %(name)s - %(message)s"), datefmt=APP_CONFIG.get("Logging_DATE_FORMAT", "%Y-%m-%d %H:%M:%S"), handlers=handlers ) # START APP init_logging() logger = logging.getLogger(__name__) app = FastAPI(title="PowerOn | Data Platform API", description="Backend-API für die Multi-Agent Platform von ValueOn AG") # CORS-Konfiguration für Frontend-Anfragen app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:8080","https://poweron-lucyagents-xxx.germanywestcentral-01.azurewebsites.net"], allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["*"], expose_headers=["*"], max_age=86400 # Erhöhung des Caching für Preflight-Anfragen ) # Statischer Folder für Frontend - mit absolutem Pfad arbeiten base_dir = pathlib.Path(__file__).parent static_folder = base_dir / "static" os.makedirs(static_folder, exist_ok=True) app.mount("/static", StaticFiles(directory=str(static_folder)), name="static") # Add a specific route for favicon.ico @app.get("/favicon.ico", include_in_schema=False) async def favicon(): favicon_path = static_folder / "favicon.ico" return FileResponse(str(favicon_path)) # Generelle Elements @app.get("/", tags=["General"]) async def root(): """API-Statusendpunkt""" return {"status": "online", "message": "Data Platform API ist aktiv"} @app.get("/api/test", tags=["General"]) async def get_test(): return "OK 1.5" @app.options("/{full_path:path}", tags=["General"]) async def options_route(full_path: str): return Response(status_code=200) # Token-Endpunkt für Login @app.post("/api/token", response_model=gateway_model.Token, tags=["General"]) async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): # Gateway-Interface ohne Kontext initialisieren gateway = get_gateway_interface() # Benutzer authentifizieren user = gateway.authenticate_user(form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Ungültiger Benutzername oder Passwort", headers={"WWW-Authenticate": "Bearer"}, ) # Token mit Mandanten-ID erstellen access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={ "sub": user["username"], "mandate_id": user["mandate_id"] }, expires_delta=access_token_expires ) return {"access_token": access_token, "token_type": "bearer"} # Benutzerinfo abrufen @app.get("/api/user/me", response_model=Dict[str, Any], tags=["General"]) async def read_user_me(current_user: Dict[str, Any] = Depends(get_current_active_user)): return current_user # Alle Router einbinden from routes.attributes import router as attributes_router app.include_router(attributes_router) from routes.mandates import router as mandate_router app.include_router(mandate_router) from routes.users import router as user_router app.include_router(user_router) from routes.files import router as file_router app.include_router(file_router) from routes.prompts import router as prompt_router app.include_router(prompt_router) from routes.workflows import router as workflow_router app.include_router(workflow_router) # Event handler beim Herunterfahren @app.on_event("shutdown") async def shutdown_event(): """Führt Aufräumarbeiten beim Herunterfahren der Anwendung durch""" logger.info("Anwendung wurde heruntergefahren") #if __name__ == "__main__": # uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)