Files
creator3/backend/montage.py
2026-07-23 16:07:36 +02:00

60 lines
2.5 KiB
Python

"""Stufe 5: Guide-Zusammenbau (Kapitel + Intros + Sections) + deterministische
Abschluss-Checks: jeder Atom-Marker global genau einmal, Anker-Links auflösbar."""
import re
from . import config, db, engine
from .guide import _MARKER_RE, _slug
def guide_pfad(topic: str) -> str:
return str(config.KORPUS_DIR.parent / "guides" / f"{topic}.md")
def bauen(topic: str) -> str:
teile = []
t = db.one("SELECT COALESCE(NULLIF(titel,''), name) t FROM topics WHERE name=?",
topic)
teile.append(f"# {t['t']}\n")
for kap in db.query("SELECT * FROM kapitel WHERE topic=? ORDER BY ord", topic):
teile.append(f"\n## {kap['titel']}\n")
if kap["intro"]:
teile.append(kap["intro"] + "\n")
for b in db.query("SELECT * FROM bausteine WHERE kapitel_id=? ORDER BY ord",
kap["id"]):
sec = db.one("SELECT text FROM sections WHERE baustein_id=?", b["id"])
if sec and sec["text"]:
teile.append(f"\n### {b['titel']}\n")
teile.append(sec["text"] + "\n")
return "\n".join(teile)
@engine.worker("montage.montieren")
async def montieren(task: dict) -> engine.Ergebnis:
topic = task["topic"]
text = bauen(topic)
# Check 1: jeder aktive Atom-Marker genau einmal
marker = [int(m) for m in _MARKER_RE.findall(text)]
aktive = {a["id"] for a in db.query(
"SELECT id FROM atome WHERE topic=? AND status='aktiv' AND "
"baustein_id IS NOT NULL", topic)}
fehler = []
for a in aktive:
if marker.count(a) != 1:
fehler.append(f"Atom-Marker {a}: {marker.count(a)}x")
# Check 2: Anker-Links auflösbar (H2/H3-Slugs)
slugs = {_slug(u) for u in re.findall(r"^#{2,3}\s+(.+)$", text, re.MULTILINE)}
for link in re.findall(r"\]\(#([^)]+)\)", text):
if link not in slugs:
fehler.append(f"toter Anker-Link: #{link}")
if fehler:
for f in fehler:
db.insert("befunde", run_id=task["run_id"], stufe="montage",
knoten="montage", art="montage", item=topic, detail=f[:300])
raise RuntimeError(f"Montage-Checks: {len(fehler)} Fehler")
from .laden import _atomar_schreiben
_atomar_schreiben(guide_pfad(topic), text.encode("utf-8"))
db.update("topics", "name=?", (topic,), status="fertig")
return engine.Ergebnis(daten={"zeichen": len(text),
"kapitel": len(db.query(
"SELECT id FROM kapitel WHERE topic=?", topic))})