from fastapi import APIRouter, HTTPException, Depends, Body, Path from typing import List, Dict, Any from fastapi import status import asyncio import uuid # Import auth module from auth import get_current_active_user, get_user_context # Import interfaces from modules.lucydom_interface import get_lucydom_interface from modules.agentservice_interface import get_agentservice_interface # Import models import modules.lucydom_model as lucydom_model # Router für Workflow-Endpunkte erstellen router = APIRouter( prefix="/api/workflows", tags=["Workflow"], responses={404: {"description": "Not found"}} ) @router.post("/run", response_model=Dict[str, Any]) async def run_workflow( workflow_request: lucydom_model.WorkflowRequest = Body(...), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Führt einen Workflow mit den ausgewählten Agenten und Dateien aus""" mandate_id, user_id = await get_user_context(current_user) # Populate the fields from user context workflow_request.mandate_id = mandate_id workflow_request.user_id = user_id workflow_request.id = str(uuid.uuid4()) # Generate a unique ID # LucyDOM-Interface mit Benutzerkontext initialisieren lucy_interface = get_lucydom_interface(mandate_id, user_id) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) workspace = lucy_interface.get_workspace(workflow_request.workspace_id) if not workspace: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workspace mit ID {workflow_request.workspace_id} nicht gefunden" ) # Prüfen, ob Dateien existieren files = [] for file_id in workflow_request.files: file = lucy_interface.get_file(file_id) if not file: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Datei mit ID {file_id} nicht gefunden" ) files.append(file) # Prüfen, ob Agenten existieren agents = [] for agent_id in workflow_request.agents: agent = lucy_interface.get_agent(agent_id) if not agent: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Agent mit ID {agent_id} nicht gefunden" ) agents.append(agent) # Workflow ID generieren workflow_id = str(uuid.uuid4()) # Workflow starten (asynchron) workflow_task = asyncio.create_task( agent_service.execute_workflow( workflow_id, workflow_request.prompt, agents, files ) ) # Sofort eine Antwort zurückgeben return { "workflow_id": workflow_id, "status": "running", "message": "Workflow wurde gestartet" } @router.get("/{workflow_id}/status") async def get_workflow_status( workflow_id: str, current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Status eines laufenden Workflows abrufen""" mandate_id, user_id = await get_user_context(current_user) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) status = agent_service.get_workflow_status(workflow_id) if not status: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workflow mit ID {workflow_id} nicht gefunden" ) return status @router.get("/{workflow_id}/logs", response_model=List[Dict[str, Any]]) async def get_workflow_logs( workflow_id: str, current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Protokolle eines Workflows abrufen""" mandate_id, user_id = await get_user_context(current_user) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) logs = agent_service.get_workflow_logs(workflow_id) if logs is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workflow mit ID {workflow_id} nicht gefunden" ) return logs @router.get("/{workflow_id}/results", response_model=List[Dict[str, Any]]) async def get_workflow_results( workflow_id: str, current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Ergebnisse eines Workflows abrufen""" mandate_id, user_id = await get_user_context(current_user) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) results = agent_service.get_workflow_results(workflow_id) if results is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workflow mit ID {workflow_id} nicht gefunden" ) return results @router.post("/{workflow_id}/stop", response_model=Dict[str, Any]) async def stop_workflow( workflow_id: str = Path(..., description="ID des zu stoppenden Workflows"), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Stoppt einen laufenden Workflow""" mandate_id, user_id = await get_user_context(current_user) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) result = agent_service.stop_workflow(workflow_id) if not result: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workflow mit ID {workflow_id} nicht gefunden oder bereits beendet" ) return { "workflow_id": workflow_id, "status": "stopped", "message": "Workflow wurde gestoppt" } @router.post("/{workflow_id}/user-input", response_model=Dict[str, Any]) async def submit_user_input( workflow_id: str = Path(..., description="ID des Workflows"), user_input: Dict[str, Any] = Body(...), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """ Ermöglicht es dem Benutzer, Eingaben für einen laufenden Workflow zu senden. Dies wird verwendet, wenn der User-Agent im Workflow angesprochen wird. Der Request-Body sollte folgendes Format haben: { "message": "Die Antwort des Benutzers", "additional_files": [1, 2, 3] // Optional: IDs zusätzlicher Dateien } """ mandate_id, user_id = await get_user_context(current_user) # Überprüfen, ob die erforderlichen Felder vorhanden sind if "message" not in user_input: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Das Feld 'message' ist erforderlich" ) message = user_input["message"] additional_file_ids = user_input.get("additional_files", []) # LucyDOM-Interface mit Benutzerkontext initialisieren lucy_interface = get_lucydom_interface(mandate_id, user_id) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) # Zusätzliche Dateien einsammeln, wenn vorhanden additional_files = [] if additional_file_ids: for file_id in additional_file_ids: file = lucy_interface.get_file(file_id) if not file: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Zusätzliche Datei mit ID {file_id} nicht gefunden" ) additional_files.append(file) # Benutzereingabe verarbeiten try: result = await agent_service.process_user_input(workflow_id, message, additional_files) if not result: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Workflow {workflow_id} wartet nicht auf Benutzereingabe oder existiert nicht" ) return { "workflow_id": workflow_id, "status": "processing", "message": "Benutzereingabe wurde empfangen und wird verarbeitet" } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Fehler bei der Verarbeitung der Benutzereingabe: {str(e)}" ) @router.get("/{workflow_id}/data-statistics", response_model=Dict[str, Any]) async def get_workflow_data_statistics( workflow_id: str, current_user: Dict[str, Any] = Depends(get_current_active_user) ): """ Gibt Statistiken über die übertragenen Datenmengen für einen Workflow zurück. """ mandate_id, user_id = await get_user_context(current_user) # AgentService mit Benutzerkontext initialisieren agent_service = get_agentservice_interface(mandate_id, user_id) status = agent_service.get_workflow_status(workflow_id) if not status: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Workflow mit ID {workflow_id} nicht gefunden" ) # Gib nur die Datenstatistiken zurück if "data_stats" in status: return { "workflow_id": workflow_id, "data_stats": status["data_stats"] } else: return { "workflow_id": workflow_id, "data_stats": { "sent_bytes": 0, "received_bytes": 0 } }