Files
creator3/backend/belege.py
2026-07-23 16:07:36 +02:00

74 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Beleg-Fenster um Anker (300/+1200): Faktenbasis für Writer und Prüfer.
Überlappende Fenster derselben Quelle werden gemerged (creator2-Muster).
Außerdem: Facetten-Abdeckung — jede Soll-BELEG-Stelle braucht ein Atom in
der Nähe (das feine 100-%-Maß, Gutachten-Lücke „Namensherkunft")."""
from . import config, db, laden, textkit
def beleg_stellen(topic: str) -> list[dict]:
"""Alle auffindbaren Beleg-Stellen bestätigter Soll-Punkte."""
stellen = []
for s in db.query("SELECT id, belege FROM soll WHERE topic=? AND "
"status='bestaetigt' AND freispruch=''", topic):
for beleg in db.uj(s["belege"], []):
quelle = db.one("SELECT * FROM quellen WHERE id=? AND "
"status='geladen'", beleg["quelle"])
if not quelle:
continue
try:
text = laden.snapshot_lesen(quelle)
except OSError:
continue
pos = textkit.finde_zitat(text, beleg["zitat"])
if pos:
stellen.append({"soll_id": s["id"], "quelle_id": quelle["id"],
"start": pos[0], "ende": pos[1],
"zitat": beleg["zitat"][:120]})
return stellen
def unbedeckte_belege(topic: str) -> list[dict]:
"""Beleg-Stellen OHNE aktives Atom im ±EXTRAKT_FENSTER derselben Quelle."""
anker = {}
for a in db.query(
"SELECT an.quelle_id q, an.start s FROM anker an JOIN atome a ON "
"a.id=an.atom_id WHERE a.topic=? AND a.status='aktiv' AND "
"an.start>=0", topic):
anker.setdefault(a["q"], []).append(a["s"])
return [st for st in beleg_stellen(topic)
if not any(abs(s - st["start"]) <= config.EXTRAKT_FENSTER
for s in anker.get(st["quelle_id"], []))]
def abdeckung_prozent(topic: str) -> float | None:
stellen = beleg_stellen(topic)
if not stellen:
return None
frei = len(unbedeckte_belege(topic))
return round((len(stellen) - frei) / len(stellen) * 100, 1)
def fenster_fuer_atome(atom_ids: list[int]) -> str:
spans: dict[int, list[list[int]]] = {}
for aid in atom_ids:
for a in db.query("SELECT * FROM anker WHERE atom_id=? AND start>=0", aid):
von = max(0, a["start"] - config.BELEG_FENSTER_VOR)
bis = a["ende"] + config.BELEG_FENSTER_NACH
spans.setdefault(a["quelle_id"], []).append([von, bis])
teile = []
for qid, fenster in spans.items():
quelle = db.one("SELECT * FROM quellen WHERE id=?", qid)
if not quelle or quelle["status"] != "geladen":
continue
text = laden.snapshot_lesen(quelle)
fenster.sort()
gemerged = [fenster[0]]
for von, bis in fenster[1:]:
if von <= gemerged[-1][1]:
gemerged[-1][1] = max(gemerged[-1][1], bis)
else:
gemerged.append([von, bis])
for von, bis in gemerged:
teile.append(f"[Quelle: {quelle['titel'][:60]}]\n{text[von:bis]}")
return "\n\n---\n\n".join(teile)