klausur-service (11 files): - cv_gutter_repair, ocr_pipeline_regression, upload_api - ocr_pipeline_sessions, smart_spell, nru_worksheet_generator - ocr_pipeline_overlays, mail/aggregator, zeugnis_api - cv_syllable_detect, self_rag backend-lehrer (17 files): - classroom_engine/suggestions, generators/quiz_generator - worksheets_api, llm_gateway/comparison, state_engine_api - classroom/models (→ 4 submodules), services/file_processor - alerts_agent/api/wizard+digests+routes, content_generators/pdf - classroom/routes/sessions, llm_gateway/inference - classroom_engine/analytics, auth/keycloak_auth - alerts_agent/processing/rule_engine, ai_processor/print_versions agent-core (5 files): - brain/memory_store, brain/knowledge_graph, brain/context_manager - orchestrator/supervisor, sessions/session_manager admin-lehrer (5 components): - GridOverlay, StepGridReview, DevOpsPipelineSidebar - DataFlowDiagram, sbom/wizard/page website (2 files): - DependencyMap, lehrer/abitur-archiv Other: nibis_ingestion, grid_detection_service, export-doclayout-onnx Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
136 lines
4.3 KiB
Python
136 lines
4.3 KiB
Python
"""
|
|
Worksheets API - Pydantic Models und Helpers.
|
|
|
|
Request-/Response-Models und Hilfsfunktionen fuer die
|
|
Arbeitsblatt-Generierungs-API.
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import List, Dict, Any, Optional
|
|
from enum import Enum
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from generators.mc_generator import Difficulty
|
|
from generators.cloze_generator import ClozeType
|
|
from generators.quiz_generator import QuizType
|
|
|
|
|
|
# ============================================================================
|
|
# Pydantic Models
|
|
# ============================================================================
|
|
|
|
class ContentType(str, Enum):
|
|
"""Verfügbare Content-Typen."""
|
|
MULTIPLE_CHOICE = "multiple_choice"
|
|
CLOZE = "cloze"
|
|
MINDMAP = "mindmap"
|
|
QUIZ = "quiz"
|
|
|
|
|
|
class GenerateRequest(BaseModel):
|
|
"""Basis-Request für Generierung."""
|
|
source_text: str = Field(..., min_length=50, description="Quelltext für Generierung")
|
|
topic: Optional[str] = Field(None, description="Thema/Titel")
|
|
subject: Optional[str] = Field(None, description="Fach")
|
|
grade_level: Optional[str] = Field(None, description="Klassenstufe")
|
|
|
|
|
|
class MCGenerateRequest(GenerateRequest):
|
|
"""Request für Multiple-Choice-Generierung."""
|
|
num_questions: int = Field(5, ge=1, le=20, description="Anzahl Fragen")
|
|
difficulty: str = Field("medium", description="easy, medium, hard")
|
|
|
|
|
|
class ClozeGenerateRequest(GenerateRequest):
|
|
"""Request für Lückentext-Generierung."""
|
|
num_gaps: int = Field(5, ge=1, le=15, description="Anzahl Lücken")
|
|
difficulty: str = Field("medium", description="easy, medium, hard")
|
|
cloze_type: str = Field("fill_in", description="fill_in, drag_drop, dropdown")
|
|
|
|
|
|
class MindmapGenerateRequest(GenerateRequest):
|
|
"""Request für Mindmap-Generierung."""
|
|
max_depth: int = Field(3, ge=2, le=5, description="Maximale Tiefe")
|
|
|
|
|
|
class QuizGenerateRequest(GenerateRequest):
|
|
"""Request für Quiz-Generierung."""
|
|
quiz_types: List[str] = Field(
|
|
["true_false", "matching"],
|
|
description="Typen: true_false, matching, sorting, open_ended"
|
|
)
|
|
num_items: int = Field(5, ge=1, le=10, description="Items pro Typ")
|
|
difficulty: str = Field("medium", description="easy, medium, hard")
|
|
|
|
|
|
class BatchGenerateRequest(BaseModel):
|
|
"""Request für Batch-Generierung mehrerer Content-Typen."""
|
|
source_text: str = Field(..., min_length=50)
|
|
content_types: List[str] = Field(..., description="Liste von Content-Typen")
|
|
topic: Optional[str] = None
|
|
subject: Optional[str] = None
|
|
grade_level: Optional[str] = None
|
|
difficulty: str = "medium"
|
|
|
|
|
|
class WorksheetContent(BaseModel):
|
|
"""Generierter Content."""
|
|
id: str
|
|
content_type: str
|
|
data: Dict[str, Any]
|
|
h5p_format: Optional[Dict[str, Any]] = None
|
|
created_at: datetime
|
|
topic: Optional[str] = None
|
|
difficulty: Optional[str] = None
|
|
|
|
|
|
class GenerateResponse(BaseModel):
|
|
"""Response mit generiertem Content."""
|
|
success: bool
|
|
content: Optional[WorksheetContent] = None
|
|
error: Optional[str] = None
|
|
|
|
|
|
class BatchGenerateResponse(BaseModel):
|
|
"""Response für Batch-Generierung."""
|
|
success: bool
|
|
contents: List[WorksheetContent] = []
|
|
errors: List[str] = []
|
|
|
|
|
|
# ============================================================================
|
|
# Helper Functions
|
|
# ============================================================================
|
|
|
|
def parse_difficulty(difficulty_str: str) -> Difficulty:
|
|
"""Konvertiert String zu Difficulty Enum."""
|
|
mapping = {
|
|
"easy": Difficulty.EASY,
|
|
"medium": Difficulty.MEDIUM,
|
|
"hard": Difficulty.HARD
|
|
}
|
|
return mapping.get(difficulty_str.lower(), Difficulty.MEDIUM)
|
|
|
|
|
|
def parse_cloze_type(type_str: str) -> ClozeType:
|
|
"""Konvertiert String zu ClozeType Enum."""
|
|
mapping = {
|
|
"fill_in": ClozeType.FILL_IN,
|
|
"drag_drop": ClozeType.DRAG_DROP,
|
|
"dropdown": ClozeType.DROPDOWN
|
|
}
|
|
return mapping.get(type_str.lower(), ClozeType.FILL_IN)
|
|
|
|
|
|
def parse_quiz_types(type_strs: List[str]) -> List[QuizType]:
|
|
"""Konvertiert String-Liste zu QuizType Enums."""
|
|
mapping = {
|
|
"true_false": QuizType.TRUE_FALSE,
|
|
"matching": QuizType.MATCHING,
|
|
"sorting": QuizType.SORTING,
|
|
"open_ended": QuizType.OPEN_ENDED
|
|
}
|
|
return [mapping.get(t.lower(), QuizType.TRUE_FALSE) for t in type_strs]
|