Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
669 lines
23 KiB
Python
669 lines
23 KiB
Python
"""
|
|
Phasenspezifische Content-Vorschlaege (Feature f18 erweitert).
|
|
|
|
Generiert Aktivitaets-Vorschlaege basierend auf der aktuellen Unterrichtsphase
|
|
und optional dem Fach.
|
|
"""
|
|
|
|
from typing import List, Dict, Any, Optional
|
|
|
|
from .models import LessonPhase, LessonSession, PhaseSuggestion
|
|
|
|
|
|
# Unterstuetzte Faecher fuer fachspezifische Vorschlaege
|
|
SUPPORTED_SUBJECTS = [
|
|
"mathematik", "mathe", "math",
|
|
"deutsch",
|
|
"englisch", "english",
|
|
"biologie", "bio",
|
|
"physik",
|
|
"chemie",
|
|
"geschichte",
|
|
"geografie", "erdkunde",
|
|
"kunst",
|
|
"musik",
|
|
"sport",
|
|
"informatik",
|
|
]
|
|
|
|
|
|
# Fachspezifische Vorschlaege (Feature f18)
|
|
SUBJECT_SUGGESTIONS: Dict[str, Dict[LessonPhase, List[Dict[str, Any]]]] = {
|
|
"mathematik": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "math_warm_up",
|
|
"title": "Kopfrechnen-Challenge",
|
|
"description": "5 schnelle Kopfrechenaufgaben zum Aufwaermen",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 3,
|
|
"icon": "calculate",
|
|
"subjects": ["mathematik", "mathe"],
|
|
},
|
|
{
|
|
"id": "math_puzzle",
|
|
"title": "Mathematisches Raetsel",
|
|
"description": "Ein kniffliges Zahlenraetsel als Einstieg",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "extension",
|
|
"subjects": ["mathematik", "mathe"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "math_geogebra",
|
|
"title": "GeoGebra-Exploration",
|
|
"description": "Interaktive Visualisierung mit GeoGebra",
|
|
"activity_type": "individual_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "functions",
|
|
"subjects": ["mathematik", "mathe"],
|
|
},
|
|
{
|
|
"id": "math_peer_explain",
|
|
"title": "Rechenweg erklaeren",
|
|
"description": "Schueler erklaeren sich gegenseitig ihre Loesungswege",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 10,
|
|
"icon": "groups",
|
|
"subjects": ["mathematik", "mathe"],
|
|
},
|
|
],
|
|
LessonPhase.SICHERUNG: [
|
|
{
|
|
"id": "math_formula_card",
|
|
"title": "Formelkarte erstellen",
|
|
"description": "Wichtigste Formeln auf einer Karte festhalten",
|
|
"activity_type": "documentation",
|
|
"estimated_minutes": 5,
|
|
"icon": "note_alt",
|
|
"subjects": ["mathematik", "mathe"],
|
|
},
|
|
],
|
|
},
|
|
"deutsch": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "deutsch_wordle",
|
|
"title": "Wordle-Variante",
|
|
"description": "Wort des Tages erraten",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 4,
|
|
"icon": "abc",
|
|
"subjects": ["deutsch"],
|
|
},
|
|
{
|
|
"id": "deutsch_zitat",
|
|
"title": "Zitat-Interpretation",
|
|
"description": "Ein literarisches Zitat gemeinsam deuten",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "format_quote",
|
|
"subjects": ["deutsch"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "deutsch_textarbeit",
|
|
"title": "Textanalyse in Gruppen",
|
|
"description": "Gruppenarbeit zu verschiedenen Textabschnitten",
|
|
"activity_type": "group_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "menu_book",
|
|
"subjects": ["deutsch"],
|
|
},
|
|
{
|
|
"id": "deutsch_schreibworkshop",
|
|
"title": "Schreibwerkstatt",
|
|
"description": "Kreatives Schreiben mit Peer-Feedback",
|
|
"activity_type": "individual_work",
|
|
"estimated_minutes": 20,
|
|
"icon": "edit_note",
|
|
"subjects": ["deutsch"],
|
|
},
|
|
],
|
|
LessonPhase.SICHERUNG: [
|
|
{
|
|
"id": "deutsch_zusammenfassung",
|
|
"title": "Text-Zusammenfassung",
|
|
"description": "Die wichtigsten Punkte in 3 Saetzen formulieren",
|
|
"activity_type": "summary",
|
|
"estimated_minutes": 5,
|
|
"icon": "summarize",
|
|
"subjects": ["deutsch"],
|
|
},
|
|
],
|
|
},
|
|
"englisch": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "english_smalltalk",
|
|
"title": "Small Talk Warm-Up",
|
|
"description": "2-Minuten Gespraeche zu einem Alltagsthema",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 4,
|
|
"icon": "chat",
|
|
"subjects": ["englisch", "english"],
|
|
},
|
|
{
|
|
"id": "english_video",
|
|
"title": "Authentic Video Clip",
|
|
"description": "Kurzer Clip aus einer englischen Serie oder Nachricht",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "movie",
|
|
"subjects": ["englisch", "english"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "english_role_play",
|
|
"title": "Role Play Activity",
|
|
"description": "Dialoguebung in authentischen Situationen",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 12,
|
|
"icon": "theater_comedy",
|
|
"subjects": ["englisch", "english"],
|
|
},
|
|
{
|
|
"id": "english_reading_circle",
|
|
"title": "Reading Circle",
|
|
"description": "Gemeinsames Lesen mit verteilten Rollen",
|
|
"activity_type": "group_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "auto_stories",
|
|
"subjects": ["englisch", "english"],
|
|
},
|
|
],
|
|
},
|
|
"biologie": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "bio_nature_question",
|
|
"title": "Naturfrage",
|
|
"description": "Eine spannende Frage aus der Natur diskutieren",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "eco",
|
|
"subjects": ["biologie", "bio"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "bio_experiment",
|
|
"title": "Mini-Experiment",
|
|
"description": "Einfaches Experiment zum Thema durchfuehren",
|
|
"activity_type": "group_work",
|
|
"estimated_minutes": 20,
|
|
"icon": "science",
|
|
"subjects": ["biologie", "bio"],
|
|
},
|
|
{
|
|
"id": "bio_diagram",
|
|
"title": "Biologische Zeichnung",
|
|
"description": "Beschriftete Zeichnung eines Organismus",
|
|
"activity_type": "individual_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "draw",
|
|
"subjects": ["biologie", "bio"],
|
|
},
|
|
],
|
|
},
|
|
"physik": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "physik_demo",
|
|
"title": "Phaenomen-Demo",
|
|
"description": "Ein physikalisches Phaenomen vorfuehren",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "bolt",
|
|
"subjects": ["physik"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "physik_simulation",
|
|
"title": "PhET-Simulation",
|
|
"description": "Interaktive Simulation von phet.colorado.edu",
|
|
"activity_type": "individual_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "smart_toy",
|
|
"subjects": ["physik"],
|
|
},
|
|
{
|
|
"id": "physik_rechnung",
|
|
"title": "Physikalische Rechnung",
|
|
"description": "Rechenaufgabe mit physikalischem Kontext",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 12,
|
|
"icon": "calculate",
|
|
"subjects": ["physik"],
|
|
},
|
|
],
|
|
},
|
|
"informatik": {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "info_code_puzzle",
|
|
"title": "Code-Puzzle",
|
|
"description": "Kurzen Code-Schnipsel analysieren - was macht er?",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 4,
|
|
"icon": "code",
|
|
"subjects": ["informatik"],
|
|
},
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "info_live_coding",
|
|
"title": "Live Coding",
|
|
"description": "Gemeinsam Code entwickeln mit Erklaerungen",
|
|
"activity_type": "instruction",
|
|
"estimated_minutes": 15,
|
|
"icon": "terminal",
|
|
"subjects": ["informatik"],
|
|
},
|
|
{
|
|
"id": "info_pair_programming",
|
|
"title": "Pair Programming",
|
|
"description": "Zu zweit programmieren - Driver und Navigator",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 20,
|
|
"icon": "computer",
|
|
"subjects": ["informatik"],
|
|
},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
# Vordefinierte allgemeine Vorschlaege pro Phase
|
|
PHASE_SUGGESTIONS: Dict[LessonPhase, List[Dict[str, Any]]] = {
|
|
LessonPhase.EINSTIEG: [
|
|
{
|
|
"id": "warmup_quiz",
|
|
"title": "Kurzes Quiz zum Einstieg",
|
|
"description": "Aktivieren Sie das Vorwissen der Schueler mit 3-5 Fragen zum Thema",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 3,
|
|
"icon": "quiz"
|
|
},
|
|
{
|
|
"id": "problem_story",
|
|
"title": "Problemgeschichte erzaehlen",
|
|
"description": "Stellen Sie ein alltagsnahes Problem vor, das zum Thema fuehrt",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 5,
|
|
"icon": "auto_stories"
|
|
},
|
|
{
|
|
"id": "video_intro",
|
|
"title": "Kurzes Erklaervideo",
|
|
"description": "Zeigen Sie ein 2-3 Minuten Video zur Einfuehrung ins Thema",
|
|
"activity_type": "motivation",
|
|
"estimated_minutes": 4,
|
|
"icon": "play_circle"
|
|
},
|
|
{
|
|
"id": "brainstorming",
|
|
"title": "Brainstorming",
|
|
"description": "Sammeln Sie Ideen und Vorkenntnisse der Schueler an der Tafel",
|
|
"activity_type": "warmup",
|
|
"estimated_minutes": 5,
|
|
"icon": "psychology"
|
|
},
|
|
{
|
|
"id": "daily_challenge",
|
|
"title": "Tagesaufgabe vorstellen",
|
|
"description": "Praesentieren Sie die zentrale Frage oder Aufgabe der Stunde",
|
|
"activity_type": "problem_introduction",
|
|
"estimated_minutes": 3,
|
|
"icon": "flag"
|
|
}
|
|
],
|
|
LessonPhase.ERARBEITUNG: [
|
|
{
|
|
"id": "think_pair_share",
|
|
"title": "Think-Pair-Share",
|
|
"description": "Schueler denken erst einzeln nach, tauschen sich dann zu zweit aus und praesentieren im Plenum",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 10,
|
|
"icon": "groups"
|
|
},
|
|
{
|
|
"id": "worksheet_digital",
|
|
"title": "Digitales Arbeitsblatt",
|
|
"description": "Schueler bearbeiten ein interaktives Arbeitsblatt am Tablet oder Computer",
|
|
"activity_type": "individual_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "description"
|
|
},
|
|
{
|
|
"id": "station_learning",
|
|
"title": "Stationenlernen",
|
|
"description": "Verschiedene Stationen mit unterschiedlichen Aufgaben und Materialien",
|
|
"activity_type": "group_work",
|
|
"estimated_minutes": 20,
|
|
"icon": "hub"
|
|
},
|
|
{
|
|
"id": "expert_puzzle",
|
|
"title": "Expertenrunde (Jigsaw)",
|
|
"description": "Schueler werden Experten fuer ein Teilthema und lehren es anderen",
|
|
"activity_type": "group_work",
|
|
"estimated_minutes": 15,
|
|
"icon": "extension"
|
|
},
|
|
{
|
|
"id": "guided_instruction",
|
|
"title": "Geleitete Instruktion",
|
|
"description": "Schrittweise Erklaerung mit Uebungsphasen zwischendurch",
|
|
"activity_type": "instruction",
|
|
"estimated_minutes": 12,
|
|
"icon": "school"
|
|
},
|
|
{
|
|
"id": "pair_programming",
|
|
"title": "Partnerarbeit",
|
|
"description": "Zwei Schueler loesen gemeinsam eine Aufgabe",
|
|
"activity_type": "partner_work",
|
|
"estimated_minutes": 10,
|
|
"icon": "people"
|
|
}
|
|
],
|
|
LessonPhase.SICHERUNG: [
|
|
{
|
|
"id": "mindmap_class",
|
|
"title": "Gemeinsame Mindmap",
|
|
"description": "Ergebnisse als Mindmap an der Tafel oder digital sammeln und strukturieren",
|
|
"activity_type": "visualization",
|
|
"estimated_minutes": 8,
|
|
"icon": "account_tree"
|
|
},
|
|
{
|
|
"id": "exit_ticket",
|
|
"title": "Exit Ticket",
|
|
"description": "Schueler notieren 3 Dinge die sie gelernt haben und 1 offene Frage",
|
|
"activity_type": "summary",
|
|
"estimated_minutes": 5,
|
|
"icon": "sticky_note_2"
|
|
},
|
|
{
|
|
"id": "gallery_walk",
|
|
"title": "Galerie-Rundgang",
|
|
"description": "Schueler praesentieren ihre Ergebnisse und geben sich Feedback",
|
|
"activity_type": "presentation",
|
|
"estimated_minutes": 10,
|
|
"icon": "photo_library"
|
|
},
|
|
{
|
|
"id": "key_points",
|
|
"title": "Kernpunkte zusammenfassen",
|
|
"description": "Gemeinsam die wichtigsten Erkenntnisse der Stunde formulieren",
|
|
"activity_type": "summary",
|
|
"estimated_minutes": 5,
|
|
"icon": "format_list_bulleted"
|
|
},
|
|
{
|
|
"id": "quick_check",
|
|
"title": "Schneller Wissenscheck",
|
|
"description": "5 kurze Fragen zur Ueberpruefung des Verstaendnisses",
|
|
"activity_type": "documentation",
|
|
"estimated_minutes": 5,
|
|
"icon": "fact_check"
|
|
}
|
|
],
|
|
LessonPhase.TRANSFER: [
|
|
{
|
|
"id": "real_world_example",
|
|
"title": "Alltagsbeispiele finden",
|
|
"description": "Schueler suchen Beispiele aus ihrem Alltag, wo das Gelernte vorkommt",
|
|
"activity_type": "application",
|
|
"estimated_minutes": 5,
|
|
"icon": "public"
|
|
},
|
|
{
|
|
"id": "challenge_task",
|
|
"title": "Knobelaufgabe",
|
|
"description": "Eine anspruchsvollere Aufgabe fuer schnelle Schueler oder als Bonus",
|
|
"activity_type": "differentiation",
|
|
"estimated_minutes": 7,
|
|
"icon": "psychology"
|
|
},
|
|
{
|
|
"id": "creative_application",
|
|
"title": "Kreative Anwendung",
|
|
"description": "Schueler wenden das Gelernte in einem kreativen Projekt an",
|
|
"activity_type": "application",
|
|
"estimated_minutes": 10,
|
|
"icon": "palette"
|
|
},
|
|
{
|
|
"id": "peer_teaching",
|
|
"title": "Peer-Teaching",
|
|
"description": "Schueler erklaeren sich gegenseitig das Gelernte",
|
|
"activity_type": "real_world_connection",
|
|
"estimated_minutes": 5,
|
|
"icon": "supervisor_account"
|
|
}
|
|
],
|
|
LessonPhase.REFLEXION: [
|
|
{
|
|
"id": "thumbs_feedback",
|
|
"title": "Daumen-Feedback",
|
|
"description": "Schnelle Stimmungsabfrage: Daumen hoch/mitte/runter",
|
|
"activity_type": "feedback",
|
|
"estimated_minutes": 2,
|
|
"icon": "thumb_up"
|
|
},
|
|
{
|
|
"id": "homework_assign",
|
|
"title": "Hausaufgabe vergeben",
|
|
"description": "Passende Hausaufgabe zur Vertiefung des Gelernten",
|
|
"activity_type": "homework",
|
|
"estimated_minutes": 3,
|
|
"icon": "home_work"
|
|
},
|
|
{
|
|
"id": "one_word",
|
|
"title": "Ein-Wort-Reflexion",
|
|
"description": "Jeder Schueler nennt ein Wort, das die Stunde beschreibt",
|
|
"activity_type": "feedback",
|
|
"estimated_minutes": 3,
|
|
"icon": "chat"
|
|
},
|
|
{
|
|
"id": "preview_next",
|
|
"title": "Ausblick naechste Stunde",
|
|
"description": "Kurzer Ausblick auf das Thema der naechsten Stunde",
|
|
"activity_type": "preview",
|
|
"estimated_minutes": 2,
|
|
"icon": "event"
|
|
},
|
|
{
|
|
"id": "learning_log",
|
|
"title": "Lerntagebuch",
|
|
"description": "Schueler notieren ihre wichtigsten Erkenntnisse im Lerntagebuch",
|
|
"activity_type": "feedback",
|
|
"estimated_minutes": 4,
|
|
"icon": "menu_book"
|
|
}
|
|
]
|
|
}
|
|
|
|
|
|
class SuggestionEngine:
|
|
"""
|
|
Engine zur Generierung von phasenspezifischen Vorschlaegen (Feature f18 erweitert).
|
|
|
|
Liefert Aktivitaets-Vorschlaege basierend auf:
|
|
- Aktueller Phase
|
|
- Fach (priorisiert fachspezifische Vorschlaege)
|
|
- Optional: Klassenstufe, bisherige Nutzung
|
|
"""
|
|
|
|
def _normalize_subject(self, subject: str) -> Optional[str]:
|
|
"""Normalisiert Fachnamen fuer die Suche."""
|
|
if not subject:
|
|
return None
|
|
normalized = subject.lower().strip()
|
|
# Mapping zu Hauptkategorien
|
|
mappings = {
|
|
"mathe": "mathematik",
|
|
"math": "mathematik",
|
|
"bio": "biologie",
|
|
"english": "englisch",
|
|
"erdkunde": "geografie",
|
|
}
|
|
return mappings.get(normalized, normalized)
|
|
|
|
def _get_subject_suggestions(
|
|
self,
|
|
subject: str,
|
|
phase: LessonPhase
|
|
) -> List[Dict[str, Any]]:
|
|
"""Holt fachspezifische Vorschlaege (Feature f18)."""
|
|
normalized = self._normalize_subject(subject)
|
|
if not normalized:
|
|
return []
|
|
|
|
subject_data = SUBJECT_SUGGESTIONS.get(normalized, {})
|
|
return subject_data.get(phase, [])
|
|
|
|
def get_suggestions(
|
|
self,
|
|
session: LessonSession,
|
|
limit: int = 3
|
|
) -> List[PhaseSuggestion]:
|
|
"""
|
|
Gibt Vorschlaege fuer die aktuelle Phase zurueck.
|
|
|
|
Priorisiert fachspezifische Vorschlaege (Feature f18),
|
|
ergaenzt mit allgemeinen Vorschlaegen.
|
|
|
|
Args:
|
|
session: Die aktuelle Session
|
|
limit: Maximale Anzahl Vorschlaege
|
|
|
|
Returns:
|
|
Liste von PhaseSuggestion Objekten
|
|
"""
|
|
# Keine Vorschlaege fuer inaktive Phasen
|
|
if session.current_phase in [LessonPhase.NOT_STARTED, LessonPhase.ENDED]:
|
|
return []
|
|
|
|
suggestions = []
|
|
seen_ids = set()
|
|
|
|
# 1. Fachspezifische Vorschlaege zuerst (Feature f18)
|
|
if session.subject:
|
|
subject_suggestions = self._get_subject_suggestions(
|
|
session.subject,
|
|
session.current_phase
|
|
)
|
|
for s in subject_suggestions:
|
|
if s["id"] not in seen_ids:
|
|
suggestions.append(PhaseSuggestion(**s))
|
|
seen_ids.add(s["id"])
|
|
if len(suggestions) >= limit:
|
|
return suggestions
|
|
|
|
# 2. Allgemeine Vorschlaege ergaenzen
|
|
phase_suggestions = PHASE_SUGGESTIONS.get(session.current_phase, [])
|
|
for s in phase_suggestions:
|
|
if s["id"] not in seen_ids:
|
|
suggestions.append(PhaseSuggestion(**s))
|
|
seen_ids.add(s["id"])
|
|
if len(suggestions) >= limit:
|
|
break
|
|
|
|
return suggestions
|
|
|
|
def get_all_suggestions(self, session: LessonSession) -> List[PhaseSuggestion]:
|
|
"""
|
|
Gibt alle Vorschlaege fuer die aktuelle Phase zurueck.
|
|
|
|
Inkludiert fachspezifische und allgemeine Vorschlaege (Feature f18).
|
|
|
|
Args:
|
|
session: Die aktuelle Session
|
|
|
|
Returns:
|
|
Alle Vorschlaege fuer die Phase
|
|
"""
|
|
return self.get_suggestions(session, limit=100)
|
|
|
|
def get_suggestion_by_id(
|
|
self,
|
|
session: LessonSession,
|
|
suggestion_id: str
|
|
) -> Optional[PhaseSuggestion]:
|
|
"""
|
|
Gibt einen spezifischen Vorschlag zurueck.
|
|
|
|
Args:
|
|
session: Die aktuelle Session
|
|
suggestion_id: ID des Vorschlags
|
|
|
|
Returns:
|
|
Der Vorschlag oder None
|
|
"""
|
|
all_suggestions = self.get_all_suggestions(session)
|
|
for s in all_suggestions:
|
|
if s.id == suggestion_id:
|
|
return s
|
|
return None
|
|
|
|
def get_suggestions_by_type(
|
|
self,
|
|
session: LessonSession,
|
|
activity_type: str
|
|
) -> List[PhaseSuggestion]:
|
|
"""
|
|
Gibt Vorschlaege eines bestimmten Typs zurueck.
|
|
|
|
Args:
|
|
session: Die aktuelle Session
|
|
activity_type: Der Aktivitaetstyp (z.B. "warmup", "group_work")
|
|
|
|
Returns:
|
|
Gefilterte Vorschlaege
|
|
"""
|
|
all_suggestions = self.get_all_suggestions(session)
|
|
return [s for s in all_suggestions if s.activity_type == activity_type]
|
|
|
|
def get_suggestions_response(
|
|
self,
|
|
session: LessonSession,
|
|
limit: int = 3
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Gibt die Vorschlaege als API-Response-Format zurueck (Feature f18 erweitert).
|
|
|
|
Args:
|
|
session: Die aktuelle Session
|
|
limit: Maximale Anzahl Vorschlaege
|
|
|
|
Returns:
|
|
Dictionary fuer API-Response
|
|
"""
|
|
suggestions = self.get_suggestions(session, limit)
|
|
|
|
# Zaehle fachspezifische und allgemeine Vorschlaege
|
|
general_count = len(PHASE_SUGGESTIONS.get(session.current_phase, []))
|
|
subject_count = len(self._get_subject_suggestions(
|
|
session.subject,
|
|
session.current_phase
|
|
)) if session.subject else 0
|
|
|
|
return {
|
|
"suggestions": [s.to_dict() for s in suggestions],
|
|
"current_phase": session.current_phase.value,
|
|
"phase_display_name": session.get_phase_display_name(),
|
|
"total_available": general_count + subject_count,
|
|
"subject_specific_available": subject_count,
|
|
"subject": session.subject,
|
|
}
|