638 lines
25 KiB
Python
638 lines
25 KiB
Python
"""
|
|
Zentrales Filehandling-Modul für den Agentservice.
|
|
Enthält alle Funktionen für das Verarbeiten von Dateien.
|
|
Angepasst, um mit LucyDOMInterface als zentrale Datei-Autorität zu arbeiten.
|
|
"""
|
|
|
|
import os
|
|
import logging
|
|
import base64
|
|
import json
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Dict, Any, List, Optional, Tuple, Union, BinaryIO
|
|
from io import BytesIO # Import BytesIO at the top level
|
|
|
|
# Bibliotheken für Dateiverarbeitung
|
|
try:
|
|
import pandas as pd
|
|
except ImportError:
|
|
pd = None
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Custom exception für das File-Handling
|
|
class FileProcessingError(Exception):
|
|
"""Basisklasse für Fehler bei der Dateiverarbeitung im AgentService."""
|
|
pass
|
|
|
|
class FileExtractionError(FileProcessingError):
|
|
"""Fehler bei der Textextraktion aus Dateien."""
|
|
pass
|
|
|
|
class FileAnalysisError(FileProcessingError):
|
|
"""Fehler bei der Analyse von Dateien."""
|
|
pass
|
|
|
|
def encode_to_base64(content: bytes, mime_type: str = None) -> str:
|
|
"""
|
|
Kodiert Binärdaten als Base64-String.
|
|
|
|
Args:
|
|
content: Die zu kodierenden Binärdaten
|
|
mime_type: Optionaler MIME-Typ für das Encoding
|
|
|
|
Returns:
|
|
Base64-kodierter String
|
|
"""
|
|
base64_data = base64.b64encode(content).decode('utf-8')
|
|
return base64_data
|
|
|
|
def prepare_file_contexts(files: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""
|
|
Bereitet die Dateikontexte basierend auf Metadaten vor.
|
|
Akzeptiert keine Pfade mehr, sondern nur Metadaten aus der Datenbank.
|
|
|
|
Args:
|
|
files: Liste von Dateien mit Metadaten (Dict mit id, name, type, content_type)
|
|
|
|
Returns:
|
|
Liste von Dateikontexten für die Verarbeitung
|
|
"""
|
|
file_contexts = []
|
|
|
|
logger.info(f"Preparing file contexts for {len(files)} files")
|
|
|
|
for file in files:
|
|
file_id = file.get("id")
|
|
file_name = file.get("name")
|
|
file_type = file.get("type")
|
|
|
|
# Create a comprehensive context with all available metadata
|
|
context = {
|
|
"id": file_id,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"size": file.get("size", "Unbekannt"),
|
|
"content_type": file.get("content_type"),
|
|
"path": file.get("path"),
|
|
"upload_date": file.get("upload_date"),
|
|
"hash": file.get("hash"),
|
|
"mandate_id": file.get("mandate_id"),
|
|
"user_id": file.get("user_id")
|
|
}
|
|
|
|
# Log for debugging
|
|
logger.info(f"Created file context: {file_name} (ID: {file_id}, Type: {file_type})")
|
|
|
|
file_contexts.append(context)
|
|
|
|
return file_contexts
|
|
|
|
def is_text_extractable(file_name: str, content_type: str = None) -> bool:
|
|
"""
|
|
Prüft, ob aus der Datei Text extrahiert werden kann.
|
|
|
|
Args:
|
|
file_name: Name der Datei für die Erkennung des Formats
|
|
content_type: Optional MIME-Typ der Datei
|
|
|
|
Returns:
|
|
True wenn Text extrahiert werden kann, sonst False
|
|
"""
|
|
# Einfache Textdateien
|
|
if file_name.endswith(('.txt', '.md', '.json', '.xml', '.html', '.htm', '.css', '.js', '.py', '.csv')):
|
|
return True
|
|
|
|
# Excel-Dateien
|
|
elif file_name.endswith(('.xlsx', '.xls')):
|
|
return pd is not None # Nur extrahierbar, wenn pandas installiert ist
|
|
|
|
# PDF-Dateien - Textextraktion ist möglich
|
|
elif file_name.endswith('.pdf'):
|
|
try:
|
|
# Prüfen ob PyPDF2 oder PyMuPDF installiert sind
|
|
try:
|
|
import PyPDF2
|
|
return True
|
|
except ImportError:
|
|
try:
|
|
import fitz # PyMuPDF
|
|
return True
|
|
except ImportError:
|
|
return False
|
|
except:
|
|
return False
|
|
|
|
# Bildformate - nicht als Text extrahierbar
|
|
elif file_name.endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg')):
|
|
return False
|
|
|
|
# Video-Formate - nicht als Text extrahierbar
|
|
elif file_name.endswith(('.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv')):
|
|
return False
|
|
|
|
# Audio-Formate - nicht als Text extrahierbar
|
|
elif file_name.endswith(('.mp3', '.wav', '.ogg', '.flac', '.aac')):
|
|
return False
|
|
|
|
# Content-Type prüfen, falls Dateiendung nicht eindeutig ist
|
|
if content_type:
|
|
if content_type.startswith(('text/', 'application/json', 'application/xml')):
|
|
return True
|
|
elif content_type == 'application/pdf':
|
|
return True
|
|
elif content_type.startswith(('image/', 'video/', 'audio/')):
|
|
return False
|
|
|
|
# Im Zweifelsfall versuchen zu extrahieren
|
|
return True
|
|
|
|
def extract_text_from_file_content(file_content: bytes, file_name: str, content_type: str = None) -> Tuple[str, bool]:
|
|
"""
|
|
Extrahiert Text aus verschiedenen Dateiformaten basierend auf dem Binärinhalt.
|
|
|
|
Args:
|
|
file_content: Binärinhalt der Datei
|
|
file_name: Name der Datei für die Erkennung des Formats
|
|
content_type: Optional MIME-Typ der Datei
|
|
|
|
Returns:
|
|
Tuple mit (extrahierter Text, is_extracted Flag)
|
|
"""
|
|
# Prüfen, ob Text extrahierbar ist
|
|
if not is_text_extractable(file_name, content_type):
|
|
return f"[Datei: {file_name} - Textextraktion nicht unterstützt]", False
|
|
|
|
try:
|
|
# Einfache Textdateien
|
|
if file_name.endswith(('.txt', '.md', '.json', '.xml', '.html', '.htm', '.css', '.js', '.py')):
|
|
try:
|
|
return file_content.decode('utf-8'), True
|
|
except UnicodeDecodeError:
|
|
try:
|
|
return file_content.decode('latin1'), True
|
|
except:
|
|
return file_content.decode('cp1252', errors='replace'), True
|
|
|
|
# Excel-Dateien
|
|
elif file_name.endswith(('.xlsx', '.xls')):
|
|
if pd is not None:
|
|
# Temporäre Datei im Speicher erstellen
|
|
file_obj = BytesIO(file_content)
|
|
df = pd.read_excel(file_obj)
|
|
result = f"Excel file with {len(df)} rows and {len(df.columns)} columns.\n"
|
|
result += f"Columns: {', '.join(df.columns.tolist())}\n\n"
|
|
result += df.to_string(index=False)
|
|
return result, True
|
|
else:
|
|
return f"[Excel-Datei: {file_name} - pandas nicht installiert]", False
|
|
|
|
# CSV-Dateien
|
|
elif file_name.endswith('.csv'):
|
|
if pd is not None:
|
|
try:
|
|
# Temporäre Datei im Speicher erstellen
|
|
file_obj = BytesIO(file_content)
|
|
df = pd.read_csv(file_obj, encoding='utf-8')
|
|
except UnicodeDecodeError:
|
|
file_obj = BytesIO(file_content)
|
|
try:
|
|
df = pd.read_csv(file_obj, encoding='latin1')
|
|
except:
|
|
file_obj = BytesIO(file_content)
|
|
df = pd.read_csv(file_obj, encoding='cp1252')
|
|
|
|
result = f"CSV file with {len(df)} rows and {len(df.columns)} columns.\n"
|
|
result += f"Columns: {', '.join(df.columns.tolist())}\n\n"
|
|
result += df.to_string(index=False)
|
|
return result, True
|
|
else:
|
|
return f"[CSV-Datei: {file_name} - pandas nicht installiert]", False
|
|
|
|
# PDF-Dateien
|
|
elif file_name.endswith('.pdf'):
|
|
try:
|
|
try:
|
|
from PyPDF2 import PdfReader
|
|
reader = PdfReader(BytesIO(file_content))
|
|
text = ""
|
|
for page in reader.pages:
|
|
text += page.extract_text() + "\n\n"
|
|
return text, True
|
|
except ImportError:
|
|
try:
|
|
import fitz # PyMuPDF
|
|
doc = fitz.open(stream=file_content, filetype="pdf")
|
|
text = ""
|
|
for page in doc:
|
|
text += page.get_text() + "\n\n"
|
|
return text, True
|
|
except ImportError:
|
|
return f"[PDF: {file_name} - Keine PDF-Bibliothek installiert]", False
|
|
except Exception as e:
|
|
raise FileExtractionError(f"Fehler beim Lesen der PDF-Datei {file_name}: {str(e)}")
|
|
|
|
# Sonstige Dateien
|
|
else:
|
|
return f"[Datei: {file_name} - Textextraktion nicht unterstützt]", False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Extrahieren von Text aus {file_name}: {str(e)}")
|
|
return f"[Fehler bei der Textextraktion: {str(e)}]", False
|
|
|
|
async def extract_and_analyze_pdf_images(
|
|
pdf_content: bytes,
|
|
prompt: str,
|
|
ai_service
|
|
) -> List[Dict[str, Any]]:
|
|
"""
|
|
Extrahiert Bilder aus einer PDF-Datei und analysiert sie.
|
|
Arbeitet mit Binärdaten statt Dateipfaden.
|
|
|
|
Args:
|
|
pdf_content: Binärdaten der PDF-Datei
|
|
prompt: Prompt für die Bildanalyse
|
|
ai_service: AI-Service für die Bildanalyse
|
|
|
|
Returns:
|
|
Liste mit Analyseergebnissen für jedes Bild
|
|
"""
|
|
image_responses = []
|
|
temp_files = [] # Liste der temporären Dateien zur Bereinigung
|
|
|
|
try:
|
|
# PDF mit PyMuPDF öffnen
|
|
import fitz # PyMuPDF
|
|
# BytesIO is already imported at the top level
|
|
import tempfile
|
|
|
|
# PDF im Speicher öffnen
|
|
doc = fitz.open(stream=pdf_content, filetype="pdf")
|
|
logger.info(f"PDF geöffnet mit {len(doc)} Seiten")
|
|
|
|
for page_num, page in enumerate(doc, 1):
|
|
# Alle Bilder auf der Seite finden
|
|
image_list = page.get_images(full=True)
|
|
|
|
if image_list:
|
|
logger.info(f"Seite {page_num}: {len(image_list)} Bilder gefunden")
|
|
|
|
for img_index, img in enumerate(image_list):
|
|
try:
|
|
# Bild-Referenz
|
|
xref = img[0]
|
|
|
|
# Bild und Metadaten extrahieren
|
|
base_image = doc.extract_image(xref)
|
|
image_bytes = base_image["image"] # Tatsächliche Bilddaten
|
|
image_ext = base_image["ext"] # Dateiendung (jpg, png, etc.)
|
|
|
|
# Erstelle temporäre Datei
|
|
fd, temp_img_path = tempfile.mkstemp(suffix=f".{image_ext}")
|
|
temp_files.append(temp_img_path) # Zur Bereinigungsliste hinzufügen
|
|
|
|
with os.fdopen(fd, 'wb') as img_file:
|
|
img_file.write(image_bytes)
|
|
|
|
logger.debug(f"Bild temporär gespeichert: {temp_img_path}")
|
|
|
|
# Analysiere mit AI-Service
|
|
try:
|
|
analysis_result = await ai_service.analyze_image(
|
|
image_data=image_bytes, # Direktes Übergeben der Bilddaten
|
|
prompt=prompt,
|
|
mime_type=f"image/{image_ext}"
|
|
)
|
|
logger.debug(f"Bildanalyse für Bild {img_index} auf Seite {page_num} abgeschlossen")
|
|
except Exception as analyze_error:
|
|
logger.error(f"Fehler bei der Bildanalyse: {str(analyze_error)}")
|
|
analysis_result = f"[Fehler bei der Bildanalyse: {str(analyze_error)}]"
|
|
|
|
# Ergebnis speichern
|
|
try:
|
|
# Versuche zuerst, die Größe aus base_image zu bekommen
|
|
if 'width' in base_image and 'height' in base_image:
|
|
image_size = f"{base_image['width']}x{base_image['height']}"
|
|
else:
|
|
# Alternative: Öffne das temporäre Bild, um die Größe zu bestimmen
|
|
from PIL import Image
|
|
with Image.open(temp_img_path) as img:
|
|
width, height = img.size
|
|
image_size = f"{width}x{height}"
|
|
except Exception as e:
|
|
logger.warning(f"Konnte Bildgröße nicht ermitteln: {str(e)}")
|
|
image_size = "unbekannt"
|
|
|
|
image_responses.append({
|
|
"page": page_num,
|
|
"image_index": img_index,
|
|
"format": image_ext,
|
|
"image_size": image_size,
|
|
"response": analysis_result
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.warning(f"Fehler bei der Extraktion von Bild {img_index} auf Seite {page_num}: {str(e)}")
|
|
continue
|
|
|
|
logger.info(f"Extrahiert und analysiert: {len(image_responses)} Bilder aus PDF")
|
|
|
|
except ImportError:
|
|
logger.error("PyMuPDF (fitz) ist nicht installiert. Installiere es mit 'pip install pymupdf'")
|
|
raise FileExtractionError("PyMuPDF (fitz) ist nicht installiert")
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Extrahieren von PDF-Bildern: {str(e)}")
|
|
raise FileExtractionError(f"Fehler beim Extrahieren von PDF-Bildern: {str(e)}")
|
|
finally:
|
|
# Bereinige alle temporären Dateien
|
|
for temp_file in temp_files:
|
|
try:
|
|
if os.path.exists(temp_file):
|
|
os.remove(temp_file)
|
|
except Exception as e:
|
|
logger.warning(f"Konnte temporäre Datei nicht entfernen: {temp_file} - {str(e)}")
|
|
|
|
return image_responses
|
|
|
|
def add_file_to_message(message: Dict[str, Any], file_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
Fügt eine Datei zu einer Nachricht hinzu mit Kennzeichnung, ob Text extrahiert wurde.
|
|
|
|
Args:
|
|
message: Die zu erweiternde Nachricht
|
|
file_data: Dateimetadaten und Inhalt
|
|
|
|
Returns:
|
|
Die aktualisierte Nachricht mit der Datei
|
|
"""
|
|
# Detailliertes Logging für Debugging
|
|
logger.info(f"Adding file to message: {file_data.get('name', 'unnamed_file')} (ID: {file_data.get('id', 'unknown')})")
|
|
|
|
# Initialize documents array if needed
|
|
if "documents" not in message:
|
|
message["documents"] = []
|
|
logger.debug("Initialized empty documents array in message")
|
|
|
|
# Create a unique ID for the document if not provided
|
|
import uuid
|
|
doc_id = file_data.get("id", f"file_{uuid.uuid4()}")
|
|
|
|
# Extract file size if available
|
|
file_size = file_data.get("size")
|
|
if isinstance(file_size, str) and file_size.isdigit():
|
|
file_size = int(file_size)
|
|
elif file_size is None and file_data.get("content"):
|
|
# Estimate size from content if not provided
|
|
file_size = len(file_data.get("content", ""))
|
|
|
|
# Bestimmen, ob der Inhalt bereits extrahiert wurde
|
|
content = file_data.get("content", "No content available")
|
|
file_name = file_data.get("name", "unnamed_file")
|
|
content_type = file_data.get("content_type")
|
|
|
|
# Prüfen, ob der Inhalt als extrahiert markiert werden sollte
|
|
is_extracted = file_data.get("is_extracted", False)
|
|
if not is_extracted and isinstance(content, str) and content.strip() and file_name:
|
|
# Wenn nicht explizit markiert, aber Inhalt vorhanden ist, prüfen wir den Dateityp
|
|
is_extracted = is_text_extractable(file_name, content_type)
|
|
|
|
# Create standard document structure that matches the data model
|
|
document = {
|
|
"id": doc_id,
|
|
"source": {
|
|
"type": "file",
|
|
"id": file_data.get("id", doc_id),
|
|
"name": file_name,
|
|
"content_type": content_type,
|
|
"size": file_size,
|
|
"upload_date": file_data.get("upload_date", datetime.now().isoformat())
|
|
},
|
|
"contents": [
|
|
{
|
|
"type": "text",
|
|
"text": content,
|
|
"is_extracted": is_extracted # Flag für den Extraktionsstatus hinzufügen
|
|
}
|
|
]
|
|
}
|
|
|
|
# Log document structure for debugging
|
|
logger.debug(f"Created document structure: id={doc_id}, name={file_name}, is_extracted={is_extracted}")
|
|
|
|
# Check if file is already in the message to avoid duplicates
|
|
file_already_added = any(
|
|
doc.get("source", {}).get("id") == file_data.get("id")
|
|
for doc in message.get("documents", [])
|
|
)
|
|
|
|
if not file_already_added:
|
|
message["documents"].append(document)
|
|
logger.info(f"File {file_name} successfully added to message (total: {len(message.get('documents', []))} files)")
|
|
else:
|
|
logger.info(f"File {file_name} already exists in message, skipping")
|
|
|
|
return message
|
|
|
|
def extract_files_from_message(message: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
"""
|
|
Extrahiert Dateiinformationen aus einer Nachricht.
|
|
Funktion für Workflow-Manager und interne Verwendung.
|
|
|
|
Args:
|
|
message: Die Nachricht, aus der Dateien extrahiert werden sollen
|
|
|
|
Returns:
|
|
Liste der extrahierten Dateiinformationen
|
|
"""
|
|
files = []
|
|
|
|
if "documents" not in message:
|
|
logger.debug("No documents found in message")
|
|
return files
|
|
|
|
# Log for debugging
|
|
logger.debug(f"Extracting files from message with {len(message.get('documents', []))} documents")
|
|
|
|
for doc in message.get("documents", []):
|
|
doc_source = doc.get("source", {})
|
|
|
|
# Nur Dateien extrahieren
|
|
if doc_source.get("type") == "file":
|
|
file_info = {
|
|
"id": doc_source.get("id", f"file_{uuid.uuid4()}"),
|
|
"name": doc_source.get("name", "unnamed_file"),
|
|
"content_type": doc_source.get("content_type"),
|
|
"size": doc_source.get("size")
|
|
}
|
|
|
|
# Inhalt extrahieren, falls vorhanden
|
|
doc_contents = doc.get("contents", [])
|
|
for content in doc_contents:
|
|
if content.get("type") == "text":
|
|
file_info["content"] = content.get("text", "")
|
|
break
|
|
|
|
logger.debug(f"Extracted file: {file_info.get('name')} (ID: {file_info.get('id')})")
|
|
files.append(file_info)
|
|
else:
|
|
logger.debug(f"Skipping non-file document of type: {doc_source.get('type')}")
|
|
|
|
logger.info(f"Extracted {len(files)} files from message")
|
|
return files
|
|
|
|
async def read_file_contents(
|
|
file_contexts: List[Dict[str, Any]],
|
|
lucydom_interface,
|
|
workflow_id: str = None,
|
|
add_log_func = None,
|
|
ai_service = None # AI service parameter for image analysis
|
|
) -> Dict[str, Dict[str, Any]]:
|
|
"""
|
|
Liest den Inhalt aller Dateien und führt bei Bildern und Dokumenten Analysen durch.
|
|
Verwendet LucyDOM-Interface statt direkter Dateizugriffe.
|
|
Gibt jetzt ein Dictionary mit Dateiinhalten und Extraktionsstatus zurück.
|
|
|
|
Args:
|
|
file_contexts: Liste der Dateikontexte mit Metadaten
|
|
lucydom_interface: LucyDOM-Interface für Dateizugriffe
|
|
workflow_id: Optionale ID des Workflows für Logging
|
|
add_log_func: Optionale Funktion für das Hinzufügen von Logs
|
|
ai_service: Optionaler AI-Service für die Bildanalyse
|
|
|
|
Returns:
|
|
Dictionary mit Dateiinhalten und Metadaten (file_id -> {content, is_extracted, ...})
|
|
"""
|
|
file_contents = {}
|
|
|
|
# Add debug logging
|
|
logger.info(f"Reading contents of {len(file_contexts)} files for workflow {workflow_id}")
|
|
|
|
for file in file_contexts:
|
|
file_id = file["id"]
|
|
file_name = file["name"]
|
|
file_type = file.get("type", "unknown")
|
|
|
|
try:
|
|
# Dateiinhalt über LucyDOM-Interface abrufen
|
|
file_data = await lucydom_interface.read_file_content(file_id)
|
|
|
|
if not file_data:
|
|
_log(add_log_func, workflow_id, f"Datei {file_name} nicht gefunden", "warning")
|
|
file_contents[file_id] = {
|
|
"content": f"File content not available (File not found)",
|
|
"is_extracted": False,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
continue
|
|
|
|
logger.info(f"Successfully read file: {file_name} (ID: {file_id}, Type: {file_type})")
|
|
|
|
# Bildverarbeitung - immer KI-Analyse verwenden, wenn verfügbar
|
|
if file_type == "image" or file_name.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')):
|
|
if ai_service and hasattr(ai_service, "analyze_image"):
|
|
try:
|
|
image_analysis = await ai_service.analyze_image(
|
|
image_data=file_data,
|
|
prompt="Describe this image in detail",
|
|
mime_type=file.get("content_type")
|
|
)
|
|
|
|
logger.debug(f"Image analysis successfully generated for {file_name}")
|
|
|
|
file_contents[file_id] = {
|
|
"content": f"Image Analysis:\n{image_analysis}",
|
|
"is_extracted": False, # Bildanalyse gilt nicht als Text-Extraktion
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
_log(add_log_func, workflow_id, f"Image {file_name} analyzed successfully", "info")
|
|
except Exception as e:
|
|
logger.error(f"Error analyzing image {file_name}: {str(e)}")
|
|
_log(add_log_func, workflow_id, f"Error analyzing image {file_name}: {str(e)}", "error")
|
|
file_contents[file_id] = {
|
|
"content": f"Image file: {file_name} (Analysis failed: {str(e)})",
|
|
"is_extracted": False,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
else:
|
|
file_contents[file_id] = {
|
|
"content": f"Image file: {file_name} (AI analysis not available)",
|
|
"is_extracted": False,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
|
|
# Dokument- und Textdateien
|
|
elif file_type == "document" or not file_type:
|
|
# Verwende die zentrale Textextraktionsfunktion mit Dateiinhalt
|
|
content, is_extracted = extract_text_from_file_content(
|
|
file_data, file_name, file.get("content_type")
|
|
)
|
|
file_contents[file_id] = {
|
|
"content": content,
|
|
"is_extracted": is_extracted,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
_log(add_log_func, workflow_id,
|
|
f"File {file_name} read successfully (extracted: {is_extracted})", "info")
|
|
|
|
# Andere Dateitypen - nur Metadaten speichern
|
|
else:
|
|
file_contents[file_id] = {
|
|
"content": f"File: {file_name} (Type: {file_type}, content not available)",
|
|
"is_extracted": False,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
_log(add_log_func, workflow_id, f"Unsupported file type: {file_type} for {file_name}", "warning")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error reading file {file_name}: {str(e)}")
|
|
_log(add_log_func, workflow_id, f"Error reading file {file_name}: {str(e)}", "error")
|
|
file_contents[file_id] = {
|
|
"content": f"File content not available (Error: {str(e)})",
|
|
"is_extracted": False,
|
|
"name": file_name,
|
|
"type": file_type,
|
|
"content_type": file.get("content_type")
|
|
}
|
|
|
|
return file_contents
|
|
|
|
def _log(add_log_func, workflow_id, message, log_type, agent_id=None, agent_name=None):
|
|
"""Hilfsfunktion zum Loggen mit unterschiedlichen Log-Funktionen"""
|
|
# Log über die Logger-Instanz
|
|
if log_type == "error":
|
|
logger.error(message)
|
|
elif log_type == "warning":
|
|
logger.warning(message)
|
|
else:
|
|
logger.info(message)
|
|
|
|
# Log über die bereitgestellte Log-Funktion (falls vorhanden)
|
|
if add_log_func and workflow_id:
|
|
add_log_func(workflow_id, message, log_type, agent_id, agent_name)
|
|
|
|
def _log(add_log_func, workflow_id, message, log_type, agent_id=None, agent_name=None):
|
|
"""Hilfsfunktion zum Loggen mit unterschiedlichen Log-Funktionen"""
|
|
# Log über die Logger-Instanz
|
|
if log_type == "error":
|
|
logger.error(message)
|
|
elif log_type == "warning":
|
|
logger.warning(message)
|
|
else:
|
|
logger.info(message)
|
|
|
|
# Log über die bereitgestellte Log-Funktion (falls vorhanden)
|
|
if add_log_func and workflow_id:
|
|
add_log_func(workflow_id, message, log_type, agent_id, agent_name)
|