fix: Beschreibung generieren gibt jetzt reinen Fließtext aus

Neuer raw_text Parameter in call_claude() umgeht den JSON-System-Prompt.
Haiku gibt direkt lesbaren Text zurück statt JSON-Objekte.
Gesamtes JSON-Parsing (_json_to_text, Markdown-Strip) entfernt.
Dieser Commit ist enthalten in:
Claude Dev
2026-03-28 00:20:36 +01:00
Ursprung 813b3d975e
Commit 322004e0b4
2 geänderte Dateien mit 9 neuen und 49 gelöschten Zeilen

Datei anzeigen

@@ -43,7 +43,7 @@ def _sanitize_mdash(text: str) -> str:
"""Entfernt Gedankenstriche aus LLM-Output (KI-Indikator).""" """Entfernt Gedankenstriche aus LLM-Output (KI-Indikator)."""
return text.replace("\u2014", ", ").replace("\u2013", ", ") return text.replace("\u2014", ", ").replace("\u2013", ", ")
async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", model: str | None = None) -> tuple[str, ClaudeUsage]: async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", model: str | None = None, raw_text: bool = False) -> tuple[str, ClaudeUsage]:
"""Ruft Claude CLI auf. Gibt (result_text, usage) zurück. """Ruft Claude CLI auf. Gibt (result_text, usage) zurück.
Prompt wird via stdin uebergeben um OS ARG_MAX Limits zu vermeiden. Prompt wird via stdin uebergeben um OS ARG_MAX Limits zu vermeiden.
@@ -60,11 +60,12 @@ async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", mod
cmd.extend(["--allowedTools", tools]) cmd.extend(["--allowedTools", tools])
else: else:
cmd.extend(["--max-turns", "1", "--allowedTools", ""]) cmd.extend(["--max-turns", "1", "--allowedTools", ""])
cmd.extend(["--append-system-prompt", if not raw_text:
"CRITICAL: You are a JSON-only output agent. " cmd.extend(["--append-system-prompt",
"Output EXCLUSIVELY a single valid JSON object. " "CRITICAL: You are a JSON-only output agent. "
"No explanatory text, no markdown fences, no continuation of previous responses. " "Output EXCLUSIVELY a single valid JSON object. "
"Start your response with { and end with }."]) "No explanatory text, no markdown fences, no continuation of previous responses. "
"Start your response with { and end with }."])
process = await asyncio.create_subprocess_exec( process = await asyncio.create_subprocess_exec(
*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,

Datei anzeigen

@@ -186,30 +186,6 @@ Erstelle eine knappe, informative Beschreibung mit:
Schreibe NUR die Beschreibung als Fliesstext (3-5 Zeilen). Keine Erklaerungen davor oder danach.""" Schreibe NUR die Beschreibung als Fliesstext (3-5 Zeilen). Keine Erklaerungen davor oder danach."""
def _json_to_text(obj, depth=0):
"""Konvertiert verschachteltes JSON in lesbaren Fliesstext."""
parts = []
if isinstance(obj, str):
return obj
if isinstance(obj, list):
for item in obj:
if isinstance(item, str):
parts.append(f"- {item}")
elif isinstance(item, dict):
parts.append(_json_to_text(item, depth + 1))
return "\n".join(parts)
if isinstance(obj, dict):
for key, val in obj.items():
if isinstance(val, str):
parts.append(val)
elif isinstance(val, list):
parts.append(_json_to_text(val, depth + 1))
elif isinstance(val, dict):
parts.append(_json_to_text(val, depth + 1))
return "\n".join(parts)
return str(obj)
_enhance_logger = logging.getLogger("osint.enhance") _enhance_logger = logging.getLogger("osint.enhance")
@@ -227,29 +203,12 @@ async def enhance_description(
prompt = template.format(title=data.title.strip(), context=context) prompt = template.format(title=data.title.strip(), context=context)
try: try:
result, usage = await call_claude(prompt, tools=None, model=CLAUDE_MODEL_FAST) result, usage = await call_claude(prompt, tools=None, model=CLAUDE_MODEL_FAST, raw_text=True)
# call_claude erzwingt bei tools=None JSON-Output —
# Haiku wrapped den Text dann in ein JSON-Objekt (oft verschachtelt)
text = result.strip()
# Markdown-Code-Block-Wrapper entfernen
import re as _re
_md = _re.search(r'`{3}(?:json)?\s*\n?(.*?)\n?\s*`{3}', text, _re.DOTALL)
if _md:
text = _md.group(1).strip()
try:
import json as _json
parsed = _json.loads(text)
if isinstance(parsed, dict):
text = _json_to_text(parsed)
except (ValueError, TypeError):
pass # Kein JSON — text direkt verwenden
_enhance_logger.info( _enhance_logger.info(
f"Beschreibung generiert fuer \"{data.title[:50]}\": " f"Beschreibung generiert fuer \"{data.title[:50]}\": "
f"{usage.input_tokens}in/{usage.output_tokens}out" f"{usage.input_tokens}in/{usage.output_tokens}out"
) )
return {"description": text} return {"description": result.strip()}
except Exception as e: except Exception as e:
_enhance_logger.error(f"Beschreibung generieren fehlgeschlagen: {e}") _enhance_logger.error(f"Beschreibung generieren fehlgeschlagen: {e}")
raise HTTPException(status_code=500, detail="Beschreibung konnte nicht generiert werden") raise HTTPException(status_code=500, detail="Beschreibung konnte nicht generiert werden")