update
This commit is contained in:
@@ -104,7 +104,31 @@ def _marker_fehlend(text: str, atome: list[dict]) -> list[int]:
|
||||
return [a["id"] for a in atome if a["id"] not in da]
|
||||
|
||||
|
||||
def _det_auftraege(topic: str, b: dict, lang: str) -> list[str]:
|
||||
def _mathe_auftraege(text: str, wo: str) -> list[str]:
|
||||
"""Deterministische Mathe-Hygiene je Fassung: $-Parität, nackte LaTeX-Befehle,
|
||||
Klartext-Formelreste (x_i, u_{3m}, 2^(…) — aak Lauf 19: 8 Kompakt-/6
|
||||
Lang-Fassungen betroffen)."""
|
||||
auftraege = []
|
||||
for nr, absatz in enumerate(text.split("\n\n"), 1):
|
||||
if absatz.count("$") % 2: # ein einzelnes $ zieht Fließtext in die Formel
|
||||
auftraege.append(f"{wo}, Absatz {nr}: ungerade Anzahl $-Zeichen — jede"
|
||||
f" Formel braucht öffnendes UND schließendes $.")
|
||||
ohne = re.sub(r"\$\$[\s\S]*?\$\$|\$[^$\n]*\$", "", text)
|
||||
nackt = sorted(set(re.findall(
|
||||
r"\\(?:times|Sigma|Gamma|subseteq|neq|leq|geq|cup|cap|mid|forall|exists"
|
||||
r"|mathbb|frac|text|dots|ldots|quad|qquad|bar|setminus)\b", ohne)))
|
||||
if nackt: # KaTeX rendert nur innerhalb von $…$
|
||||
auftraege.append(f"{wo}: LaTeX ohne $-Delimiter ({', '.join(nackt[:5])}…):"
|
||||
f" jede Formel vollständig in $…$ bzw. $$…$$ einschließen.")
|
||||
reste = sorted(set(re.findall(
|
||||
r"\w+_\{[^}]*\}|\w+\^\{[^}]*\}|\w+\^\([^)]*\)|\b\w+_[a-z0-9]\b", ohne)))
|
||||
if reste:
|
||||
auftraege.append(f"{wo}: Formeln im Klartext ({', '.join(reste[:4])}…):"
|
||||
f" auch Indizes/Potenzen gehören in $…$ (x_i → $x_i$).")
|
||||
return auftraege
|
||||
|
||||
|
||||
def _det_auftraege(topic: str, b: dict, lang: str, kompakt: str = "") -> list[str]:
|
||||
"""Deterministische Checks vor dem Judge: Marker, Länge, Vorwärtsverweise."""
|
||||
atome = _atome_von(b["id"])
|
||||
auftraege = [f"KRITISCH: Marker für Atom {i} fehlt — exakt einfügen."
|
||||
@@ -126,18 +150,9 @@ def _det_auftraege(topic: str, b: dict, lang: str) -> list[str]:
|
||||
if "6=" in lang:
|
||||
auftraege.append("PDF-Artefakt „6=“ im Text: gemeint ist Ungleichheit —"
|
||||
" durch $\\neq$ ersetzen.")
|
||||
for nr, absatz in enumerate(lang.split("\n\n"), 1):
|
||||
if absatz.count("$") % 2: # ein einzelnes $ zieht Fließtext in die Formel
|
||||
auftraege.append(f"Absatz {nr}: ungerade Anzahl $-Zeichen — jede Formel"
|
||||
f" braucht öffnendes UND schließendes $ (Beispiel-Fehler:"
|
||||
f" „$[.“ statt „$[$.“).")
|
||||
ohne_mathe = re.sub(r"\$\$[\s\S]*?\$\$|\$[^$\n]*\$", "", lang)
|
||||
nackt = sorted(set(re.findall(
|
||||
r"\\(?:times|Sigma|Gamma|subseteq|neq|leq|geq|cup|cap|mid|forall|exists"
|
||||
r"|mathbb|frac|text|dots|ldots|quad|qquad|bar|setminus)\b", ohne_mathe)))
|
||||
if nackt: # KaTeX rendert nur innerhalb von $…$ — nackte Befehle bleiben Rohtext
|
||||
auftraege.append(f"LaTeX ohne $-Delimiter im Text ({', '.join(nackt[:5])}…):"
|
||||
f" jede Formel vollständig in $…$ bzw. $$…$$ einschließen.")
|
||||
auftraege += _mathe_auftraege(lang, "Langtext")
|
||||
if kompakt:
|
||||
auftraege += _mathe_auftraege(kompakt, "Kompakt-Fassung")
|
||||
return auftraege
|
||||
|
||||
|
||||
@@ -168,7 +183,7 @@ async def _stage_pruefer(ctx: llm.Kontext, b: dict, tag: str = "") -> str:
|
||||
sec = db.one("SELECT * FROM sections WHERE baustein_id=?", (b["id"],))
|
||||
atome = _atome_von(b["id"])
|
||||
ziel = db.one("SELECT text FROM lernziele WHERE id=?", (b["ziel_id"],)) or {"text": b["titel"]}
|
||||
auftraege = _det_auftraege(ctx.topic, b, sec["text_lang"])
|
||||
auftraege = _det_auftraege(ctx.topic, b, sec["text_lang"], sec["text_kompakt"])
|
||||
fakten = "\n\n".join(f"Atom {a['id']} ({a['titel']}): {a['definition']}\n"
|
||||
+ "\n".join(f"> {z}" for z in _zitate(a["id"])) for a in atome)
|
||||
res = await llm.call(ctx, stage=f"pruefer{tag}", template="Guide-Pruefer",
|
||||
|
||||
@@ -154,6 +154,11 @@ def state(topic: str):
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/health")
|
||||
def health():
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.get("/api/topics/{topic}/guide")
|
||||
def guide_holen(topic: str):
|
||||
# kein markdown-Feld: das Frontend rendert aus kapitel; Roh-Markdown
|
||||
|
||||
7
backend/requirements.txt
Normal file
7
backend/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
# Runtime-Abhängigkeiten (torch kommt im Dockerfile als CPU-Build davor)
|
||||
fastapi
|
||||
uvicorn[standard]
|
||||
httpx
|
||||
ftfy
|
||||
fuzzysearch
|
||||
sentence-transformers
|
||||
Reference in New Issue
Block a user