This commit is contained in:
team3
2026-07-12 20:02:13 +02:00
parent 31a42bbf1d
commit cde1721d10
23 changed files with 731 additions and 219 deletions

View File

@@ -137,14 +137,24 @@ def _luecke(prompt: str):
def _artefakt_generate(prompt: str):
ids = [int(i) for i in re.findall(r"ATOM (\d+):", prompt)]
# Form je Atom-Typ [in Klammern] wählen (wie die typgesteuerte Regel im Prompt)
paare = re.findall(r"ATOM (\d+):[^\[\n]*\[(\w+)\]", prompt)
out = []
for i in ids:
for raw, typ in paare:
i = int(raw)
out += [{"atom": i, "typ": "flashcard", "frage": f"Was besagt Atom {i}?",
"antwort": "Siehe Beleg — deterministische Fake-Antwort."},
{"atom": i, "typ": "flashcard", "frage": f"Wozu dient Atom {i}?",
"antwort": "Zum Lernen — deterministische Fake-Antwort."},
{"atom": i, "typ": "beispiel", "text": f"Beispiel zu Atom {i}: Schritt 1, Schritt 2."}]
"antwort": "Zum Lernen — deterministische Fake-Antwort."}]
if typ == "verfahren":
out.append({"atom": i, "typ": "beispiel", "form": "code",
"sprache": "python", "code": f"print({i} + 1)"})
elif typ == "begriff":
out.append({"atom": i, "typ": "beispiel", "form": "tabelle",
"tabelle": f"| Fall | Ergebnis |\n|---|---|\n| Atom {i} | passt |"})
else: # aussage → Text-Beispiel
out.append({"atom": i, "typ": "beispiel", "form": "text",
"text": f"Beispiel zu Atom {i}: Schritt 1, Schritt 2."})
return out
@@ -196,24 +206,40 @@ def _zyklus(prompt: str):
return {"von": int(m.group(1)), "zu": int(m.group(2))} if m else {}
def _braucht_aufloesung(prompt: str):
# je ANGABE den Kandidaten mit den meisten geteilten Tokens (Substring, ≥4 Zeichen)
# wählen, sonst null — spiegelt den Substring-Prefilter der Auflösung.
def toks(s):
return {t for t in re.findall(r"\w+", s.lower()) if len(t) >= 4}
out = []
bloecke = re.split(r"ANGABE (\d+):", prompt)[1:]
for i in range(0, len(bloecke), 2):
n, body = int(bloecke[i]), bloecke[i + 1]
mp = re.search(r"Voraussetzung „([^“]+)", body)
ph = mp.group(1) if mp else ""
pl, pt = ph.lower(), toks(ph)
ranked = []
for kid, ktitel in re.findall(r"- atom (\d+): (.+?) —", body):
geteilt = {t for t in toks(ktitel) if t in pl} | {t for t in pt if t in ktitel.lower()}
if geteilt:
ranked.append((-len(geteilt), len(ktitel), int(kid)))
ranked.sort()
out.append({"phrase": n, "atom": ranked[0][2] if ranked else None})
return out
def _writer(prompt: str):
ziel = re.search(r"Lernziel: (.+)", prompt)
marker = re.findall(r"MARKER \(exakt so übernehmen\): (<!-- atom: \d+ \| (.+?) -->)",
prompt)
defs = re.findall(r"Definition: (.+)", prompt)
fragen = re.findall(r"^- (.+\?)$", prompt, re.MULTILINE)[:2]
lo = int(re.search(r"hat (\d+)", prompt).group(1)) if re.search(r"hat (\d+)", prompt) else 40
absaetze = [f"Ziel dieser Einheit: {ziel.group(1) if ziel else 'Lernen'}. Formal: $n \\ge 0$."]
fuellung = "Daran anknüpfend gehen wir das Schritt für Schritt am Beispiel durch. " * 5
diag = re.findall(r"(<!-- diagramm: \d+ -->)", prompt) # angebotene Diagramme
for n, ((mk, titel), d) in enumerate(zip(marker, defs)):
block = f"#### {titel} verstehen\n{mk}\n{d} {fuellung}"
if n == 0 and diag: # erstes Diagramm beim ersten Absatz platzieren
block += f"\n\n{diag[0]}"
absaetze.append(block)
absaetze.append("**Kernpunkte:**\n" + "\n".join(f"- {t} sitzt" for _, t in marker))
if fragen:
absaetze.append("**Prüfe dich:**\n" + "\n".join(f"- {f}" for f in fragen))
for (mk, titel), d in zip(marker, defs):
# Beispiel-/Diagramm-Marker setzt jetzt _marker_platzieren deterministisch,
# nicht mehr der Writer.
absaetze.append(f"#### {titel} verstehen\n{mk}\n{d} {fuellung}")
lang = "\n\n".join(absaetze)
while len(lang.split()) < lo:
lang += "\nNoch ein Übungssatz zur Vertiefung des Gelernten."
@@ -222,8 +248,8 @@ def _writer(prompt: str):
def _diagramm_plan(prompt: str):
# deterministisch: die Fake-Welt braucht kein LLM-Diagramm (DAG-Pfad wird
# getestet). Unit-Tests für den LLM-Zweig monkeypatchen diesen Handler.
# deterministisch: die Fake-Welt braucht kein Diagramm. Unit-Tests für den
# LLM-Diagramm-Zweig monkeypatchen diesen Handler auf noetig=True.
return {"noetig": False, "typ": ""}
@@ -269,7 +295,7 @@ _HANDLER = {
"Artefakt-Generate": _artefakt_generate, "Artefakt-Verify": _artefakt_verify,
"Artefakt-Fix": _artefakt_fix, "Lernziele": _lernziele, "Kapitel-Intro": _kapitel_intro,
"Kapitel-Schnitt": _kapitel_schnitt, "Level-Kalibrierung": _level_kalibrierung,
"Kanten-Zyklus": _zyklus,
"Kanten-Zyklus": _zyklus, "Braucht-Aufloesung": _braucht_aufloesung,
"Guide-Writer": _writer, "Guide-Pruefer": _pruefer, "Guide-Fix": _fix,
"QA-Guide-Falsch": _qa_falsch, "QA-Guide-Falsch-Check": _qa_falsch_check,
"Diagramm-Plan": _diagramm_plan, "Diagramm-Spec": _diagramm_spec,