stable endpoints and connections
This commit is contained in:
parent
39f33b0fb8
commit
b6ac189abe
18 changed files with 386 additions and 125 deletions
|
|
@ -1,47 +1,12 @@
|
|||
[
|
||||
{
|
||||
"id": "agent_001",
|
||||
"name": "Datenanalyse-Agent",
|
||||
"type": "analyzer",
|
||||
"workspace_id": "workspace_001",
|
||||
"capabilities": ["Datenanalyse", "Statistik", "Trendanalyse"],
|
||||
"description": "Spezialisiert auf die Analyse von strukturierten Daten und Informationen.",
|
||||
"instructions": "Als Datenanalyse-Agent ist es deine Aufgabe, die bereitgestellten Daten zu analysieren und wichtige Erkenntnisse zu extrahieren.\n\nFolge diesen Anweisungen zur Analyse der Dateien:\n1. Lese und verstehe den Inhalt der bereitgestellten Dateien gründlich\n2. Identifiziere welchen Datentyp jede Datei enthält (z.B. Zeitreihendaten, kategorische Daten, Text)\n3. Wenn es sich um tabellarische Daten handelt:\n - Identifiziere Muster, Trends und Anomalien\n - Berechne relevante statistische Kennzahlen (Mittelwerte, Mediane, Standardabweichungen)\n - Suche nach Korrelationen zwischen verschiedenen Spalten\n - Identifiziere Ausreißer und ungewöhnliche Datenpunkte\n4. Wenn es sich um Textdaten handelt:\n - Analysiere Schlüsselthemen und -begriffe\n - Identifiziere Stimmung und Tonalität, wenn relevant\n - Extrahiere zentrale Aussagen und Schlussfolgerungen\n5. Erstelle eine strukturierte Zusammenfassung deiner Erkenntnisse\n6. Gib konkrete, datengestützte Empfehlungen, wenn möglich\n\nIn deiner Antwort:\n- Beginne mit einer kurzen Übersicht der analysierten Daten\n- Strukturiere deine Erkenntnisse klar mit Überschriften und Aufzählungen\n- Füge quantitative Erkenntnisse ein, wo immer möglich\n- Schließe mit einer Zusammenfassung der wichtigsten Punkte ab"
|
||||
},
|
||||
{
|
||||
"id": "agent_002",
|
||||
"name": "Visualisierungs-Agent",
|
||||
"type": "visualizer",
|
||||
"workspace_id": "workspace_001",
|
||||
"capabilities": ["Datenvisualisierung", "Diagrammerstellung"],
|
||||
"description": "Erstellt visuelle Darstellungen aus Daten",
|
||||
"instructions": "Als Visualisierungs-Agent ist es deine Aufgabe, die Daten visuell zu beschreiben.\n\nFolge diesen Anweisungen:\n1. Analysiere die bereitgestellten Daten und identifiziere die wichtigsten Aspekte für eine Visualisierung\n2. Empfehle geeignete Visualisierungstypen basierend auf der Art der Daten:\n - Für zeitliche Verläufe: Liniendiagramme, Area-Charts\n - Für Kategorienvergleiche: Balkendiagramme, gestapelte Balken\n - Für Verteilungen: Histogramme, Box-Plots\n - Für Anteile: Kreisdiagramme, Donut-Charts\n - Für Beziehungen: Streudiagramme, Heatmaps\n3. Beschreibe detailliert, wie die Visualisierung aufgebaut werden sollte:\n - Welche Daten auf welcher Achse abgebildet werden sollten\n - Farben und ihre Bedeutung\n - Beschriftungen und Legenden\n - Skalen und deren Anpassung\n4. Erkläre, welche Erkenntnisse die Visualisierung vermitteln würde\n5. Gib Empfehlungen für Interaktionsmöglichkeiten oder zusätzliche Visualisierungen"
|
||||
},
|
||||
{
|
||||
"id": "agent_003",
|
||||
"name": "Text-Generator",
|
||||
"type": "writer",
|
||||
"workspace_id": "workspace_001",
|
||||
"capabilities": ["Texterstellung", "Zusammenfassung"],
|
||||
"description": "Verfasst verständliche Berichte und Zusammenfassungen",
|
||||
"instructions": "Als Text-Generator ist es deine Aufgabe, verständliche Berichte und Zusammenfassungen zu erstellen.\n\nFolge diesen Anweisungen:\n1. Destilliere die wichtigsten Erkenntnisse aus den bereitgestellten Daten und Analysen\n2. Strukturiere den Bericht logisch mit:\n - Einer prägnanten Einleitung mit Kontext und Haupterkenntnissen\n - Einem detaillierten Hauptteil, der die Erkenntnisse systematisch präsentiert\n - Einem Abschluss mit Zusammenfassung und Handlungsempfehlungen\n3. Verwende eine klare, präzise und faktenbasierte Sprache\n4. Integriere Zahlen und Daten direkt in den Text, um Aussagen zu untermauern\n5. Nutze Markdown für eine bessere Formatierung:\n - Überschriften für verschiedene Abschnitte\n - Aufzählungspunkte für Listen\n - Hervorhebungen für wichtige Punkte\n - Tabellen für strukturierte Daten"
|
||||
},
|
||||
{
|
||||
"id": "agent_004",
|
||||
"name": "Web-Scraper",
|
||||
"type": "scraper",
|
||||
"workspace_id": "workspace_002",
|
||||
"capabilities": ["Datensammlung", "Webanalyse", "Echtzeit-Recherche"],
|
||||
"description": "Sammelt und analysiert Daten aus Webquellen in Echtzeit",
|
||||
"instructions": "Als Web-Scraper-Agent ist es deine Aufgabe, Webseiten zu durchsuchen und relevante Informationen zu extrahieren.\n\nFolge diesen Anweisungen:\n1. Analysiere die bereitgestellten Web-Daten sorgfältig\n2. Extrahiere die wichtigsten Informationen und Fakten aus den Webinhalten\n3. Organisiere die Informationen in klare Kategorien\n4. Identifiziere Trends, Muster und wichtige Erkenntnisse\n5. Vergleiche die Informationen aus verschiedenen Quellen, wenn verfügbar\n6. Fasse die gefundenen Informationen prägnant zusammen\n7. Erkenne mögliche Einschränkungen oder Verzerrungen in den Quellen\n\nIn deiner Antwort:\n- Beginne mit einer Zusammenfassung der gefundenen Informationen\n- Strukturiere die extrahierten Daten in logische Abschnitte\n- Hebe wichtige Fakten und Zahlen hervor\n- Gib Quellenhinweise an\n- Formuliere Schlussfolgerungen basierend auf den gesammelten Daten"
|
||||
},
|
||||
{
|
||||
"id": "agent_005",
|
||||
"name": "Marktanalyse-Agent",
|
||||
"type": "analyzer",
|
||||
"workspace_id": "workspace_002",
|
||||
"capabilities": ["Wettbewerbsanalyse", "Markttrends"],
|
||||
"description": "Spezialisiert auf Wettbewerbsanalyse und Markttrends",
|
||||
"instructions": "Als Marktanalyse-Agent ist es deine Aufgabe, Wettbewerbsdaten und Markttrends zu analysieren.\n\nFolge diesen Anweisungen:\n1. Identifiziere die wichtigsten Wettbewerber und ihre Positionierung im Markt\n2. Analysiere Markttrends und -entwicklungen:\n - Wachstumsraten und Marktgrößen\n - Veränderungen im Konsumentenverhalten\n - Technologische Entwicklungen\n - Regulatorische Änderungen\n3. Vergleiche Produkte und Dienstleistungen nach relevanten Kriterien\n4. Identifiziere Stärken, Schwächen, Chancen und Risiken (SWOT-Analyse)\n5. Erstelle eine fundierte Einschätzung der Marktposition\n6. Entwickle strategische Empfehlungen basierend auf der Marktanalyse"
|
||||
"id": 2,
|
||||
"mandate_id": 1,
|
||||
"user_id": 1,
|
||||
"name": "Hugo",
|
||||
"type": "Transformation",
|
||||
"workspace_id": 1,
|
||||
"capabilities": "ccc",
|
||||
"description": "ddd"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "0399d060-5beb-46e6-9c3c-830ae7a471cb",
|
||||
"name": "Index.pdf",
|
||||
"type": "document",
|
||||
"path": "D:\\Athi\\Local\\Web\\git-apps\\gateway\\gwserver\\uploads\\0399d060-5beb-46e6-9c3c-830ae7a471cb.pdf",
|
||||
"content_type": "application/pdf",
|
||||
"size": 114510,
|
||||
"upload_date": "2025-03-16T02:10:23.229879"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "prompt_001",
|
||||
"content": "Analysiere die Quartalsdaten und erstelle eine Zusammenfassung mit wichtigsten Trends",
|
||||
"workspace_id": "workspace_001",
|
||||
"created_at": "2025-03-14T00:25:25.076526"
|
||||
},
|
||||
{
|
||||
"id": "prompt_002",
|
||||
"content": "Erstelle eine Prognose für das nächste Quartal basierend auf historischen Daten",
|
||||
"workspace_id": "workspace_001",
|
||||
"created_at": "2025-03-14T00:25:25.076526"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
[
|
||||
{
|
||||
"id": "workspace_001",
|
||||
"name": "Datenanalyse-Projekt",
|
||||
"created_at": "2025-03-14T00:25:25.076526",
|
||||
"prompts": [],
|
||||
"agents": [],
|
||||
"dataObjectReferences": []
|
||||
"id": 1,
|
||||
"mandate_id": 1,
|
||||
"user_id": 1,
|
||||
"name": "Default Workspace",
|
||||
"created_at": "2025-03-17T18:14:50.796803"
|
||||
},
|
||||
{
|
||||
"id": "workspace_002",
|
||||
"name": "Marktforschung",
|
||||
"created_at": "2025-03-14T00:25:25.076526",
|
||||
"prompts": [],
|
||||
"agents": [],
|
||||
"dataObjectReferences": []
|
||||
"id": 1,
|
||||
"mandate_id": 0,
|
||||
"user_id": 0,
|
||||
"name": "Default Workspace",
|
||||
"created_at": "2025-03-17T22:25:11.350744"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from fastapi import FastAPI, HTTPException, Depends, Body, status
|
||||
from fastapi import FastAPI, HTTPException, Depends, Body, status, Response
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.responses import JSONResponse, FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
|
||||
|
|
@ -12,7 +12,8 @@ from datetime import timedelta
|
|||
|
||||
# Import interfaces
|
||||
from modules.gateway_interface import get_gateway_interface
|
||||
from modules.agentservice_interface import get_agent_service
|
||||
from modules.lucydom_interface import get_lucydom_interface
|
||||
from modules.agentservice_interface import get_agentservice_interface
|
||||
|
||||
# Import auth module
|
||||
from auth import (
|
||||
|
|
@ -47,16 +48,23 @@ app = FastAPI(title="PowerOn | Data Platform API", description="Backend-API für
|
|||
# CORS-Konfiguration für Frontend-Anfragen
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:8080","https://poweron-gateway-fsahaxgbfee8djea.germanywestcentral-01.azurewebsites.net"],
|
||||
allow_origins=["http://localhost:8080","https://poweron-lucyagents-xxx.germanywestcentral-01.azurewebsites.net"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
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
|
||||
os.makedirs(os.path.join(os.getcwd(), "static"), exist_ok=True)
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
# Add a specific route for favicon.ico
|
||||
@app.get("/favicon.ico", include_in_schema=False)
|
||||
async def favicon():
|
||||
return FileResponse("static/favicon.ico")
|
||||
|
||||
# Generelle Elements
|
||||
@app.get("/", tags=["General"])
|
||||
async def root():
|
||||
|
|
@ -65,10 +73,14 @@ async def root():
|
|||
|
||||
@app.get("/api/test", tags=["General"])
|
||||
async def get_test():
|
||||
return "OK 1.0"
|
||||
return "OK 1.1"
|
||||
|
||||
@app.options("/{full_path:path}")
|
||||
async def options_route(full_path: str):
|
||||
return Response(status_code=200)
|
||||
|
||||
# Token-Endpunkt für Login
|
||||
@app.post("/token", response_model=gateway_model.Token, tags=["General"])
|
||||
@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()
|
||||
|
|
@ -143,7 +155,7 @@ app.include_router(mandate_router)
|
|||
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()
|
||||
agent_service = get_agentservice_interface()
|
||||
|
||||
# HTTP-Client des AgentService schließen
|
||||
await agent_service.close()
|
||||
|
|
|
|||
|
|
@ -92,6 +92,16 @@ def get_model_attributes(model_class, user_language="de"):
|
|||
{"value": "Benutzerdefiniert", "label": "Benutzerdefiniert"}
|
||||
]
|
||||
|
||||
# Extrahiere die Beschreibung aus dem Field-Objekt
|
||||
description = None
|
||||
# Versuche, die description aus verschiedenen möglichen Quellen zu holen
|
||||
if hasattr(field, 'field_info') and hasattr(field.field_info, 'description'):
|
||||
description = field.field_info.description
|
||||
elif hasattr(field, 'description'):
|
||||
description = field.description
|
||||
elif hasattr(field, 'schema') and hasattr(field.schema, 'description'):
|
||||
description = field.schema.description
|
||||
|
||||
# Attributdefinition erstellen
|
||||
attr_def = AttributeDefinition(
|
||||
name=field_name,
|
||||
|
|
@ -105,7 +115,7 @@ def get_model_attributes(model_class, user_language="de"):
|
|||
visible=field_name not in ["hashed_password", "mandate_id", "user_id"],
|
||||
order=i,
|
||||
validation=validation,
|
||||
help_text=field.description
|
||||
help_text=description or "" # Setze leeren String als Standardwert, wenn keine Beschreibung gefunden wurde
|
||||
)
|
||||
|
||||
attributes.append(attr_def)
|
||||
|
|
@ -107,21 +107,24 @@ class JSONDatabaseConnector:
|
|||
|
||||
# Wenn beides existiert, filtere entsprechend
|
||||
if has_mandate and has_user:
|
||||
print(" DEBUG opt m+u: record +mandate:",record["mandate_id"])
|
||||
if record["mandate_id"] == self.mandate_id:
|
||||
filtered_records.append(record)
|
||||
# Wenn nur mandate_id existiert
|
||||
elif has_mandate and not has_user:
|
||||
print(" DEBUG opt m : record +mandate:",record["mandate_id"])
|
||||
if record["mandate_id"] == self.mandate_id:
|
||||
filtered_records.append(record)
|
||||
# Wenn weder mandate_id noch user_id existieren, füge den Datensatz hinzu
|
||||
elif not has_mandate and not has_user:
|
||||
print(" DEBUG opt ---: record +")
|
||||
filtered_records.append(record)
|
||||
|
||||
return filtered_records
|
||||
|
||||
def _apply_field_filter(self, records: List[Dict[str, Any]], field_filter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
||||
"""Wendet einen Feldfilter auf die Datensätze an"""
|
||||
if not field_filter:
|
||||
def _apply_record_filter(self, records: List[Dict[str, Any]], record_filter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
||||
"""Wendet einen Datensatzfilter auf die Datensätze an"""
|
||||
if not record_filter:
|
||||
return records
|
||||
|
||||
filtered_records = []
|
||||
|
|
@ -129,16 +132,32 @@ class JSONDatabaseConnector:
|
|||
for record in records:
|
||||
match = True
|
||||
|
||||
for field, value in field_filter.items():
|
||||
if field not in record or record[field] != value:
|
||||
for field, value in record_filter.items():
|
||||
# Prüfen, ob das Feld existiert
|
||||
if field not in record:
|
||||
print(" - field not in record")
|
||||
match = False
|
||||
break
|
||||
|
||||
# Wenn der Filterwert ein Integer-String ist und das Datensatzfeld ein Integer
|
||||
if isinstance(value, str) and value.isdigit() and isinstance(record[field], int):
|
||||
if record[field] != int(value):
|
||||
print(" - ",record[field],"!=",int(value))
|
||||
match = False
|
||||
break
|
||||
# Sonst direkter Vergleich
|
||||
elif record[field] != value:
|
||||
print(" - ",record[field],"!='",value,"'")
|
||||
match = False
|
||||
break
|
||||
|
||||
if match:
|
||||
print(" + take it")
|
||||
filtered_records.append(record)
|
||||
|
||||
return filtered_records
|
||||
|
||||
|
||||
# Public API
|
||||
|
||||
def get_tables(self, filter_criteria: Dict[str, Any] = None) -> List[str]:
|
||||
|
|
@ -245,7 +264,7 @@ class JSONDatabaseConnector:
|
|||
|
||||
# Wende record_filter an, wenn vorhanden
|
||||
if record_filter:
|
||||
filtered_data = self._apply_field_filter(filtered_data, record_filter)
|
||||
filtered_data = self._apply_record_filter(filtered_data, record_filter)
|
||||
|
||||
# Wenn field_filter vorhanden ist, reduziere die Felder
|
||||
if field_filter and isinstance(field_filter, list):
|
||||
|
|
|
|||
|
|
@ -732,7 +732,7 @@ class AgentService:
|
|||
# Singleton-Factory für AgentService-Instanzen pro Kontext
|
||||
_agent_service_instances = {}
|
||||
|
||||
def get_agent_service(mandate_id: int = None, user_id: int = None) -> AgentService:
|
||||
def get_agentservice_interface(mandate_id: int = None, user_id: int = None) -> AgentService:
|
||||
"""
|
||||
Gibt eine AgentService-Instanz für den angegebenen Kontext zurück.
|
||||
Wiederverwendet bestehende Instanzen.
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ class GatewayInterface:
|
|||
|
||||
# Datenmodell-Modul importieren
|
||||
try:
|
||||
self.model_module = importlib.import_module("model_gateway")
|
||||
logger.info("model_gateway erfolgreich importiert")
|
||||
self.model_module = importlib.import_module("modules.gateway_model")
|
||||
logger.info("gateway_model erfolgreich importiert")
|
||||
except ImportError as e:
|
||||
logger.error(f"Fehler beim Importieren von model_gateway: {e}")
|
||||
logger.error(f"Fehler beim Importieren von gateway_model: {e}")
|
||||
raise
|
||||
|
||||
# Konnektor erstellen
|
||||
|
|
@ -252,3 +252,7 @@ def get_gateway_interface(mandate_id: int = None, user_id: int = None) -> Gatewa
|
|||
if context_key not in _gateway_interfaces:
|
||||
_gateway_interfaces[context_key] = GatewayInterface(mandate_id, user_id)
|
||||
return _gateway_interfaces[context_key]
|
||||
|
||||
#Init
|
||||
get_gateway_interface()
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ class LucyDOMInterface:
|
|||
|
||||
# Datenmodell-Modul importieren
|
||||
try:
|
||||
self.model_module = importlib.import_module("model_lucydom")
|
||||
logger.info("model_lucydom erfolgreich importiert")
|
||||
self.model_module = importlib.import_module("modules.lucydom_model")
|
||||
logger.info("lucydom_model erfolgreich importiert")
|
||||
except ImportError as e:
|
||||
logger.error(f"Fehler beim Importieren von model_lucydom: {e}")
|
||||
logger.error(f"Fehler beim Importieren von lucydom_model: {e}")
|
||||
raise
|
||||
|
||||
# Konnektor erstellen
|
||||
|
|
@ -107,6 +107,42 @@ class LucyDOMInterface:
|
|||
|
||||
return self.db.record_create("workspaces", workspace_data)
|
||||
|
||||
def update_workspace(self, workspace_id: int, name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Aktualisiert einen vorhandenen Workspace
|
||||
|
||||
Args:
|
||||
workspace_id: ID des zu aktualisierenden Workspaces
|
||||
name: Neuer Name des Workspaces
|
||||
|
||||
Returns:
|
||||
Das aktualisierte Workspace-Objekt
|
||||
"""
|
||||
# Prüfen, ob der Workspace existiert
|
||||
workspace = self.get_workspace(workspace_id)
|
||||
if not workspace:
|
||||
return None
|
||||
|
||||
# Daten für die Aktualisierung vorbereiten
|
||||
workspace_data = {
|
||||
"id": workspace_id,
|
||||
"mandate_id": self.mandate_id,
|
||||
"user_id": self.user_id,
|
||||
"name": name,
|
||||
"created_at": workspace.get("created_at")
|
||||
}
|
||||
|
||||
# Workspace aktualisieren
|
||||
return self.db.record_modify("workspaces", workspace_id, workspace_data)
|
||||
|
||||
def delete_workspace(self, workspace_id: int) -> bool:
|
||||
"""
|
||||
Löscht einen Workspace aus der Datenbank
|
||||
Returns:
|
||||
True, wenn der Workspace erfolgreich gelöscht wurde, sonst False
|
||||
"""
|
||||
return self.db.record_delete("workspaces", workspace_id)
|
||||
|
||||
# Agent-Methoden
|
||||
|
||||
def get_all_agents(self) -> List[Dict[str, Any]]:
|
||||
|
|
@ -125,7 +161,7 @@ class LucyDOMInterface:
|
|||
return None
|
||||
|
||||
def create_agent(self, name: str, agent_type: str, workspace_id: int,
|
||||
capabilities: List[str] = None, description: str = None) -> Dict[str, Any]:
|
||||
capabilities: str = None, description: str = None) -> Dict[str, Any]:
|
||||
"""Erstellt einen neuen Agenten"""
|
||||
# Bestimme die nächste ID
|
||||
agents = self.db.get_recordset("agents")
|
||||
|
|
@ -140,12 +176,62 @@ class LucyDOMInterface:
|
|||
"name": name,
|
||||
"type": agent_type,
|
||||
"workspace_id": workspace_id,
|
||||
"capabilities": capabilities or [],
|
||||
"capabilities": capabilities,
|
||||
"description": description
|
||||
}
|
||||
|
||||
return self.db.record_create("agents", agent_data)
|
||||
|
||||
def update_agent(self, agent_id: int, name: str, agent_type: str, workspace_id: int,
|
||||
capabilities: str = None, description: str = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Aktualisiert einen vorhandenen Agenten
|
||||
|
||||
Args:
|
||||
agent_id: ID des zu aktualisierenden Agenten
|
||||
name: Neuer Name des Agenten
|
||||
agent_type: Neuer Typ des Agenten
|
||||
workspace_id: ID des Workspaces, zu dem der Agent gehört
|
||||
capabilities: Fähigkeiten des Agenten
|
||||
description: Beschreibung des Agenten
|
||||
|
||||
Returns:
|
||||
Das aktualisierte Agenten-Objekt
|
||||
"""
|
||||
# Prüfen, ob der Agent existiert
|
||||
agent = self.get_agent(agent_id)
|
||||
if not agent:
|
||||
return None
|
||||
|
||||
# Daten für die Aktualisierung vorbereiten
|
||||
agent_data = {
|
||||
"id": agent_id,
|
||||
"mandate_id": self.mandate_id,
|
||||
"user_id": self.user_id,
|
||||
"name": name,
|
||||
"type": agent_type,
|
||||
"workspace_id": workspace_id,
|
||||
"capabilities": capabilities if capabilities is not None else agent.get("capabilities"),
|
||||
"description": description if description is not None else agent.get("description")
|
||||
}
|
||||
|
||||
# Agent aktualisieren
|
||||
updated_agent = self.db.record_modify("agents", agent_id, agent_data)
|
||||
|
||||
return updated_agent
|
||||
|
||||
def delete_agent(self, agent_id: int) -> bool:
|
||||
"""
|
||||
Löscht einen Agenten aus der Datenbank
|
||||
|
||||
Args:
|
||||
agent_id: ID des zu löschenden Agenten
|
||||
|
||||
Returns:
|
||||
True, wenn der Agent erfolgreich gelöscht wurde, sonst False
|
||||
"""
|
||||
return self.db.record_delete("agents", agent_id)
|
||||
|
||||
# Datei-Methoden
|
||||
|
||||
def get_all_files(self) -> List[Dict[str, Any]]:
|
||||
|
|
@ -182,6 +268,43 @@ class LucyDOMInterface:
|
|||
|
||||
return self.db.record_create("files", file_data)
|
||||
|
||||
def update_file(self, file_id: int, name: str = None, file_type: str = None,
|
||||
content_type: str = None, size: int = None, path: str = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Aktualisiert eine vorhandene Datei
|
||||
|
||||
Args:
|
||||
file_id: ID der zu aktualisierenden Datei
|
||||
name: Neuer Name der Datei
|
||||
file_type: Neuer Dateityp
|
||||
content_type: Neuer Content-Type
|
||||
size: Neue Dateigröße
|
||||
path: Neuer Dateipfad
|
||||
|
||||
Returns:
|
||||
Das aktualisierte Datei-Objekt
|
||||
"""
|
||||
# Prüfen, ob die Datei existiert
|
||||
file = self.get_file(file_id)
|
||||
if not file:
|
||||
return None
|
||||
|
||||
# Daten für die Aktualisierung vorbereiten
|
||||
file_data = {
|
||||
"id": file_id,
|
||||
"mandate_id": self.mandate_id,
|
||||
"user_id": self.user_id,
|
||||
"name": name if name is not None else file.get("name"),
|
||||
"type": file_type if file_type is not None else file.get("type"),
|
||||
"content_type": content_type if content_type is not None else file.get("content_type"),
|
||||
"size": size if size is not None else file.get("size"),
|
||||
"path": path if path is not None else file.get("path"),
|
||||
"upload_date": file.get("upload_date")
|
||||
}
|
||||
|
||||
# Datei aktualisieren
|
||||
return self.db.record_modify("files", file_id, file_data)
|
||||
|
||||
def delete_file(self, file_id: int) -> bool:
|
||||
"""Löscht eine Datei aus der Datenbank"""
|
||||
return self.db.record_delete("files", file_id)
|
||||
|
|
@ -222,11 +345,53 @@ class LucyDOMInterface:
|
|||
|
||||
return self.db.record_create("prompts", prompt_data)
|
||||
|
||||
def update_prompt(self, prompt_id: int, content: str = None, workspace_id: int = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Aktualisiert einen vorhandenen Prompt
|
||||
|
||||
Args:
|
||||
prompt_id: ID des zu aktualisierenden Prompts
|
||||
content: Neuer Inhalt des Prompts
|
||||
workspace_id: Neue ID des Workspaces, zu dem der Prompt gehört
|
||||
|
||||
Returns:
|
||||
Das aktualisierte Prompt-Objekt
|
||||
"""
|
||||
# Prüfen, ob der Prompt existiert
|
||||
prompt = self.get_prompt(prompt_id)
|
||||
if not prompt:
|
||||
return None
|
||||
|
||||
# Daten für die Aktualisierung vorbereiten
|
||||
prompt_data = {
|
||||
"id": prompt_id,
|
||||
"mandate_id": self.mandate_id,
|
||||
"user_id": self.user_id,
|
||||
"content": content if content is not None else prompt.get("content"),
|
||||
"workspace_id": workspace_id if workspace_id is not None else prompt.get("workspace_id"),
|
||||
"created_at": prompt.get("created_at")
|
||||
}
|
||||
|
||||
# Prompt aktualisieren
|
||||
return self.db.record_modify("prompts", prompt_id, prompt_data)
|
||||
|
||||
def delete_prompt(self, prompt_id: int) -> bool:
|
||||
"""
|
||||
Löscht einen Prompt aus der Datenbank
|
||||
|
||||
Args:
|
||||
prompt_id: ID des zu löschenden Prompts
|
||||
|
||||
Returns:
|
||||
True, wenn der Prompt erfolgreich gelöscht wurde, sonst False
|
||||
"""
|
||||
return self.db.record_delete("prompts", prompt_id)
|
||||
|
||||
|
||||
# Singleton-Factory für LucyDOMInterface-Instanzen pro Kontext
|
||||
_lucydom_interfaces = {}
|
||||
|
||||
def get_lucydom_interface(mandate_id: int, user_id: int) -> LucyDOMInterface:
|
||||
def get_lucydom_interface(mandate_id: int = 0, user_id: int = 0) -> LucyDOMInterface:
|
||||
"""
|
||||
Gibt eine LucyDOMInterface-Instanz für den angegebenen Kontext zurück.
|
||||
Wiederverwendet bestehende Instanzen.
|
||||
|
|
@ -235,3 +400,6 @@ def get_lucydom_interface(mandate_id: int, user_id: int) -> LucyDOMInterface:
|
|||
if context_key not in _lucydom_interfaces:
|
||||
_lucydom_interfaces[context_key] = LucyDOMInterface(mandate_id, user_id)
|
||||
return _lucydom_interfaces[context_key]
|
||||
|
||||
#Init
|
||||
get_lucydom_interface()
|
||||
|
|
@ -23,7 +23,7 @@ class Agent(BaseModel):
|
|||
name: str = Field(description="Name des Agenten")
|
||||
type: str = Field(description="Typ des Agenten")
|
||||
workspace_id: int = Field(description="ID des zugehörigen Workspaces")
|
||||
capabilities: List[str] = Field(default=[], description="Fähigkeiten des Agenten")
|
||||
capabilities: Optional[str] = Field(None, description="Fähigkeiten des Agenten")
|
||||
description: Optional[str] = Field(None, description="Beschreibung des Agenten")
|
||||
instructions: Optional[str] = Field(None, description="Anweisungen für den Agenten")
|
||||
|
||||
|
|
|
|||
|
|
@ -56,14 +56,14 @@ async def create_agent(
|
|||
if not workspace:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Workspace mit ID {workspace_id} nicht gefunden"
|
||||
detail=f"Workspace mit ID {workspace_id} nicht gefunden für User {user_id} im Mandanten {mandate_id}"
|
||||
)
|
||||
|
||||
new_agent = lucy_interface.create_agent(
|
||||
name=agent.get("name", "Neuer Agent"),
|
||||
agent_type=agent.get("type", "generic"),
|
||||
workspace_id=workspace_id,
|
||||
capabilities=agent.get("capabilities", []),
|
||||
capabilities=agent.get("capabilities", ""),
|
||||
description=agent.get("description", "")
|
||||
)
|
||||
|
||||
|
|
@ -87,5 +87,76 @@ async def get_agent(
|
|||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Agent mit ID {agent_id} nicht gefunden"
|
||||
)
|
||||
|
||||
return agent
|
||||
|
||||
|
||||
@router.post("/{agent_id}", response_model=Dict[str, Any])
|
||||
async def update_agent(
|
||||
agent_id: int = Path(..., description="ID des zu aktualisierenden Agenten"),
|
||||
agent_data: Dict[str, Any] = Body(..., description="Aktualisierte Agentendaten"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
||||
):
|
||||
"""Einen bestehenden Agenten aktualisieren"""
|
||||
mandate_id, user_id = await get_user_context(current_user)
|
||||
|
||||
# LucyDOM-Interface mit Benutzerkontext initialisieren
|
||||
lucy_interface = get_lucydom_interface(mandate_id, user_id)
|
||||
|
||||
# Überprüfen, ob der Agent existiert
|
||||
existing_agent = lucy_interface.get_agent(agent_id)
|
||||
if not existing_agent:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Agent mit ID {agent_id} nicht gefunden"
|
||||
)
|
||||
|
||||
# Wenn workspace_id im Request vorhanden ist, prüfen ob der Workspace existiert
|
||||
if "workspace_id" in agent_data:
|
||||
workspace_id = agent_data["workspace_id"]
|
||||
workspace = lucy_interface.get_workspace(workspace_id)
|
||||
if not workspace:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Workspace mit ID {workspace_id} nicht gefunden für User {user_id} im Mandanten {mandate_id}"
|
||||
)
|
||||
|
||||
# Agent-Daten aktualisieren
|
||||
updated_agent = lucy_interface.update_agent(
|
||||
agent_id=agent_id,
|
||||
name=agent_data.get("name", existing_agent.get("name")),
|
||||
agent_type=agent_data.get("type", existing_agent.get("type")),
|
||||
workspace_id=agent_data.get("workspace_id", existing_agent.get("workspace_id")),
|
||||
capabilities=agent_data.get("capabilities", existing_agent.get("capabilities")),
|
||||
description=agent_data.get("description", existing_agent.get("description"))
|
||||
)
|
||||
return updated_agent
|
||||
|
||||
@router.delete("/{agent_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_agent(
|
||||
agent_id: int = Path(..., description="ID des zu löschenden Agenten"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_active_user)
|
||||
):
|
||||
"""Einen Agenten löschen"""
|
||||
mandate_id, user_id = await get_user_context(current_user)
|
||||
|
||||
# LucyDOM-Interface mit Benutzerkontext initialisieren
|
||||
lucy_interface = get_lucydom_interface(mandate_id, user_id)
|
||||
|
||||
# Überprüfen, ob der Agent existiert
|
||||
existing_agent = lucy_interface.get_agent(agent_id)
|
||||
if not existing_agent:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Agent mit ID {agent_id} nicht gefunden"
|
||||
)
|
||||
|
||||
# Agent löschen
|
||||
success = lucy_interface.delete_agent(agent_id)
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Fehler beim Löschen des Agenten mit ID {agent_id}"
|
||||
)
|
||||
|
||||
# Kein Inhalt zurückgeben bei erfolgreichem Löschen
|
||||
return None
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import APIRouter, HTTPException, Depends, Path
|
||||
from fastapi import APIRouter, HTTPException, Depends, Path, Response
|
||||
from typing import List, Dict, Any
|
||||
from fastapi import status
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ from fastapi import status
|
|||
from auth import get_current_active_user, get_user_context
|
||||
|
||||
# Importiere die Attributdefinition und Hilfsfunktionen
|
||||
from attributes import AttributeDefinition, get_model_attributes
|
||||
from attributes_def import AttributeDefinition, get_model_attributes
|
||||
|
||||
# Importiere die Modellmodule (ohne spezifische Klassen)
|
||||
import modules.gateway_model as gateway_model
|
||||
|
|
@ -33,6 +33,16 @@ router = APIRouter(
|
|||
responses={404: {"description": "Not found"}}
|
||||
)
|
||||
|
||||
@router.get("/test", response_model=str)
|
||||
async def get_entity_test(s:str):
|
||||
return s+s
|
||||
|
||||
@router.options("/{entity_type}")
|
||||
async def options_entity_attributes(
|
||||
entity_type: str = Path(..., description="Typ der Entität (z.B. workspace, agent, prompt)")
|
||||
):
|
||||
return Response(status_code=200)
|
||||
|
||||
@router.get("/{entity_type}", response_model=List[AttributeDefinition])
|
||||
async def get_entity_attributes(
|
||||
entity_type: str = Path(..., description="Typ der Entität (z.B. workspace, agent, prompt)"),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ 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_agent_service
|
||||
from modules.agentservice_interface import get_agentservice_interface
|
||||
|
||||
# Logger konfigurieren
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -48,7 +48,7 @@ async def upload_file(
|
|||
# Generiere eine eindeutige ID für die Datei
|
||||
file_id = str(uuid.uuid4())
|
||||
file_ext = os.path.splitext(file.filename)[1]
|
||||
file_path = os.path.join(get_agent_service(mandate_id, user_id).upload_dir, f"{file_id}{file_ext}")
|
||||
file_path = os.path.join(get_agentservice_interface(mandate_id, user_id).upload_dir, f"{file_id}{file_ext}")
|
||||
|
||||
# Datei speichern
|
||||
with open(file_path, "wb") as f:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ 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_agent_service
|
||||
from modules.agentservice_interface import get_agentservice_interface
|
||||
|
||||
# Import models
|
||||
import modules.lucydom_model as lucydom_model
|
||||
|
|
@ -33,7 +33,7 @@ async def run_workflow(
|
|||
lucy_interface = get_lucydom_interface(mandate_id, user_id)
|
||||
|
||||
# AgentService mit Benutzerkontext initialisieren
|
||||
agent_service = get_agent_service(mandate_id, user_id)
|
||||
agent_service = get_agentservice_interface(mandate_id, user_id)
|
||||
|
||||
workspace = lucy_interface.get_workspace(workflow_request.workspace_id)
|
||||
if not workspace:
|
||||
|
|
@ -94,7 +94,7 @@ async def get_workflow_status(
|
|||
mandate_id, user_id = await get_user_context(current_user)
|
||||
|
||||
# AgentService mit Benutzerkontext initialisieren
|
||||
agent_service = get_agent_service(mandate_id, user_id)
|
||||
agent_service = get_agentservice_interface(mandate_id, user_id)
|
||||
|
||||
status = agent_service.get_workflow_status(workflow_id)
|
||||
if not status:
|
||||
|
|
@ -115,7 +115,7 @@ async def get_workflow_logs(
|
|||
mandate_id, user_id = await get_user_context(current_user)
|
||||
|
||||
# AgentService mit Benutzerkontext initialisieren
|
||||
agent_service = get_agent_service(mandate_id, user_id)
|
||||
agent_service = get_agentservice_interface(mandate_id, user_id)
|
||||
|
||||
logs = agent_service.get_workflow_logs(workflow_id)
|
||||
if logs is None:
|
||||
|
|
@ -136,7 +136,7 @@ async def get_workflow_results(
|
|||
mandate_id, user_id = await get_user_context(current_user)
|
||||
|
||||
# AgentService mit Benutzerkontext initialisieren
|
||||
agent_service = get_agent_service(mandate_id, user_id)
|
||||
agent_service = get_agentservice_interface(mandate_id, user_id)
|
||||
|
||||
results = agent_service.get_workflow_results(workflow_id)
|
||||
if results is None:
|
||||
|
|
|
|||
|
|
@ -120,3 +120,29 @@ Improved Maintainability: Modular code structure makes it easier to maintain and
|
|||
Centralized Authentication: All auth logic in one place for better security.
|
||||
|
||||
This structure will allow for easier future expansion and maintenance of the system.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.......................... Tasks
|
||||
|
||||
|
||||
|
||||
|
||||
Kannst du mir bitte folgende anpassungen am code machen:
|
||||
|
||||
Beim gateway_model.py "User" das Attribut "role" ergänzen mit allen Details. Dies ist die Berechtigungsrolle, sie kann eine dieser Optionen sein: [root,admin,user]. Wenn kein User vorhanden ist, wird ein User mit der Rolle "root" erzeugt. dieser wird dann auch gleich als aktiver user genutzt.
|
||||
|
||||
Im Datenmodell den Datentyp "Lookup" oder ähnlich ergänzen, für Felder mit Auswahl, so wie die Auswahlobjekte für Berechtigungsrolle als Beispiel
|
||||
|
||||
Im "lucydom_interface.py" einen default workspace erstellen, falls keiner vorhanden ist. dieser soll mit den credentials des angemendeten users stattfinden.
|
||||
|
||||
unique id's bei datenobjekten in einer tabelle sicherstellen. über alle datensätze ist eine id eindeutig über mandanten hinweg. das management der id's soll im Connector "connector_bd_json.py" erfolgen. In den "...interface.py" dies rausnehmen. wenn ein neues datenobjekt erstellt wird, so erhält es die nächste verfügbare id. hier soll sichergestellt werden, dass bei parallelen funktionsaufrufen von mehreren Users nicht eine id doppelt gesetzt wird.
|
||||
|
||||
Bei der Ausgabe eines datensatzes soll die ID immer als schreibgeschützt mitgegeben werden.
|
||||
|
||||
Im Frontend soll im generischen Formular "generic-entity.js" für ein neues Objekt die ID entweder hidden oder schreibgeschützt sein. die ID wird nicht benötigt, sondern wird erst mit dem speichern in der datenbank erstellt. d.h. nach dem speichern in der datenbank werden die daten der entsprechenden tabelle neu geladen.
|
||||
|
||||
In den Einstellungen des Frontends soll die Sprache des aktiven benutzers gemäss den Listenoptionen in den "...model.py" angepasst werden können. die sprache gilt dann auch für die Attributnamen in einem Formularfeld im "generic-entity.js". eine sprachänderung zieht somit eine anpassung des Users über das API nach sich, indem die Sprache in der Datenbank angepasst wird.
|
||||
|
||||
|
|
|
|||
BIN
gwserver/static/favicon.ico
Normal file
BIN
gwserver/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -61,7 +61,10 @@ Configuration:
|
|||
Environment varibales:
|
||||
- Neue Variable PORT=8000
|
||||
|
||||
|
||||
### DEV TOOLS
|
||||
Kill all processes on port 8000
|
||||
netsh advfirewall firewall add rule name="Close_Port_8000" dir=in action=block protocol=TCP localport=8000
|
||||
netsh advfirewall firewall delete rule name="Close_Port_8000"
|
||||
|
||||
|
||||
### Datenbank-Migration
|
||||
|
|
|
|||
Loading…
Reference in a new issue