fix: Pipeline JSON-Parsing + defensive Zugriffe

- Curator/Writer: Doppelt-encodiertes JSON abfangen (isinstance + json.loads)
- Pipeline: .get() statt direkte Dict-Zugriffe gegen TypeError
- TypeError zum except-Block hinzugefügt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Dev
2026-03-29 14:53:42 +02:00
Ursprung c53d441c69
Commit 144b7c05c9
3 geänderte Dateien mit 21 neuen und 7 gelöschten Zeilen

Datei anzeigen

@@ -139,8 +139,14 @@ Antworte als JSON-Array:
try: try:
topics = _extract_json(result) topics = _extract_json(result)
# Doppelt-encodiertes JSON abfangen
if isinstance(topics, str):
topics = json.loads(topics)
if not isinstance(topics, list):
logger.error(f"Curator: Unerwarteter Typ {type(topics).__name__}, erwartet list")
return []
logger.info(f"Curator: {len(topics)} Themen ausgewählt (${usage.cost_usd:.4f})") logger.info(f"Curator: {len(topics)} Themen ausgewählt (${usage.cost_usd:.4f})")
return topics return topics
except (json.JSONDecodeError, IndexError) as e: except (json.JSONDecodeError, IndexError, TypeError) as e:
logger.error(f"Curator JSON-Parse-Fehler: {e}\nRaw: {result[:500]}") logger.error(f"Curator JSON-Parse-Fehler: {e}\nRaw: {result[:300]}")
return [] return []

Datei anzeigen

@@ -73,18 +73,20 @@ async def run_pipeline():
logger.warning("Keine Themen ausgewählt -- Pipeline beendet") logger.warning("Keine Themen ausgewählt -- Pipeline beendet")
return return
logger.info(f"{len(topics)} Themen ausgewählt: {[t['topic'] for t in topics]}") logger.info(f"{len(topics)} Themen ausgewählt: {[t.get('topic', '?') if isinstance(t, dict) else str(t)[:50] for t in topics]}")
# 2. Artikel schreiben # 2. Artikel schreiben
logger.info("Schritt 2: Artikel schreiben...") logger.info("Schritt 2: Artikel schreiben...")
articles = [] articles = []
for topic in topics: for topic in topics:
logger.info(f"Schreibe: {topic['topic']} ({topic['category']})") topic_title = topic.get('topic', 'Unbekannt') if isinstance(topic, dict) else str(topic)[:50]
topic_cat = topic.get('category', '?') if isinstance(topic, dict) else '?'
logger.info(f"Schreibe: {topic_title} ({topic_cat})")
article = await write_article(topic, call_claude) article = await write_article(topic, call_claude)
if article: if article:
articles.append(article) articles.append(article)
else: else:
logger.warning(f"Artikel fehlgeschlagen: {topic['topic']}") logger.warning(f"Artikel fehlgeschlagen: {topic_title}")
if not articles: if not articles:
logger.warning("Keine Artikel geschrieben -- Pipeline beendet") logger.warning("Keine Artikel geschrieben -- Pipeline beendet")

Datei anzeigen

@@ -149,10 +149,16 @@ Falls das Thema einen geographischen Bezug hat, fülle geo_data:
try: try:
article = _extract_json(result) article = _extract_json(result)
# Doppelt-encodiertes JSON abfangen
if isinstance(article, str):
article = json.loads(article)
if not isinstance(article, dict):
logger.error(f"Writer: Unerwarteter Typ {type(article).__name__}")
return None
article["category"] = topic["category"] article["category"] = topic["category"]
article["monitor_event_ids"] = topic.get("incident_ids", []) article["monitor_event_ids"] = topic.get("incident_ids", [])
logger.info(f"Writer: Artikel '{article['title']}' geschrieben (${usage.cost_usd:.4f})") logger.info(f"Writer: Artikel '{article['title']}' geschrieben (${usage.cost_usd:.4f})")
return article return article
except (json.JSONDecodeError, IndexError, KeyError) as e: except (json.JSONDecodeError, IndexError, KeyError, TypeError) as e:
logger.error(f"Writer JSON-Parse-Fehler: {e}\nRaw: {result[:500]}") logger.error(f"Writer JSON-Parse-Fehler: {e}\nRaw: {result[:300]}")
return None return None