This commit is contained in:
Team3
2026-09-27 21:36:33 +02:00
commit 498fe2220a
34 changed files with 3608 additions and 0 deletions

52
backend/gliederung.py Normal file
View File

@@ -0,0 +1,52 @@
"""Parser für buch/GLIEDERUNG.md (Format siehe prompts/gliederung.md)."""
import re
KAPITEL_RE = re.compile(r"^\*\*Kapitel (\d+) – (.+?)\*\* \(`([0-9]{2}-[a-z0-9-]+\.md)`\)\s*$")
TEIL_RE = re.compile(r"^## (Teil .+?)\s*$")
TITEL_RE = re.compile(r"^# Gliederung – (.+?)(?:\. (.+))?$")
def parsen(text: str) -> dict:
"""→ {"titel", "untertitel", "kapitel": [{"n","titel","datei","teil","abschnitte":[{"nr","titel"}]}], "fehler": [...]}"""
aus = {"titel": "", "untertitel": "", "kapitel": [], "fehler": []}
teil = ""
zeilen = text.splitlines()
i = 0
while i < len(zeilen):
z = zeilen[i].rstrip()
m = TITEL_RE.match(z)
if m and not aus["titel"]:
aus["titel"], aus["untertitel"] = m.group(1).strip(), (m.group(2) or "").strip()
elif TEIL_RE.match(z):
teil = TEIL_RE.match(z).group(1)
elif KAPITEL_RE.match(z):
m = KAPITEL_RE.match(z)
n = int(m.group(1))
k = {"n": n, "titel": m.group(2).strip(), "datei": m.group(3), "teil": teil, "abschnitte": []}
# nächste nicht-leere Zeile: Abschnitte
j = i + 1
while j < len(zeilen) and not zeilen[j].strip():
j += 1
if j < len(zeilen):
for teilstueck in re.split(r"\s+·\s+", zeilen[j].strip()):
am = re.match(r"^(\d+)\.(\d+)\s+(.+)$", teilstueck.strip())
if am and int(am.group(1)) == n:
k["abschnitte"].append({"nr": f"{am.group(1)}.{am.group(2)}", "titel": am.group(3).strip()})
else:
aus["fehler"].append(f"Kapitel {n}: Abschnittszeile unlesbar: „{teilstueck.strip()[:60]}“")
i = j
if not k["datei"].startswith(f"{n:02d}-"):
aus["fehler"].append(f"Kapitel {n}: Dateiname muss mit {n:02d}- beginnen ({k['datei']})")
aus["kapitel"].append(k)
elif z.startswith("**Kapitel"):
aus["fehler"].append(f"Kapitelzeile nicht im Format: „{z[:80]}“")
i += 1
for k in aus["kapitel"]:
if not 3 <= len(k["abschnitte"]) <= 6:
aus["fehler"].append(f"Kapitel {k['n']} hat {len(k['abschnitte'])} Abschnitte (3–6 verlangt)")
nummern = [k["n"] for k in aus["kapitel"]]
if nummern != list(range(1, len(nummern) + 1)):
aus["fehler"].append(f"Kapitelnummern nicht fortlaufend: {nummern}")
if not aus["kapitel"]:
aus["fehler"].append("Keine Kapitelzeile gefunden")
return aus