feat: Aufgaben mit Abbildungen (docling-Markdown), mit Gegenprobe beim Ablesen
Eingebettete Base64-Bilder und Bilddateien werden aus dem Aufgabentext gelöst und nur der Verstehensstufe als Bild übergeben; sie überträgt jede Abbildung in Text. Eine zweite, unabhängige Lesung wird Zahl für Zahl verglichen (bei Abweichung entscheidet eine dritte, sonst reliable=False). Alle weiteren Stufen rechnen mit der Übertragung, der Report zeigt Original und Übertragung nebeneinander. LLM_MODEL_UNDERSTANDING wählt das Bildmodell. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
915c79c1c8
commit
b07dd16143
1 changed files with 484 additions and 36 deletions
|
|
@ -4,6 +4,7 @@ error -> löst in run_pipeline eine Korrekturrunde aus
|
|||
warning -> wird nur berichtet (Heuristiken mit möglichen Fehlalarmen)
|
||||
"""
|
||||
import re
|
||||
from collections import Counter
|
||||
from typing import Iterable, List, Set
|
||||
|
||||
from core.model_schema import (
|
||||
|
|
@ -205,6 +206,44 @@ def check_understanding(understanding, task: str) -> List[CheckIssue]:
|
|||
return issues
|
||||
|
||||
|
||||
def _numbers_multiset(text: str) -> Counter:
|
||||
"""Zahlen eines Textes mit Häufigkeit – eine Kante mit Bewertung 3 zweimal ist nicht dasselbe wie einmal."""
|
||||
zaehler = Counter()
|
||||
for roh in NUMBER_PATTERN.findall(text or ""):
|
||||
try:
|
||||
zaehler[normalize_number(roh)] += 1
|
||||
except ValueError:
|
||||
continue
|
||||
return zaehler
|
||||
|
||||
|
||||
def check_figure_readings(first, second) -> List[CheckIssue]:
|
||||
"""Zwei unabhängige Übertragungen derselben Abbildungen vergleichen – Zahl für Zahl, ohne LLM.
|
||||
|
||||
Ein Bildmodell kann eine Pfeilbewertung dem falschen Pfeil zuordnen oder eine Ziffer verlesen; eine einzige
|
||||
Lesung wäre dann ungeprüft die Datengrundlage jeder weiteren Stufe. Verglichen werden die Zahlen je Abbildung
|
||||
samt Häufigkeit. Richtungsfehler bei gleichen Zahlen fängt das nicht – dafür steht das Original im Report.
|
||||
"""
|
||||
issues = []
|
||||
erste = {f.id: f for f in first}
|
||||
zweite = {f.id: f for f in second}
|
||||
for kennung in sorted(set(erste) | set(zweite)):
|
||||
if kennung not in erste or kennung not in zweite:
|
||||
issues.append(CheckIssue(severity=CheckSeverity.ERROR, code="FIGURE_READINGS_DIFFER",
|
||||
message=f"{kennung} wurde nur in einer von zwei Lesungen übertragen."))
|
||||
continue
|
||||
a = _numbers_multiset(erste[kennung].transcription)
|
||||
b = _numbers_multiset(zweite[kennung].transcription)
|
||||
if a != b:
|
||||
nur_a = sorted((a - b).elements(), key=float)
|
||||
nur_b = sorted((b - a).elements(), key=float)
|
||||
issues.append(CheckIssue(
|
||||
severity=CheckSeverity.ERROR, code="FIGURE_READINGS_DIFFER",
|
||||
message=f"{kennung} uneinheitlich gelesen – nur in Lesung 1: {', '.join(nur_a) or '–'}; "
|
||||
f"nur in Lesung 2: {', '.join(nur_b) or '–'}."))
|
||||
return issues
|
||||
|
||||
|
||||
def _strip_scripts(text: str) -> str:
|
||||
"""Entfernt Indizes/Exponenten: x_{i,j} -> x, C^{prod}_{p} -> C, x_1 -> x."""
|
||||
text = text.replace(r"\_", "_")
|
||||
|
|
|
|||
Loading…
Reference in a new issue