This commit is contained in:
team3
2026-06-15 18:51:50 +02:00
parent b592944497
commit c00580c261
5 changed files with 29 additions and 12 deletions

View File

@@ -29,7 +29,7 @@ KRITIK_MAX_RUNDEN = 2 # Generator → Kritiker → ggf. Neu, höchstens so oft
def score_berechnen(
score_vor_frage: int, gut: bool, tier2: bool, tier3: bool, absolviert: bool, gemeistert: bool,
score_vor_frage: int, gut: bool, streak: int, tier2: bool, tier3: bool, absolviert: bool, gemeistert: bool,
) -> int:
"""Neuer Score nach einer Antwort · driftfrei (immer aus dem Basis-Score gerechnet).
@@ -37,18 +37,24 @@ def score_berechnen(
- Tier 1 (tier2=False): +1 bei richtig, KEINE Strafe, Deckel NOETIG (3).
- Tier 2 (tier2, nicht tier3): +1 / 1, Boden 3, Deckel MASTERY (10).
- Tier 3 (tier3, Meisterpfad): +1 / 2, Boden 10, Deckel MEISTERN (25).
Boden vor dem Absolvieren ist 0 (sonst NOETIG — absolviert bleibt erhalten).
Ist der Baustein gemeistert, friert der Score bei MEISTERN ein (keine Punkte mehr).
Re-Bewertung nutzt denselben Basis-Score und ersetzt das vorige Ergebnis.
Streak-Bonus bei richtig: ab 3 in Folge +2 (Tier 2/3), ab 5 in Folge +3 (Tier 3).
`streak` = bisherige Folge VOR dieser Antwort; mit dieser Antwort zählt streak+1.
Boden vor dem Absolvieren ist 0; gemeistert friert bei MEISTERN ein.
Re-Bewertung nutzt denselben Basis-Score + dieselbe Streak (kein Doppelzählen).
"""
if gemeistert:
return MEISTERN
if not tier2:
delta, floor, cap = (1 if gut else 0), (NOETIG if absolviert else 0), NOETIG
floor, cap, strafe = (NOETIG if absolviert else 0), NOETIG, 0
elif not tier3:
delta, floor, cap = (1 if gut else -1), NOETIG, MASTERY
floor, cap, strafe = NOETIG, MASTERY, -1
else:
delta, floor, cap = (1 if gut else -2), MASTERY, MEISTERN
floor, cap, strafe = MASTERY, MEISTERN, -2
if gut:
s = streak + 1
delta = 3 if (tier3 and s >= 5) else (2 if (tier2 and s >= 3) else 1)
else:
delta = strafe
return max(floor, min(cap, score_vor_frage + delta))

View File

@@ -195,6 +195,7 @@ class BausteinPruefungRequest(BaseModel):
frage: str = Field(default="", max_length=2000) # aktuell geprüfte Frage (für diskussion/antwort)
letzte_bewertung: str = Field(default="", max_length=2000) # Feedback der letzten Bewertung (Kontext für diskussion)
score_vor_frage: int = 0 # Score, als die Frage gestellt wurde → driftfreies (Re-)Bewerten
streak: int = 0 # Folge korrekter Antworten VOR dieser Frage (Streak-Bonus)
tier2: bool = False # ganzer Guide absolviert (alle ≥3) → 1 bei falsch, Deckel 10
tier3: bool = False # ganzer Guide verstanden (alle ≥10) → Meisterpfad, 2 bei falsch, Deckel 25
messages: list[ChatMessage] = [] # Dialog bisher; leer = erste Frage

View File

@@ -252,7 +252,7 @@ async def baustein_pruefung_route(req: BausteinPruefungRequest):
)
if data is None:
raise HTTPException(502, "Bewertung fehlgeschlagen — bitte erneut versuchen")
score = score_berechnen(req.score_vor_frage, data["bewertung"] == "gut", req.tier2, req.tier3, absolviert, gemeistert)
score = score_berechnen(req.score_vor_frage, data["bewertung"] == "gut", req.streak, req.tier2, req.tier3, absolviert, gemeistert)
return {"feedback": data["feedback"], "bewertung": data["bewertung"], "gute_antworten": score,
"absolviert": absolviert, "verstanden": verstanden, "gemeistert": gemeistert}
@@ -265,7 +265,7 @@ async def baustein_pruefung_route(req: BausteinPruefungRequest):
# Score driftfrei aus dem Basis-Score rechnen (Re-Bewertung ersetzt das vorige Ergebnis).
score = score_berechnen(
req.score_vor_frage, data["bewertung"] == "gut", req.tier2, req.tier3, absolviert, gemeistert,
req.score_vor_frage, data["bewertung"] == "gut", req.streak, req.tier2, req.tier3, absolviert, gemeistert,
)
gute = await set_baustein_score(req.topic, req.baustein, score)
if score >= NOETIG and not absolviert: