361 lines
No EOL
12 KiB
Python
361 lines
No EOL
12 KiB
Python
import os
|
|
import json
|
|
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Query
|
|
from typing import List, Dict, Any, Optional
|
|
from fastapi import status
|
|
import asyncio
|
|
import uuid
|
|
from datetime import datetime
|
|
import logging
|
|
from dataclasses import dataclass
|
|
|
|
# Import interfaces
|
|
from modules.lucydom_interface import get_lucydom_interface
|
|
from modules.auth import get_current_active_user, get_user_context
|
|
from modules.chat import get_chat_manager
|
|
|
|
# Import models
|
|
import modules.lucydom_model as lucydom_model
|
|
|
|
# Logger konfigurieren
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Router für Workflow-Endpunkte erstellen
|
|
router = APIRouter(
|
|
prefix="/api/workflows",
|
|
tags=["Workflow"],
|
|
responses={404: {"description": "Not found"}}
|
|
)
|
|
|
|
@dataclass
|
|
class AppContext:
|
|
"""Kontext-Objekt für alle benötigten Verbindungen und Benutzerinformationen"""
|
|
mandate_id: int
|
|
user_id: int
|
|
interface_data: Any # LucyDOM Interface
|
|
interface_chat: Any # Chat Manager
|
|
|
|
async def get_context(current_user: Dict[str, Any]) -> AppContext:
|
|
"""
|
|
Erstellt ein zentrales Kontext-Objekt mit allen benötigten Interfaces
|
|
|
|
Args:
|
|
current_user: Aktueller Benutzer aus der Authentifizierung
|
|
|
|
Returns:
|
|
AppContext-Objekt mit allen benötigten Verbindungen
|
|
"""
|
|
mandate_id, user_id = await get_user_context(current_user)
|
|
interface_data = get_lucydom_interface(mandate_id, user_id)
|
|
interface_chat = get_chat_manager(mandate_id, user_id)
|
|
|
|
return AppContext(
|
|
mandate_id=mandate_id,
|
|
user_id=user_id,
|
|
interface_data=interface_data,
|
|
interface_chat=interface_chat
|
|
)
|
|
|
|
|
|
@router.get("", response_model=List[Dict[str, Any]])
|
|
async def list_workflows(current_user: Dict[str, Any] = Depends(get_current_active_user)):
|
|
"""Listet alle Workflows des Benutzers auf"""
|
|
context = await get_context(current_user)
|
|
|
|
# Workflows für den Benutzer abrufen
|
|
workflows = context.interface_data.get_workflows_by_user(context.user_id)
|
|
|
|
return workflows
|
|
|
|
@router.post("/{workflow_id}/user-input", response_model=Dict[str, Any])
|
|
async def submit_user_input(
|
|
workflow_id: Optional[str] = Path(None, description="ID des Workflows (optional)"),
|
|
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
|
|
oder einen neuen Workflow zu starten.
|
|
"""
|
|
context = await get_context(current_user)
|
|
|
|
# Improved logging
|
|
logger.info(f"Benutzereingabe für Workflow {workflow_id or 'neu'} empfangen")
|
|
|
|
try:
|
|
# Workflow mit dem Chat-Manager fortsetzen oder neu starten
|
|
workflow = await context.interface_chat.chat_run(user_input, workflow_id)
|
|
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Fehler bei der Verarbeitung der Benutzereingabe"
|
|
)
|
|
|
|
return {
|
|
"workflow_id": workflow.get("id"),
|
|
"status": "processing",
|
|
"message": "Benutzereingabe wurde empfangen und wird verarbeitet"
|
|
}
|
|
except HTTPException:
|
|
# HTTP-Exceptions weiterleiten
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Fehler bei der Verarbeitung der Benutzereingabe: {str(e)}", exc_info=True)
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Fehler bei der Verarbeitung der Benutzereingabe: {str(e)}"
|
|
)
|
|
|
|
@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"""
|
|
context = await get_context(current_user)
|
|
|
|
# Workflow laden
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
# Status auf "stopped" setzen
|
|
workflow["status"] = "stopped"
|
|
workflow["last_activity"] = datetime.now().isoformat()
|
|
|
|
# Workflow aktualisieren
|
|
context.interface_data.update_workflow(workflow_id, workflow)
|
|
|
|
return {
|
|
"workflow_id": workflow_id,
|
|
"status": "stopped",
|
|
"message": "Workflow wurde gestoppt"
|
|
}
|
|
|
|
@router.delete("/{workflow_id}", response_model=Dict[str, Any])
|
|
async def delete_workflow(
|
|
workflow_id: str,
|
|
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
|
):
|
|
"""Löscht einen Workflow"""
|
|
context = await get_context(current_user)
|
|
|
|
# Workflow löschen
|
|
success = context.interface_data.delete_workflow(workflow_id)
|
|
if not success:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
return {
|
|
"workflow_id": workflow_id,
|
|
"message": "Workflow wurde gelöscht"
|
|
}
|
|
|
|
@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.
|
|
"""
|
|
context = await get_context(current_user)
|
|
|
|
# Workflow laden
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
# Datenstatistiken zurückgeben
|
|
data_stats = workflow.get("data_stats", {})
|
|
if not data_stats:
|
|
data_stats = {
|
|
"total_processing_time": 0.0,
|
|
"total_token_count": 0,
|
|
"total_bytes_sent": 0,
|
|
"total_bytes_received": 0
|
|
}
|
|
|
|
return {
|
|
"workflow_id": workflow_id,
|
|
"data_stats": data_stats
|
|
}
|
|
|
|
@router.get("/{workflow_id}/status", response_model=Dict[str, Any])
|
|
async def get_workflow_status(
|
|
workflow_id: str,
|
|
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
|
):
|
|
"""Status eines Workflows abrufen"""
|
|
context = await get_context(current_user)
|
|
|
|
# Workflow laden
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
# Status aus dem geladenen Workflow erstellen
|
|
status_info = {
|
|
"id": workflow.get("id"),
|
|
"name": workflow.get("name"),
|
|
"status": workflow.get("status"),
|
|
"started_at": workflow.get("started_at"),
|
|
"last_activity": workflow.get("last_activity"),
|
|
"data_stats": workflow.get("data_stats", {})
|
|
}
|
|
|
|
return status_info
|
|
|
|
@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"""
|
|
context = await get_context(current_user)
|
|
|
|
# Logs abrufen
|
|
logs = context.interface_data.get_workflow_logs(workflow_id)
|
|
if not logs:
|
|
# Prüfen, ob der Workflow existiert
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
# Leere Log-Liste zurückgeben
|
|
logs = []
|
|
|
|
return logs
|
|
|
|
@router.get("/{workflow_id}/messages", response_model=List[Dict[str, Any]])
|
|
async def get_workflow_messages(
|
|
workflow_id: str,
|
|
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
|
):
|
|
"""Nachrichten eines Workflows abrufen"""
|
|
context = await get_context(current_user)
|
|
|
|
# Nachrichten abrufen
|
|
messages = context.interface_data.get_workflow_messages(workflow_id)
|
|
if messages is None:
|
|
# Prüfen, ob der Workflow existiert
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
# Leere Nachrichtenliste zurückgeben
|
|
messages = []
|
|
|
|
return messages
|
|
|
|
@router.delete("/{workflow_id}/messages/{message_id}", response_model=Dict[str, Any])
|
|
async def delete_workflow_message(
|
|
workflow_id: str = Path(..., description="ID des Workflows"),
|
|
message_id: str = Path(..., description="ID der zu löschenden Nachricht"),
|
|
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Löscht eine einzelne Nachricht aus einem Workflow.
|
|
|
|
Diese Funktion entfernt die Nachricht aus dem Workflow und auch aus der Datenbank.
|
|
"""
|
|
context = await get_context(current_user)
|
|
|
|
try:
|
|
# Prüfen, ob der Workflow existiert
|
|
workflow = context.interface_data.get_workflow(workflow_id)
|
|
if not workflow:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Workflow mit ID {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
# Nachricht löschen
|
|
success = context.interface_data.delete_workflow_message(workflow_id, message_id)
|
|
|
|
if not success:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Nachricht mit ID {message_id} im Workflow {workflow_id} nicht gefunden"
|
|
)
|
|
|
|
return {
|
|
"workflow_id": workflow_id,
|
|
"message_id": message_id,
|
|
"success": True,
|
|
"message": "Nachricht erfolgreich gelöscht"
|
|
}
|
|
|
|
except HTTPException:
|
|
# Bekannte HTTP-Exceptions weiterleiten
|
|
raise
|
|
except Exception as e:
|
|
# Sonstige Fehler abfangen
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Fehler beim Löschen der Nachricht: {str(e)}"
|
|
)
|
|
|
|
@router.delete("/{workflow_id}/messages/{message_id}/files/{file_id}", response_model=Dict[str, Any])
|
|
async def delete_file_from_message(
|
|
workflow_id: str = Path(..., description="ID des Workflows"),
|
|
message_id: str = Path(..., description="ID der Nachricht"),
|
|
file_id: str = Path(..., description="ID der zu löschenden Datei"),
|
|
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Löscht eine einzelne Dateireferenz aus einer Nachricht im Workflow.
|
|
Die Datei selbst wird nicht aus der Datenbank gelöscht, nur die Referenz in der Nachricht.
|
|
"""
|
|
context = await get_context(current_user)
|
|
|
|
# Add detailed logging
|
|
logger.debug(f"DELETE request: Remove file {file_id} from message {message_id} in workflow {workflow_id}")
|
|
|
|
try:
|
|
# Datei aus der Nachricht entfernen
|
|
success = context.interface_data.delete_file_from_message(workflow_id, message_id, file_id)
|
|
|
|
if not success:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Datei mit ID {file_id} in der Nachricht {message_id} nicht gefunden"
|
|
)
|
|
|
|
return {
|
|
"workflow_id": workflow_id,
|
|
"message_id": message_id,
|
|
"file_id": file_id,
|
|
"success": True,
|
|
"message": "Datei erfolgreich aus der Nachricht gelöscht"
|
|
}
|
|
|
|
except HTTPException:
|
|
# HTTP-Exceptions weiterleiten
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Löschen der Datei: {str(e)}")
|
|
import traceback
|
|
traceback_str = traceback.format_exc()
|
|
logger.error(f"Traceback: {traceback_str}")
|
|
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Fehler beim Löschen der Datei aus der Nachricht: {str(e)}"
|
|
) |