backend-lehrer (10 files): - game/database.py (785 → 5), correction_api.py (683 → 4) - classroom_engine/antizipation.py (676 → 5) - llm_gateway schools/edu_search already done in prior batch klausur-service (12 files): - orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4) - zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5) - eh_templates.py (658 → 5), mail/api.py (651 → 5) - qdrant_service.py (638 → 5), training_api.py (625 → 4) website (6 pages): - middleware (696 → 8), mail (733 → 6), consent (628 → 8) - compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7) studio-v2 (3 components): - B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2) - dashboard-experimental (739 → 2) admin-lehrer (4 files): - uebersetzungen (769 → 4), manager (670 → 2) - ChunkBrowserQA (675 → 6), dsfa/page (674 → 5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
137 lines
4.2 KiB
Python
137 lines
4.2 KiB
Python
"""
|
|
Antizipation Engine - SuggestionGenerator.
|
|
|
|
Main class that collects signals, evaluates rules, and generates
|
|
prioritized suggestions for teachers.
|
|
"""
|
|
|
|
from typing import List, Dict, Any
|
|
|
|
from .antizipation_models import Signals, ActiveContext, ContextType
|
|
from .antizipation_collector import SignalCollector
|
|
from .antizipation_rules import RuleEngine
|
|
|
|
|
|
class SuggestionGenerator:
|
|
"""
|
|
Hauptklasse die Signale sammelt, Regeln evaluiert und
|
|
Vorschlaege generiert.
|
|
"""
|
|
|
|
def __init__(self, db_session=None):
|
|
self.collector = SignalCollector(db_session)
|
|
self.rule_engine = RuleEngine()
|
|
|
|
def generate(self, teacher_id: str, limit: int = 5) -> Dict[str, Any]:
|
|
"""
|
|
Generiert Vorschlaege fuer einen Lehrer.
|
|
|
|
Returns:
|
|
{
|
|
"active_contexts": [...],
|
|
"suggestions": [...],
|
|
"signals_summary": {...}
|
|
}
|
|
"""
|
|
# 1. Signale sammeln
|
|
signals = self.collector.collect(teacher_id)
|
|
|
|
# 2. Regeln evaluieren
|
|
all_suggestions = self.rule_engine.evaluate(signals)
|
|
|
|
# 3. Aktive Kontexte bestimmen
|
|
active_contexts = self._determine_active_contexts(signals)
|
|
|
|
# 4. Top N Vorschlaege
|
|
top_suggestions = all_suggestions[:limit]
|
|
|
|
return {
|
|
"active_contexts": [
|
|
{
|
|
"id": ctx.id,
|
|
"type": ctx.context_type.value,
|
|
"label": ctx.label,
|
|
}
|
|
for ctx in active_contexts
|
|
],
|
|
"suggestions": [
|
|
{
|
|
"id": s.id,
|
|
"title": s.title,
|
|
"description": s.description,
|
|
"tone": s.tone.value,
|
|
"badge": s.badge,
|
|
"priority": s.priority,
|
|
"icon": s.icon,
|
|
"action_url": s.action_url,
|
|
}
|
|
for s in top_suggestions
|
|
],
|
|
"signals_summary": {
|
|
"macro_phase": signals.macro_phase,
|
|
"current_week": signals.current_week,
|
|
"has_classes": signals.has_classes,
|
|
"exams_soon": len(signals.exams_in_7_days),
|
|
"routines_today": len(signals.routines_today),
|
|
},
|
|
"total_suggestions": len(all_suggestions),
|
|
}
|
|
|
|
def _determine_active_contexts(self, signals: Signals) -> List[ActiveContext]:
|
|
"""Bestimmt die aktiven Kontexte basierend auf Signalen."""
|
|
contexts = []
|
|
|
|
# Event-Kontexte
|
|
if signals.exams_in_7_days:
|
|
contexts.append(ActiveContext(
|
|
id="EXAM_IN_7_DAYS",
|
|
context_type=ContextType.EVENT_WINDOW,
|
|
label="Klausur in 7 Tagen",
|
|
))
|
|
|
|
if signals.trips_in_30_days:
|
|
contexts.append(ActiveContext(
|
|
id="TRIP_UPCOMING",
|
|
context_type=ContextType.EVENT_WINDOW,
|
|
label="Klassenfahrt geplant",
|
|
))
|
|
|
|
# Routine-Kontexte
|
|
if signals.has_conference_today:
|
|
contexts.append(ActiveContext(
|
|
id="CONFERENCE_TODAY",
|
|
context_type=ContextType.ROUTINE,
|
|
label="Konferenz heute",
|
|
))
|
|
|
|
# Zeit-Kontexte
|
|
if signals.is_weekend:
|
|
contexts.append(ActiveContext(
|
|
id="WEEKEND",
|
|
context_type=ContextType.TIME,
|
|
label="Wochenende",
|
|
))
|
|
|
|
if signals.is_before_holidays:
|
|
contexts.append(ActiveContext(
|
|
id="BEFORE_HOLIDAYS",
|
|
context_type=ContextType.TIME,
|
|
label="Vor den Ferien",
|
|
))
|
|
|
|
# Phase-Kontexte
|
|
if signals.macro_phase == "onboarding":
|
|
contexts.append(ActiveContext(
|
|
id="ONBOARDING",
|
|
context_type=ContextType.PHASE,
|
|
label="Einrichtung",
|
|
))
|
|
elif signals.macro_phase in ("halbjahresabschluss", "jahresabschluss"):
|
|
contexts.append(ActiveContext(
|
|
id="GRADE_PERIOD",
|
|
context_type=ContextType.PHASE,
|
|
label="Notenphase",
|
|
))
|
|
|
|
return contexts
|