|
|
|
|
@@ -422,15 +422,21 @@ async def _generate_sections(
|
|
|
|
|
"Wähle, was diesem Zweck dient — lass weg, was dafür nicht nötig ist."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Subbausteine je Baustein (Sidecar) — früh geladen: „Guide" wählt darüber aus
|
|
|
|
|
# (Bausteine mit ≥1 relevantem Sub) und filtert später Rand-Subs. Fehlt sie → {} (Fallback).
|
|
|
|
|
# Subbausteine je Baustein (Sidecar) — früh geladen: steuert Auswahl + Sub-Filter je Format.
|
|
|
|
|
# Fehlt sie → {} (Fallback: Guide nimmt alles).
|
|
|
|
|
subs_raw = _load_subbausteine(topic)
|
|
|
|
|
|
|
|
|
|
# Schritt 0: Auswahl. „Guide" ist deterministisch — alle Bausteine mit ≥1
|
|
|
|
|
# relevantem Subbaustein. Fallback (keine Relevanz-Daten): alle Bausteine.
|
|
|
|
|
if format_name == "Guide":
|
|
|
|
|
auswahl = [num for num in entries
|
|
|
|
|
if any(s.get("relevanz") == "relevant" for s in subs_raw.get(_titel(entries[num]), []))]
|
|
|
|
|
def _hat_relevanz(num, art):
|
|
|
|
|
return any(isinstance(s, dict) and s.get("relevanz") == art for s in subs_raw.get(_titel(entries[num]), []))
|
|
|
|
|
|
|
|
|
|
# Schritt 0: Auswahl. Deterministisch je Format (Roadmap hat einen eigenen Weg):
|
|
|
|
|
# Guide=relevante Bausteine · FullGuide=alle · Rest=Rand-Bausteine.
|
|
|
|
|
if format_name == "FullGuide":
|
|
|
|
|
auswahl = list(entries)
|
|
|
|
|
elif format_name == "Rest":
|
|
|
|
|
auswahl = [num for num in entries if _hat_relevanz(num, "rand")]
|
|
|
|
|
elif format_name == "Guide":
|
|
|
|
|
auswahl = [num for num in entries if _hat_relevanz(num, "relevant")]
|
|
|
|
|
if not auswahl:
|
|
|
|
|
_log(topic, "Guide: keine Relevanz-Daten — alle Bausteine genommen")
|
|
|
|
|
auswahl = list(entries)
|
|
|
|
|
@@ -442,6 +448,9 @@ async def _generate_sections(
|
|
|
|
|
)
|
|
|
|
|
if auswahl is None:
|
|
|
|
|
return None
|
|
|
|
|
if not auswahl:
|
|
|
|
|
await _fail(guide_id, "Keine passenden Bausteine für dieses Format")
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
sel_entries = {num: entries[num] for num in auswahl}
|
|
|
|
|
soll = len(sel_entries)
|
|
|
|
|
@@ -523,13 +532,14 @@ async def _generate_sections(
|
|
|
|
|
# dieselbe Aufteilung: 1 Agent je ~30 Bausteine (gedeckelt).
|
|
|
|
|
total_sections = sum(len(c["nums"]) for c in plan)
|
|
|
|
|
chunks = _split_chunks(plan, min(WRITER_MAX, max(1, math.ceil(total_sections / WRITER_SECTIONS))))
|
|
|
|
|
# Subbausteine je Baustein. Rand-Subbausteine fliegen aus dem Guide (Fokus auf
|
|
|
|
|
# Relevantes). Subs ohne Relevanz-Feld (Alt-Themen) bleiben erhalten.
|
|
|
|
|
# Fehlt die Sidecar → leer → Inhalte/Writer laufen auf Baustein-Granularität.
|
|
|
|
|
subs_by_titel = {
|
|
|
|
|
t: [s for s in subs if s.get("relevanz") != "rand"]
|
|
|
|
|
for t, subs in subs_raw.items()
|
|
|
|
|
}
|
|
|
|
|
# Subbausteine je Baustein, je Format gefiltert: Guide=relevant · FullGuide=alle · Rest=Rand.
|
|
|
|
|
# Subs ohne Relevanz-Feld (Alt-Themen) zählen als „nicht Rand" (→ Guide/FullGuide).
|
|
|
|
|
if format_name == "FullGuide":
|
|
|
|
|
subs_by_titel = {t: list(subs) for t, subs in subs_raw.items()}
|
|
|
|
|
elif format_name == "Rest":
|
|
|
|
|
subs_by_titel = {t: [s for s in subs if s.get("relevanz") == "rand"] for t, subs in subs_raw.items()}
|
|
|
|
|
else: # Guide
|
|
|
|
|
subs_by_titel = {t: [s for s in subs if s.get("relevanz") != "rand"] for t, subs in subs_raw.items()}
|
|
|
|
|
subs_by_titel = {t: subs for t, subs in subs_by_titel.items() if subs}
|
|
|
|
|
zuteilungen = [_zuteilung_subs(chunk, entries, subs_by_titel) for chunk in chunks]
|
|
|
|
|
chunk_sizes = [sum(len(c["nums"]) for c in chunk) for chunk in chunks]
|
|
|
|
|
@@ -784,12 +794,22 @@ async def _generate_sections(
|
|
|
|
|
break
|
|
|
|
|
scope = [[num for num in nums if num in ersetzt] for nums in chunk_nums]
|
|
|
|
|
|
|
|
|
|
# Prüfbar = Format hat Prüfung UND Baustein hat ≥1 relevanten Subbaustein.
|
|
|
|
|
# Guide ist immer prüfbar (auch ohne Relevanz-Daten, Fallback = alles).
|
|
|
|
|
def _pruefbar(num):
|
|
|
|
|
if format_name == "Guide":
|
|
|
|
|
return True
|
|
|
|
|
if format_name == "FullGuide":
|
|
|
|
|
return any(isinstance(s, dict) and s.get("relevanz") == "relevant"
|
|
|
|
|
for s in subs_raw.get(_titel(entries[num]), []))
|
|
|
|
|
return False # Rest u.a. → reine Lese-Sections
|
|
|
|
|
|
|
|
|
|
await _set_progress(guide_id, "Setze zusammen…")
|
|
|
|
|
chapters: list[dict] = []
|
|
|
|
|
for ch in plan:
|
|
|
|
|
sections = [
|
|
|
|
|
{"num": num, "title": _titel(entries[num]), "md": by_num[num]["md"],
|
|
|
|
|
"kompakt": by_num[num].get("kompakt", "")}
|
|
|
|
|
"kompakt": by_num[num].get("kompakt", ""), "pruefbar": _pruefbar(num)}
|
|
|
|
|
for num in ch["nums"] if num in by_num
|
|
|
|
|
]
|
|
|
|
|
if sections:
|
|
|
|
|
|