from fastapi import FastAPI, HTTPException, Depends, Body, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles from fastapi.security import OAuth2PasswordRequestForm import uvicorn from typing import Dict, Any import os import logging from datetime import timedelta # Import interfaces from modules.gateway_interface import get_gateway_interface from modules.agentservice_interface import get_agent_service # Import auth module from auth import ( create_access_token, get_current_active_user, get_user_context, ACCESS_TOKEN_EXPIRE_MINUTES ) # Import models - generisch importieren import modules.gateway_model as gateway_model # Import router modules from routes.attributes import router as attributes_router from routes.workspace import router as workspace_router from routes.agent import router as agent_router from routes.file import router as file_router from routes.prompt import router as prompt_router from routes.workflow import router as workflow_router from routes.mandate import router as mandate_router # Konfiguration des Loggers logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[logging.StreamHandler()] ) 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-gateway-fsahaxgbfee8djea.germanywestcentral-01.azurewebsites.net"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Statischer Folder für Frontend os.makedirs(os.path.join(os.getcwd(), "static"), exist_ok=True) app.mount("/static", StaticFiles(directory="static"), name="static") # 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.0" # Token-Endpunkt für Login @app.post("/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"} # Benutzerregistrierung @app.post("/api/users/register", response_model=gateway_model.User, tags=["General"]) async def register_user(user_data: dict = Body(...), current_user: Dict[str, Any] = Depends(get_current_active_user)): """Neuen Benutzer registrieren""" # Nur Benutzer des gleichen Mandanten dürfen erstellt werden mandate_id, user_id = await get_user_context(current_user) # Gateway-Interface mit Benutzerkontext initialisieren gateway = get_gateway_interface(mandate_id, user_id) if "username" not in user_data or "password" not in user_data: raise HTTPException(status_code=400, detail="Benutzername und Passwort erforderlich") try: new_user = gateway.create_user( username=user_data["username"], password=user_data["password"], email=user_data.get("email"), full_name=user_data.get("full_name"), language=user_data.get("language", "de") ) return new_user except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) # Benutzerinfo abrufen @app.get("/api/users/me", response_model=Dict[str, Any], tags=["General"]) async def read_users_me(current_user: Dict[str, Any] = Depends(get_current_active_user)): return current_user # Alle Router einbinden app.include_router(attributes_router) app.include_router(workspace_router) app.include_router(agent_router) app.include_router(file_router) app.include_router(prompt_router) app.include_router(workflow_router) app.include_router(mandate_router) # Event handler beim Herunterfahren @app.on_event("shutdown") async def shutdown_event(): """Führt Aufräumarbeiten beim Herunterfahren der Anwendung durch""" # Holen des AgentService ohne Kontext (für Aufräumarbeiten) agent_service = get_agent_service() # HTTP-Client des AgentService schließen await agent_service.close() logger.info("Anwendung wurde heruntergefahren") if __name__ == "__main__": uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)