update
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
VERSCHIEDENEN Kapiteln mit Jaccard ≥0.6 → 2er-Panel entscheidet „redundant vs.
|
||||
didaktisch gewollt" (Recap ist keine Dopplung). Befunde behebt der Fix-Knoten
|
||||
per Ein-Satz-Refresher + Anker-Link."""
|
||||
from . import config, db, engine, llm, panels, textkit
|
||||
from . import config, db, engine, graph, llm, panels, textkit
|
||||
from .dedup import _signatur
|
||||
|
||||
|
||||
def kandidaten_paare(topic: str) -> list[dict]:
|
||||
@@ -32,8 +33,14 @@ def kandidaten_paare(topic: str) -> list[dict]:
|
||||
>= config.REDUNDANZ_JACCARD
|
||||
# Shingle-Kanal: identische Wort-Folge in längeren Sätzen —
|
||||
# Jaccard übersieht sie, wenn der Restsatz verschieden ist
|
||||
if jaccard_treffer or (shingles(a["satz"]) & shingles(b["satz"])):
|
||||
paare.append({"a": a, "b": b})
|
||||
wortgleich = bool(shingles(a["satz"]) & shingles(b["satz"]))
|
||||
# Fakten-Kanal: dieselbe Studie/Zahl in Paraphrase teilt Zahlen +
|
||||
# Eigennamen (Audit: „Ariga & Lleras 2011" stand 3× im Guide,
|
||||
# Wort-Jaccard nur 0.21)
|
||||
fakten = len(_signatur(a["satz"]) & _signatur(b["satz"])) \
|
||||
>= config.FAKTEN_SIGNATUR_MIN
|
||||
if jaccard_treffer or wortgleich or fakten:
|
||||
paare.append({"a": a, "b": b, "wortgleich": wortgleich})
|
||||
return paare
|
||||
|
||||
|
||||
@@ -43,15 +50,14 @@ async def pruefen(task: dict) -> engine.Ergebnis:
|
||||
befunde = 0
|
||||
for i in range(0, len(paare), config.DEDUP_PAARE_PRO_CALL):
|
||||
chunk = paare[i:i + config.DEDUP_PAARE_PRO_CALL]
|
||||
liste = "\n\n".join(
|
||||
f"PAAR {j + 1}:\nKapitel A: {p['a']['satz']}\nKapitel B: {p['b']['satz']}"
|
||||
for j, p in enumerate(chunk))
|
||||
liste = textkit.paar_liste(
|
||||
[(q["a"]["satz"], q["b"]["satz"]) for q in chunk])
|
||||
|
||||
async def ruf(p, liste=liste, n=len(chunk)):
|
||||
text = await llm.call(
|
||||
run_id=task["run_id"], stufe="guide", knoten="redundanz",
|
||||
item=f"{task['item']}:c{i}:p{p}", role="judge", n=n,
|
||||
skill_namen=["richter", "deutsch-praezise", "redundanz-urteil"],
|
||||
skill_namen=graph.skills_von(task["knoten"]),
|
||||
werte={"paare": liste})
|
||||
if text is None:
|
||||
return None
|
||||
@@ -67,7 +73,11 @@ async def pruefen(task: dict) -> engine.Ergebnis:
|
||||
u = s[j + 1]
|
||||
return True if u == "redundant" else (
|
||||
False if u == "didaktisch_gewollt" else None)
|
||||
if panels.einstimmig(stimmen, config.PRUEF_PANEL, urteil):
|
||||
# Fast wörtliche Paare (gemeinsame 5-Wort-Folge) sind NIE
|
||||
# „didaktisch gewollt" — das Panel darf sie nicht freisprechen
|
||||
# (Audit: 94-Studierende-Satz stand 2× nahezu wortgleich im Text)
|
||||
if p.get("wortgleich") or panels.einstimmig(
|
||||
stimmen, config.PRUEF_PANEL, urteil):
|
||||
# Der SPÄTERE Baustein trägt den Befund (dort wird verwiesen)
|
||||
spaeter = max(p["a"], p["b"], key=lambda x: x["pos"])
|
||||
schon = db.one(
|
||||
@@ -80,4 +90,9 @@ async def pruefen(task: dict) -> engine.Ergebnis:
|
||||
item=f"baustein:{spaeter['bid']}",
|
||||
detail=spaeter["satz"][:400], runde=task["runde"])
|
||||
befunde += 1
|
||||
return engine.Ergebnis(daten={"paare": len(paare), "befunde": befunde})
|
||||
neue = []
|
||||
if not db.one("SELECT id FROM tasks WHERE topic=? AND knoten='lektorat' "
|
||||
"AND status='fertig'", task["topic"]):
|
||||
neue = [{"knoten": "lektorat", "item": f"r{task['runde']}:lektorat"}]
|
||||
return engine.Ergebnis(daten={"paare": len(paare), "befunde": befunde},
|
||||
neue_tasks=neue)
|
||||
|
||||
Reference in New Issue
Block a user