gateway/gwserver/modules/agentservice_agent_documentation.py
2025-04-11 23:39:10 +02:00

442 lines
No EOL
17 KiB
Python

"""
Dokumentations-Agent für die Erstellung von Dokumentation, Berichten und strukturierten Inhalten.
Verwendet einen strukturierten mehrstufigen Prozess zur Erstellung hochwertiger Dokumentation.
Angepasst für das refaktorisierte Core-Modul.
"""
import logging
import json
import re
import traceback
from typing import List, Dict, Any, Optional, Tuple, Union
from datetime import datetime
import uuid
from modules.agentservice_base import BaseAgent
from connectors.connector_aichat_openai import ChatService
from modules.agentservice_utils import WorkflowUtils, MessageUtils, LoggingUtils
logger = logging.getLogger(__name__)
class DocumentationAgent(BaseAgent):
"""Agent für die Erstellung von Dokumentation und strukturierten Inhalten"""
def __init__(self):
"""Initialisiert den Dokumentations-Agenten"""
super().__init__()
self.id = "documentation"
self.name = "Dokumentation"
self.type = "documentation"
self.description = "Erstellt Dokumentation und strukturierte Inhalte"
self.capabilities = "report_generation,documentation,content_structuring,technical_writing,knowledge_organization"
self.instructions = """
Du bist der Dokumentations-Agent. Deine Aufgabe:
1. Komplexe Informationen in klare, strukturierte Dokumente umsetzen
2. Verschiedene Dokumentformate erstellen
3. Informationen aus verschiedenen Quellen strukturieren
4. Technische Konzepte verständlich erklären
5. Konsistente Formatierung sicherstellen
"""
self.result_format = "FormattedDocument"
# Chat-Service initialisieren
self.chat_service = None
# Utility-Klassen initialisieren
self.message_utils = MessageUtils()
def get_agent_info(self) -> Dict[str, Any]:
"""Get agent information for agent registry"""
return {
"id": self.id,
"type": self.type,
"name": self.name,
"description": self.description,
"capabilities": self.capabilities,
"result_format": self.result_format
}
def get_base_prompt(self, document_type: str = "") -> str:
"""
Generiert einen Basis-Prompt für den Dokumentations-Agenten.
Args:
document_type: Typ des zu erstellenden Dokuments
Returns:
Basis-Prompt für den Dokumentations-Agenten
"""
# Basis-Prompt
prompt = f"""
Du bist {self.name}, ein {self.type} Agent.
{self.description}
Fähigkeiten: {self.capabilities}
{self.instructions}
"""
# Dokumenttyp-spezifische Anweisungen hinzufügen
if document_type:
prompt += self._get_document_type_instructions(document_type)
return prompt.strip()
def _get_document_type_instructions(self, document_type: str) -> str:
"""
Gibt spezifische Anweisungen für einen bestimmten Dokumenttyp zurück.
Args:
document_type: Typ des Dokuments
Returns:
Spezifische Anweisungen für den Dokumenttyp
"""
document_type = document_type.lower()
if "handbuch" in document_type or "anleitung" in document_type or "guide" in document_type:
return "\n\nHANDBUCH: Beginne mit Zweckbeschreibung, strukturiere in logische Schritte, verwende direkte Anweisungen."
elif "bericht" in document_type or "report" in document_type:
return "\n\nBERICHT: Beginne mit Executive Summary, strukturiere in thematische Abschnitte, halte professionellen Ton."
elif "prozess" in document_type or "process" in document_type:
return "\n\nPROZESS: Beschreibe Zweck, Ziele, Beteiligte, sequenzielle Schritte, Inputs/Outputs und Verantwortlichkeiten."
elif "präsentation" in document_type or "presentation" in document_type:
return "\n\nPRÄSENTATION: Klare Hauptpunkte, visuelle Elemente, Einleitung-Hauptteil-Schluss Struktur."
else:
return "\n\nDOKUMENT: Erstelle ein gut strukturiertes Dokument mit klarer Gliederung und präziser Sprache."
def _detect_document_type(self, message: str) -> str:
"""
Erkennt den Dokumenttyp aus der Nachricht.
Args:
message: Nachricht des Benutzers
Returns:
Erkannter Dokumenttyp
"""
message = message.lower()
if "handbuch" in message or "anleitung" in message or "guide" in message:
return "handbuch"
elif "bericht" in message or "report" in message:
return "bericht"
elif "prozess" in message or "process" in message or "ablauf" in message:
return "prozess"
elif "präsentation" in message or "presentation" in message or "folien" in message:
return "präsentation"
else:
return "dokument"
async def generate_title(self, task: str, document_type: str) -> str:
"""
Generiert einen Titel für das Dokument.
Args:
task: Die Aufgabe/Anfrage
document_type: Typ des Dokuments
Returns:
Generierter Titel
"""
prompt = f"""
Erstelle einen prägnanten, professionellen Titel für folgendes {document_type.capitalize()}:
AUFTRAG: {task}
Gib NUR den Titel zurück, ohne weitere Erklärungen oder Formatierungen.
"""
messages = [
{"role": "system", "content": "Du bist ein Experte für die Erstellung von Dokumenttiteln."},
{"role": "user", "content": prompt}
]
title = await self.chat_service.call_api(messages)
# Bereinige den Titel von Anführungszeichen und Überschriften-Symbolen
title = title.strip('"\'#*- \n\t')
return title
async def generate_summary(self, task: str, document_type: str, title: str) -> str:
"""
Generiert eine Zusammenfassung für das Dokument.
Args:
task: Die Aufgabe/Anfrage
document_type: Typ des Dokuments
title: Titel des Dokuments
Returns:
Generierte Zusammenfassung
"""
prompt = f"""
Erstelle eine prägnante Zusammenfassung für folgendes Dokument:
TITEL: {title}
TYP: {document_type.capitalize()}
AUFTRAG: {task}
Die Zusammenfassung soll einen Überblick über den Zweck und die Hauptinhalte des Dokuments geben.
Sie sollte etwa 3-5 Sätze umfassen und als eigenständiger Abschnitt funktionieren.
"""
messages = [
{"role": "system", "content": "Du bist ein Experte für die Erstellung prägnanter Dokumentzusammenfassungen."},
{"role": "user", "content": prompt}
]
summary = await self.chat_service.call_api(messages)
return summary.strip()
async def generate_toc_with_prompts(self, task: str, document_type: str, title: str, summary: str) -> Dict[str, str]:
"""
Generiert ein Inhaltsverzeichnis mit Prompts für die einzelnen Kapitel.
Args:
task: Die Aufgabe/Anfrage
document_type: Typ des Dokuments
title: Titel des Dokuments
summary: Zusammenfassung des Dokuments
Returns:
Dict mit Kapiteltiteln als Schlüssel und Prompts als Werte
"""
prompt = f"""
Erstelle ein strukturiertes Inhaltsverzeichnis für folgendes Dokument:
TITEL: {title}
TYP: {document_type.capitalize()}
AUFTRAG: {task}
ZUSAMMENFASSUNG: {summary}
Für jedes Kapitel gib auch einen kurzen Prompt an, der beschreibt, was in diesem Kapitel behandelt werden soll.
Formatiere deine Antwort als JSON-Objekt mit folgendem Format:
{{
"Kapitel 1: Titel": "Prompt für Kapitel 1",
"Kapitel 2: Titel": "Prompt für Kapitel 2",
...
}}
Beschränke dich auf sowenige Kapitel wie nötig, die das Thema umfassend behandeln. Schreibe in Prosa und nur als Liste, wenn auch angebracht.
"""
messages = [
{"role": "system", "content": "Du bist ein Experte für die Strukturierung von Dokumenten und die Erstellung von Inhaltsverzeichnissen."},
{"role": "user", "content": prompt}
]
toc_response = await self.chat_service.call_api(messages)
# JSON aus der Antwort extrahieren
import json
import re
# Markdown-Code-Blöcke entfernen, falls vorhanden
toc_response = re.sub(r'```json\s*|\s*```', '', toc_response)
try:
toc_with_prompts = json.loads(toc_response)
return toc_with_prompts
except json.JSONDecodeError as e:
logger.error(f"Fehler beim Parsen des Inhaltsverzeichnisses: {str(e)}")
logger.error(f"Rohe Antwort: {toc_response}")
# Notfall-Fallback
return {
"1. Einleitung": "Einführung in das Thema und Überblick",
"2. Hauptteil": "Hauptinhalte des Dokuments",
"3. Schlussfolgerung": "Zusammenfassung und nächste Schritte"
}
async def generate_chapter_content(self, chapter_title: str, chapter_prompt: str,
task: str, document_type: str, title: str, summary: str) -> str:
"""
Generiert den Inhalt für ein bestimmtes Kapitel.
Args:
chapter_title: Titel des Kapitels
chapter_prompt: Prompt für das Kapitel
task: Die Aufgabe/Anfrage
document_type: Typ des Dokuments
title: Titel des Dokuments
summary: Zusammenfassung des Dokuments
Returns:
Generierter Kapitelinhalt
"""
prompt = f"""
Erstelle detaillierten Inhalt für folgendes Kapitel eines {document_type}s:
DOKUMENT-TITEL: {title}
AUFGABE: {task}
KAPITEL: {chapter_title}
ANWEISUNG FÜR DIESES KAPITEL: {chapter_prompt}
Der Inhalt sollte detailliert, informativ und gut strukturiert sein.
Verwende bei Bedarf Unterüberschriften, Aufzählungen und Tabellen zur besseren Strukturierung.
Der Inhalt sollte direkt mit dem Kapiteltext beginnen, ohne den Kapiteltitel zu wiederholen.
"""
messages = [
{"role": "system", "content": "Du bist ein Experte für die Erstellung hochwertiger Dokumentationsinhalte."},
{"role": "user", "content": prompt}
]
chapter_content = await self.chat_service.call_api(messages)
return chapter_content.strip()
def _format_final_document(self, title: str, summary: str, toc: Dict[str, str], chapter_contents: Dict[str, str]) -> str:
"""
Formatiert das endgültige Dokument aus allen Teilen.
Args:
title: Titel des Dokuments
summary: Zusammenfassung
toc: Inhaltsverzeichnis (Dict mit Kapiteltiteln als Schlüssel)
chapter_contents: Kapitelinhalte (Dict mit Kapiteltiteln als Schlüssel und Inhalten als Werte)
Returns:
Formatiertes Dokument
"""
# Titel formatieren
doc = f"# {title}\n\n"
# Zusammenfassung hinzufügen
doc += f"## Zusammenfassung\n\n{summary}\n\n"
# Inhaltsverzeichnis hinzufügen
doc += "## Inhaltsverzeichnis\n\n"
for idx, chapter in enumerate(toc.keys(), 1):
# Extrahiere den reinen Kapitelnamen (entferne Nummerierung, falls vorhanden)
clean_chapter = chapter
if chapter.strip().startswith(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) and '. ' in chapter:
clean_chapter = chapter.split('. ', 1)[1]
doc += f"{idx}. {clean_chapter}\n"
doc += "\n"
# Kapitelinhalte hinzufügen
for idx, (chapter, content) in enumerate(chapter_contents.items(), 1):
# Extrahiere den reinen Kapitelnamen (entferne Nummerierung, falls vorhanden)
clean_chapter = chapter
if chapter.strip().startswith(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) and '. ' in chapter:
clean_chapter = chapter.split('. ', 1)[1]
doc += f"## {idx}. {clean_chapter}\n\n{content}\n\n"
# Metadaten hinzufügen
doc += "---\n\n"
doc += f"**Erstellt durch:** {self.name}\n"
return doc
async def process_message(self, message: Dict[str, Any],
workflow: Dict[str, Any],
context: Dict[str, Any] = None,
log_func=None) -> Dict[str, Any]:
"""
Verarbeitet eine Nachricht und erstellt Dokumentation in einem strukturierten Prozess.
Args:
message: Die zu verarbeitende Nachricht
workflow: Der aktuelle Workflow
context: Zusätzlicher Kontext
log_func: Funktion für Workflow-Logging
Returns:
Die generierte Dokumentation
"""
# Initialize logging
workflow_id = workflow.get("id", "unknown")
logging_utils = LoggingUtils(workflow_id, log_func)
logging_utils.info(f"DocumentationAgent startet Dokumentationserstellung", "agents")
# Create response message
response = self.message_utils.create_message(workflow_id, role="assistant")
response["agent_type"] = self.type
response["agent_name"] = self.name
response["parent_message_id"] = message.get("id")
try:
# Chat-Service initialisieren, falls noch nicht geschehen
if self.chat_service is None:
self.chat_service = ChatService()
# Task aus der Nachricht extrahieren
task = message.get("content", "")
if context and "task" in context:
task = context["task"]
# Dokumenttyp erkennen
document_type = self._detect_document_type(task)
logging_utils.info(f"Dokumenttyp erkannt: {document_type}", "agents")
# Schritt 1: Titel generieren
title = await self.generate_title(task, document_type)
logging_utils.info(f"Titel generiert: {title}", "agents")
# Schritt 2: Zusammenfassung generieren
summary = await self.generate_summary(task, document_type, title)
logging_utils.info("Zusammenfassung generiert", "agents")
# Schritt 3: Inhaltsverzeichnis mit Prompts generieren
toc_with_prompts = await self.generate_toc_with_prompts(task, document_type, title, summary)
logging_utils.info(f"Inhaltsverzeichnis mit {len(toc_with_prompts)} Kapiteln generiert", "agents")
# Schritt 4: Kapitelinhalte in einer Schleife generieren
chapter_contents = {}
for chapter_title, chapter_prompt in toc_with_prompts.items():
logging_utils.info(f"Generiere Inhalt für Kapitel: {chapter_title}", "agents")
content = await self.generate_chapter_content(
chapter_title, chapter_prompt, task, document_type, title, summary
)
chapter_contents[chapter_title] = content
# Schritt 5: Dokument zusammenführen
final_document = self._format_final_document(title, summary, toc_with_prompts, chapter_contents)
logging_utils.info(f"Dokument fertiggestellt mit {len(final_document)} Zeichen", "agents")
# Set the content in the response
response["content"] = final_document
# Finalize the message
self.message_utils.finalize_message(response)
response["result_format"] = self.result_format
# Chat-Service schließen
await self.chat_service.close()
self.chat_service = None
return response
except Exception as e:
error_msg = f"Fehler bei der Dokumentationserstellung: {str(e)}"
logging_utils.error(error_msg, "error")
# Chat-Service schließen bei Fehler
if self.chat_service:
try:
await self.chat_service.close()
except:
pass
self.chat_service = None
# Create error response
response["content"] = f"## Fehler bei der Dokumentationserstellung\n\n{error_msg}\n\n```\n{traceback.format_exc()}\n```"
self.message_utils.finalize_message(response)
return response
# Singleton-Instanz
_documentation_agent = None
def get_documentation_agent():
"""Gibt eine Singleton-Instanz des Dokumentations-Agenten zurück"""
global _documentation_agent
if _documentation_agent is None:
_documentation_agent = DocumentationAgent()
return _documentation_agent