50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
"""Toleranter JSON-Parser für KI-Output — als Text oder aus Dateien.
|
|
|
|
Verkraftet Code-Fences, Drumherum-Text und unescapte Anführungszeichen in
|
|
Strings (z. B. MiniMax: "Titel „p" geändert"): das letzte `"` vor der
|
|
Fehlerstelle wird escapet und erneut geparst.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import re
|
|
from pathlib import Path
|
|
|
|
log = logging.getLogger("creator.jsonio")
|
|
|
|
|
|
def parse_json_text(text: str):
|
|
"""Parst JSON aus KI-Output; None bei nicht reparierbarem Input."""
|
|
text = re.sub(r"^```(?:json)?\s*|\s*```$", "", (text or "").strip())
|
|
start, end = text.find("{"), text.rfind("}")
|
|
if start == -1 or end <= start:
|
|
return None
|
|
candidate = text[start:end + 1]
|
|
for _ in range(20):
|
|
try:
|
|
return json.loads(candidate)
|
|
except json.JSONDecodeError as e:
|
|
if not e.msg.startswith(("Expecting ',' delimiter", "Expecting ':' delimiter")):
|
|
return None
|
|
q = candidate.rfind('"', 0, e.pos)
|
|
if q <= 0:
|
|
return None
|
|
candidate = candidate[:q] + '\\"' + candidate[q + 1:]
|
|
except Exception:
|
|
return None
|
|
return None
|
|
|
|
|
|
def read_json_file(path: Path):
|
|
"""Liest eine JSON-Datei mit derselben Toleranz; None bei fehlend/ungültig."""
|
|
if not path.exists():
|
|
return None
|
|
try:
|
|
data = parse_json_text(path.read_text(encoding="utf-8"))
|
|
except Exception as e:
|
|
log.debug("JSON-Datei nicht lesbar: %s (%s)", path, e)
|
|
return None
|
|
if data is None:
|
|
log.debug("JSON-Datei ungültig: %s", path)
|
|
return data
|