fix: Pipeline 4/4 Artikel erfolgreich
- _extract_json: Typographische Anfuehrungszeichen ersetzen - _extract_json: Detailliertes Error-Logging bei Parse-Fehlern - Writer-Prompt: Regel 5 verbietet doppelte Anfuehrungszeichen im Markdown (brechen JSON-String-Werte) - json.loads(strict=False) fuer rohe Newlines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -10,6 +10,9 @@ logger = logging.getLogger("blog.curator")
|
||||
def _extract_json(text):
|
||||
"""Extrahiert JSON aus Claude-Antworten (robust)."""
|
||||
text = text.strip()
|
||||
# Typographische Anfuehrungszeichen ersetzen (brechen JSON)
|
||||
text = text.replace("„", "'").replace("“", "'").replace("”", "'")
|
||||
text = text.replace("«", "'").replace("»", "'")
|
||||
# 1. Direktes Parsen versuchen
|
||||
try:
|
||||
return json.loads(text, strict=False)
|
||||
@@ -20,8 +23,9 @@ def _extract_json(text):
|
||||
start = text.find(open_c)
|
||||
end = text.rfind(close_c)
|
||||
if start != -1 and end > start:
|
||||
candidate = text[start:end+1]
|
||||
try:
|
||||
return json.loads(text[start:end+1], strict=False)
|
||||
return json.loads(candidate, strict=False)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
raise json.JSONDecodeError("Kein gueltiges JSON gefunden", text, 0)
|
||||
|
||||
@@ -10,6 +10,9 @@ logger = logging.getLogger("blog.writer")
|
||||
def _extract_json(text):
|
||||
"""Extrahiert JSON aus Claude-Antworten (robust)."""
|
||||
text = text.strip()
|
||||
# Typographische Anfuehrungszeichen ersetzen (brechen JSON)
|
||||
text = text.replace("„", "'").replace("“", "'").replace("”", "'")
|
||||
text = text.replace("«", "'").replace("»", "'")
|
||||
# 1. Direktes Parsen versuchen
|
||||
try:
|
||||
return json.loads(text, strict=False)
|
||||
@@ -20,10 +23,11 @@ def _extract_json(text):
|
||||
start = text.find(open_c)
|
||||
end = text.rfind(close_c)
|
||||
if start != -1 and end > start:
|
||||
candidate = text[start:end+1]
|
||||
try:
|
||||
return json.loads(text[start:end+1], strict=False)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return json.loads(candidate, strict=False)
|
||||
except json.JSONDecodeError as e:
|
||||
import logging; logging.getLogger("blog.writer.json").warning(f"Parse at {open_c}..{close_c}: {e.msg} at pos {e.pos}, ctx: {repr(candidate[max(0,e.pos-40):e.pos+40])}")
|
||||
raise json.JSONDecodeError("Kein gueltiges JSON gefunden", text, 0)
|
||||
|
||||
DB_PATH = "/mnt/gitea/osint-data/osint.db"
|
||||
@@ -115,10 +119,11 @@ REGELN FÜR DEN ARTIKEL:
|
||||
2. Erzählerischer Fließtext mit Kontext und Einordnung
|
||||
3. Verwende echte Umlaute (ü, ä, ö, ß)
|
||||
4. Markdown-Format: ## für Zwischenüberschriften, **fett** für Betonung
|
||||
5. 800-1500 Wörter, gut strukturiert
|
||||
6. Nenne und verlinke Quellen im Text wo möglich
|
||||
7. Meta-Description: 1 Satz, max 155 Zeichen, für Suchmaschinen
|
||||
8. Am Ende: Einordnung/Ausblick (was bedeutet das?)
|
||||
5. WICHTIG: Verwende im Markdown-Text KEINE doppelten Anführungszeichen ("). Nutze stattdessen einfache Anführungszeichen (') oder *kursiv*. Doppelte Anführungszeichen brechen das JSON-Format.
|
||||
6. 800-1500 Wörter, gut strukturiert
|
||||
7. Nenne und verlinke Quellen im Text wo möglich
|
||||
8. Meta-Description: 1 Satz, max 155 Zeichen, für Suchmaschinen
|
||||
9. Am Ende: Einordnung/Ausblick (was bedeutet das?)
|
||||
|
||||
Antworte als JSON:
|
||||
{{
|
||||
@@ -153,5 +158,5 @@ Falls das Thema einen geographischen Bezug hat, fülle geo_data:
|
||||
logger.info(f"Writer: Artikel '{article['title']}' geschrieben (${usage.cost_usd:.4f})")
|
||||
return article
|
||||
except (json.JSONDecodeError, IndexError, KeyError, TypeError) as e:
|
||||
logger.error(f"Writer JSON-Parse-Fehler: {e}\nRaw: {result[:300]}")
|
||||
logger.error(f"Writer JSON-Parse-Fehler: {e} | repr: {repr(result[:200])} | has_brace: {chr(123) in result}")
|
||||
return None
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren