diff --git a/services/aiknowledge_sync_utils.py b/services/aiknowledge_sync_utils.py index c8b1044..c9fd70c 100644 --- a/services/aiknowledge_sync_utils.py +++ b/services/aiknowledge_sync_utils.py @@ -361,11 +361,13 @@ class AIKnowledgeSync(BaseSyncUtils): mime_type = attachment.get('type', 'application/octet-stream') file_size = attachment.get('size', 0) original_filename = attachment.get('name', doc_name) # Original filename with extension + # URL-decode filename (fixes special chars like §, ä, ö, ü, etc.) + original_filename = unquote(original_filename) except Exception as e: ctx.logger.warn(f" ⚠️ Failed to get attachment details: {e}, using defaults") mime_type = 'application/octet-stream' file_size = 0 - original_filename = doc_name + original_filename = unquote(doc_name) # Also decode fallback name ctx.logger.info(f" 📎 Attachment: {attachment_id} ({mime_type}, {file_size} bytes)") ctx.logger.info(f" 📄 Original filename: {original_filename}") diff --git a/services/document_sync_utils.py b/services/document_sync_utils.py index 68e0bf5..d872cc3 100644 --- a/services/document_sync_utils.py +++ b/services/document_sync_utils.py @@ -10,6 +10,7 @@ Utility functions for document synchronization with xAI: from typing import Dict, Any, Optional, List, Tuple from datetime import datetime, timedelta +from urllib.parse import unquote from services.sync_utils_base import BaseSyncUtils from services.models import FileStatus, XAISyncStatus @@ -365,6 +366,10 @@ class DocumentSync(BaseSyncUtils): # Filename: Nutze dokumentName/fileName falls vorhanden, sonst aus Attachment final_filename = filename or attachment.get('name', 'unknown') + # URL-decode filename (fixes special chars like §, ä, ö, ü, etc.) + # EspoCRM stores filenames URL-encoded: %C2%A7 → § + final_filename = unquote(final_filename) + return { 'attachment_id': attachment_id, 'download_url': f"/api/v1/Attachment/file/{attachment_id}",