stable endpoints and connections

This commit is contained in:
valueon 2025-03-18 23:13:14 +01:00
parent 39f33b0fb8
commit b6ac189abe
18 changed files with 386 additions and 125 deletions

View file

@ -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"
}
]

View file

@ -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"
}
]

View file

@ -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"
}
]

View file

@ -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"
}
]

View file

@ -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()

View file

@ -91,6 +91,16 @@ def get_model_attributes(model_class, user_language="de"):
{"value": "Klassifikation", "label": "Klassifikation"},
{"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(
@ -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)

View file

@ -97,7 +97,7 @@ class JSONDatabaseConnector:
sofern diese Felder im Datensatz existieren.
"""
filtered_records = []
for record in records:
# Prüfe, ob mandate_id im Datensatz existiert und nicht null ist
has_mandate = "mandate_id" in record and record["mandate_id"] is not None and record["mandate_id"] != ""
@ -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]:
@ -239,13 +258,13 @@ class JSONDatabaseConnector:
"""
# Lade die Tabellendaten
data = self._load_table(table)
# Filtere nach Mandanten- und Benutzerkontext
filtered_data = self._filter_by_context(data)
# 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):

View file

@ -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.

View file

@ -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
@ -251,4 +251,8 @@ def get_gateway_interface(mandate_id: int = None, user_id: int = None) -> Gatewa
context_key = f"{mandate_id}_{user_id}"
if context_key not in _gateway_interfaces:
_gateway_interfaces[context_key] = GatewayInterface(mandate_id, user_id)
return _gateway_interfaces[context_key]
return _gateway_interfaces[context_key]
#Init
get_gateway_interface()

View file

@ -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,11 +176,61 @@ 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
@ -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)
@ -221,12 +344,54 @@ 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.
@ -234,4 +399,7 @@ def get_lucydom_interface(mandate_id: int, user_id: int) -> LucyDOMInterface:
context_key = f"{mandate_id}_{user_id}"
if context_key not in _lucydom_interfaces:
_lucydom_interfaces[context_key] = LucyDOMInterface(mandate_id, user_id)
return _lucydom_interfaces[context_key]
return _lucydom_interfaces[context_key]
#Init
get_lucydom_interface()

View file

@ -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")

View file

@ -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", "")
)
@ -83,9 +83,80 @@ async def get_agent(
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"
)
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"
)
return agent
# 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

View file

@ -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)"),

View file

@ -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:

View file

@ -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:

View file

@ -119,4 +119,30 @@ Enhanced Type Safety: More explicit typing and model definitions.
Improved Maintainability: Modular code structure makes it easier to maintain and extend.
Centralized Authentication: All auth logic in one place for better security.
This structure will allow for easier future expansion and maintenance of the system.
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -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