This commit is contained in:
team3
2026-07-12 16:13:50 +02:00
parent a284e03225
commit 31a42bbf1d
48 changed files with 3625 additions and 253 deletions

View File

@@ -44,11 +44,12 @@ def _chunks(topic: str, nur_ohne: bool) -> list[list[dict]]:
atome = db.query("SELECT * FROM atome WHERE topic=? AND status NOT IN"
" ('gemerged','verworfen') ORDER BY soll_id, id", (topic,))
if nur_ohne:
# verworfene zählen nicht — sonst kann der Repair nach Verwurf nie
# nachgenerieren (Lauf 8: 5 Atome blieben dauerhaft ohne Flashcard)
# Die echte Invariante ist „≥1 lebende FLASHCARD" (Beispiel zählt nicht).
# Prüfte man „irgendein lebendes Artefakt", blockierte ein überlebendes
# Beispiel die Flashcard-Nachgenerierung dauerhaft (Lauf 8: 5 Atome ohne).
atome = [a for a in atome if not db.one(
"SELECT id FROM artefakte WHERE atom_id=? AND status!='verworfen'"
" LIMIT 1", (a["id"],))]
"SELECT id FROM artefakte WHERE atom_id=? AND typ='flashcard'"
" AND status!='verworfen' LIMIT 1", (a["id"],))]
gruppen: dict = {}
for a in atome:
gruppen.setdefault(a["soll_id"], []).append(a)
@@ -74,6 +75,12 @@ async def _generieren(ctx: llm.Kontext, chunk: list[dict]) -> None:
if _referenziert_quelle(inhalt):
log.info("Artefakt zu Atom %s nicht übernommen: referenziert die Quelle", atom_id)
continue
# Nachgenerierung (nur_ohne) läuft auch, wenn nur die Flashcard fehlt —
# dann kein zweites Beispiel anlegen (Verify-Tokens/Leitner-Dubletten).
if typ == "beispiel" and db.one(
"SELECT id FROM artefakte WHERE atom_id=? AND typ='beispiel'"
" AND status!='verworfen' LIMIT 1", (atom_id,)):
continue
db.insert("artefakte", atom_id=atom_id, typ=typ, inhalt=db.j(inhalt), status="kandidat")
@@ -133,17 +140,23 @@ async def _fixen(ctx: llm.Kontext, k: dict, maengel: list[str], atom: dict) -> N
f" {k['typ']}): {db.j(res) if res else k['inhalt']}\n"
f"Belege:\n{_zitate(k['atom_id'])}"},
erwartet=list)
ok = any(isinstance(e, dict) and e.get("artefakt") == k["id"] and e.get("ok")
for e in urteil or [])
db.update("artefakte", "id", k["id"], status="verifiziert" if ok else "verworfen")
# Verwerfen nur bei EXPLIZITEM Negativurteil. Call-Ausfall (urteil None) oder
# ausgelassene id → kein Entscheid, Kandidat bleibt (messen meldet unentschieden,
# nächste Runde prüft per Panel neu) — sonst fail-open destruktiv.
eintrag = next((e for e in (urteil or [])
if isinstance(e, dict) and e.get("artefakt") == k["id"]), None)
if eintrag is None:
return
db.update("artefakte", "id", k["id"],
status="verifiziert" if eintrag.get("ok") else "verworfen")
async def bauen(ctx: llm.Kontext) -> None:
ctx.ebene = EBENE
neu = _chunks(ctx.topic, nur_ohne=True)
await asyncio.gather(*(_generieren(ctx, c) for c in neu))
await llm.alle(_generieren(ctx, c) for c in neu)
alle = _chunks(ctx.topic, nur_ohne=False)
await asyncio.gather(*(_verifizieren(ctx, c) for c in alle))
await llm.alle(_verifizieren(ctx, c) for c in alle)
def messen(ctx: llm.Kontext) -> list[dict]: