Files
breakpilot-lehrer/backend-lehrer/worksheets/models.py
Benjamin Admin cba877c65a
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 37s
CI / test-go-edu-search (push) Successful in 35s
CI / test-python-klausur (push) Failing after 2m41s
CI / test-python-agent-core (push) Successful in 30s
CI / test-nodejs-website (push) Successful in 38s
Restructure: Move final 16 root files into packages (backend-lehrer)
classroom/ (+2): state_engine_api, state_engine_models
vocabulary/ (2): api, db
worksheets/ (2): api, models
services/  (+6): audio, email, translation, claude_vision, ai_processor, story_generator
api/        (4): school, klausur_proxy, progress, user_language

Only main.py + config.py remain at root. 16 shims added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 22:50:37 +02:00

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]