From e0453719691ee13972dcb9c9d23e7c71a9965c28 Mon Sep 17 00:00:00 2001 From: Lars Date: Sat, 27 Dec 2025 18:59:38 +0100 Subject: [PATCH] Anpassung der Textausgabe zur Filterung der Steuerzeichen --- app/core/ingestion/ingestion_utils.py | 40 +++++++++++++++++---------- app/services/llm_service.py | 20 ++++++++++---- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/core/ingestion/ingestion_utils.py b/app/core/ingestion/ingestion_utils.py index f8af8ff..74cb1e6 100644 --- a/app/core/ingestion/ingestion_utils.py +++ b/app/core/ingestion/ingestion_utils.py @@ -1,37 +1,49 @@ """ FILE: app/core/ingestion/ingestion_utils.py DESCRIPTION: Hilfswerkzeuge für JSON-Recovery, Typ-Registry und Konfigurations-Lookups. - AUDIT v2.13.7: Dynamisierung von Cleanup-Patterns und Default-Typen (WP-14). + AUDIT v2.13.8: Zentralisierung der Text-Bereinigung für LLM-Antworten. """ import os import json import re import yaml -from typing import Any, Optional, Dict +from typing import Any, Optional, Dict, List -def extract_json_from_response(text: str, registry: Optional[dict] = None) -> Any: +def clean_llm_text(text: str, registry: Optional[dict] = None) -> str: """ - Extrahiert JSON-Daten und bereinigt LLM-Steuerzeichen (v2.11.14 Logic). - WP-14: Nutzt nun dynamische cleanup_patterns aus der Registry. + Entfernt LLM-Steuerzeichen und Artefakte aus einem Text. + Nutzt die cleanup_patterns aus der Registry oder Standardwerte. """ - if not text or not isinstance(text, str): - return [] - - # Fallback-Patterns für die Bereinigung - patterns = ["", "", "[OUT]", "[/OUT]"] + if not text or not isinstance(text, str): + return "" + + # Fallback-Patterns, falls die Registry nicht greift + default_patterns = ["", "", "[OUT]", "[/OUT]"] # Falls keine Registry übergeben wurde, versuchen wir sie zu laden reg = registry or load_type_registry() - if reg: - # Lade Patterns aus llm_settings (WP-14 Erweiterung) - patterns = reg.get("llm_settings", {}).get("cleanup_patterns", patterns) + + # Lade Patterns aus llm_settings (WP-14 Erweiterung) + patterns: List[str] = reg.get("llm_settings", {}).get("cleanup_patterns", default_patterns) clean = text for p in patterns: clean = clean.replace(p, "") - clean = clean.strip() + return clean.strip() + +def extract_json_from_response(text: str, registry: Optional[dict] = None) -> Any: + """ + Extrahiert JSON-Daten und bereinigt LLM-Steuerzeichen. + WP-14: Nutzt nun die zentrale clean_llm_text Funktion. + """ + if not text: + return [] + # 1. Text zentral bereinigen + clean = clean_llm_text(text, registry) + + # 2. Markdown-Code-Blöcke extrahieren match = re.search(r"```(?:json)?\s*(.*?)\s*```", clean, re.DOTALL) payload = match.group(1) if match else clean diff --git a/app/services/llm_service.py b/app/services/llm_service.py index 17ecea6..b5ce923 100644 --- a/app/services/llm_service.py +++ b/app/services/llm_service.py @@ -6,12 +6,11 @@ DESCRIPTION: Hybrid-Client für Ollama, Google GenAI (Gemini) und OpenRouter. WP-20 Fix: Bulletproof Prompt-Auflösung für format() Aufrufe. WP-22/JSON: Optionales JSON-Schema + strict (für OpenRouter structured outputs). FIX: Intelligente Rate-Limit Erkennung (429 Handling), v1-API Sync & Timeouts. -VERSION: 3.3.7 +VERSION: 3.3.8 STATUS: Active FIX: -- Implementiert striktes max_retries Handling für alle Provider (v.a. für Chat-Stabilität). -- Synchronisiert Rate-Limit Retries mit dem max_retries Parameter. -- Optimiert Logging für sofortige Fehlererkennung. +- Integriert clean_llm_text zur Entfernung von Steuerzeichen (, [OUT] etc.) in Antworten. +- Stellt sicher, dass Chat-Antworten sauber formatiert ausgegeben werden. """ import httpx import yaml @@ -25,6 +24,9 @@ from pathlib import Path from typing import Optional, Dict, Any, Literal from app.config import get_settings +# Import der zentralen Bereinigungs-Logik (WP-14 Fix) +from app.core.ingestion.ingestion_utils import clean_llm_text + logger = logging.getLogger(__name__) @@ -119,22 +121,26 @@ class LLMService: ) -> str: """ Haupteinstiegspunkt für LLM-Anfragen mit Priorisierung. + Wendet die Bereinigung auf Text-Antworten an. """ target_provider = provider or self.settings.MINDNET_LLM_PROVIDER if priority == "background": async with LLMService._background_semaphore: - return await self._dispatch( + res = await self._dispatch( target_provider, prompt, system, force_json, max_retries, base_delay, model_override, json_schema, json_schema_name, strict_json_schema ) + # WP-14 Fix: Bereinige Text-Antworten vor Rückgabe + return clean_llm_text(res) if not force_json else res - return await self._dispatch( + res = await self._dispatch( target_provider, prompt, system, force_json, max_retries, base_delay, model_override, json_schema, json_schema_name, strict_json_schema ) + return clean_llm_text(res) if not force_json else res async def _dispatch( self, @@ -206,6 +212,7 @@ class LLMService: config = types.GenerateContentConfig( system_instruction=system, + # WICHTIG: Gemini 1.5+ unterstützt response_mime_type nativ response_mime_type="application/json" if force_json else "text/plain" ) response = await asyncio.wait_for( @@ -297,6 +304,7 @@ class LLMService: final_prompt = rag_template.format(context_str=context_str, query=query) # RAG Aufrufe im Chat nutzen nun standardmäßig max_retries=2 (überschreibbar) + # Durch den Aufruf von generate_raw_response wird die Bereinigung automatisch angewendet. return await self.generate_raw_response( final_prompt, system=system_prompt,