This commit is contained in:
root
2026-06-07 05:01:30 +00:00
parent 656b5bb621
commit fce82fbd16
2 changed files with 13 additions and 12 deletions

View File

@@ -22,11 +22,11 @@ TIMEOUTS = {
"onepager_verify": (300, 0), "onepager_verify": (300, 0),
} }
# Auswahl-Auftrag je Format: (Mindest-Anteil, Mindestanzahl, Zweck). # Auswahl-Auftrag je Format: (Mindest-Anteil, Maximal-Anteil, Mindestanzahl, Zweck).
FORMAT_ANTEIL = { FORMAT_ANTEIL = {
"MiniGuide": (0.05, 8, "einen kompakten Anfänger-Guide — der schnelle Einstieg ins Thema"), "MiniGuide": (0.05, 0.10, 8, "einen kompakten Anfänger-Guide — der schnelle Einstieg ins Thema"),
"Guide": (0.33, 20, "einen ausführlichen Anfänger-Guide — ein solides Fundament im Thema"), "Guide": (0.25, 0.35, 20, "einen ausführlichen Anfänger-Guide — ein solides Fundament im Thema"),
"FullGuide": (0.90, 0, "einen Komplett-Guide — das ganze Thema"), "FullGuide": (0.90, 1.00, 0, "einen Komplett-Guide — das ganze Thema"),
} }
# Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden. # Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden.

View File

@@ -508,13 +508,13 @@ async def generate_bausteine(topic: str, instructions: str = "", provider: str =
# Kleine Pakete vermeiden Lazy-Output bei langen Listen und begrenzen den Schaden # Kleine Pakete vermeiden Lazy-Output bei langen Listen und begrenzen den Schaden
# eines fehlgeschlagenen Writers. # eines fehlgeschlagenen Writers.
WRITER_SECTIONS = 30 WRITER_SECTIONS = 30
WRITER_MAX = 10 WRITER_MAX = 20
def _resolve_gliederung(data, entries: dict[int, str], soll: int) -> list[dict] | None: def _resolve_gliederung(data, entries: dict[int, str], soll_min: int, soll_max: int) -> list[dict] | None:
"""{"kapitel": [{"titel", "bausteine": [Titel]}]} → [{"title", "nums"}]. """{"kapitel": [{"titel", "bausteine": [Titel]}]} → [{"title", "nums"}].
`soll` = Mindest-Anzahl gewählter Bausteine (mit kleiner Toleranz). `soll_min`/`soll_max` = erlaubte Spanne gewählter Bausteine (mit kleiner Toleranz).
""" """
if not isinstance(data, dict) or not isinstance(data.get("kapitel"), list): if not isinstance(data, dict) or not isinstance(data.get("kapitel"), list):
return None return None
@@ -540,7 +540,7 @@ def _resolve_gliederung(data, entries: dict[int, str], soll: int) -> list[dict]
return None return None
if (total - unknown) / total < 0.85: if (total - unknown) / total < 0.85:
return None return None
if len(seen) < 0.9 * soll: if len(seen) < 0.9 * soll_min or len(seen) > 1.1 * soll_max:
return None return None
return chapters return chapters
@@ -719,10 +719,11 @@ async def _generate_sections(
spec = (TEMPLATES_DIR / "Format" / "Section.md").read_text(encoding="utf-8") spec = (TEMPLATES_DIR / "Format" / "Section.md").read_text(encoding="utf-8")
bausteine_liste = "\n".join(f"- {t}" for t in entries.values()) bausteine_liste = "\n".join(f"- {t}" for t in entries.values())
n = len(entries) n = len(entries)
anteil, minimum, zweck = FORMAT_ANTEIL[format_name] anteil_min, anteil_max, minimum, zweck = FORMAT_ANTEIL[format_name]
k = min(n, max(minimum, math.ceil(anteil * n))) k_min = min(n, max(minimum, math.ceil(anteil_min * n)))
k_max = min(n, max(k_min, math.floor(anteil_max * n)))
auswahl_auftrag = ( auswahl_auftrag = (
f"Wähle MINDESTENS {k} der Bausteine und baue daraus {zweck}. " f"Wähle MINDESTENS {k_min} und HÖCHSTENS {k_max} der Bausteine und baue daraus {zweck}. "
"Wähle, was diesem Zweck dient — lass weg, was dafür nicht nötig ist." "Wähle, was diesem Zweck dient — lass weg, was dafür nicht nötig ist."
) )
@@ -738,7 +739,7 @@ async def _generate_sections(
auswahl_auftrag=auswahl_auftrag, out_path=plan_path, extra=_extra(instructions), auswahl_auftrag=auswahl_auftrag, out_path=plan_path, extra=_extra(instructions),
), ),
"role": "guide", "capabilities": "files", "role": "guide", "capabilities": "files",
"payload": (lambda result: _resolve_gliederung(_json_datei(plan_path), entries, k)), "payload": (lambda result: _resolve_gliederung(_json_datei(plan_path), entries, k_min, k_max)),
}] }]
res = await _race(topic, "Gliederung", slots, 1, _timeout("plan", n), provider, cancelled=is_cancelled) res = await _race(topic, "Gliederung", slots, 1, _timeout("plan", n), provider, cancelled=is_cancelled)
if is_cancelled(): if is_cancelled():