from pydantic import BaseModel, Field from typing import Literal FormatType = Literal[ "OnePager", "MiniGuide", "Guide", "FullGuide", ] ProviderType = Literal["claude", "minimax", "lokal"] class GuideCreateRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) format: FormatType instructions: str = Field(default="", max_length=2000) provider: ProviderType = "claude" class TopicCreateRequest(BaseModel): name: str = Field(min_length=1, max_length=100) class BausteineCreateRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) instructions: str = Field(default="", max_length=2000) provider: ProviderType = "claude" class BausteineStep(BaseModel): label: str state: Literal["done", "active", "pending"] class BausteineStatusResponse(BaseModel): ready: bool generating: bool progress: str | None = None error: str | None = None partial: bool = False steps: list[BausteineStep] = [] class ProjectResponse(BaseModel): name: str class ProviderInfo(BaseModel): id: str available: bool class GuideResponse(BaseModel): id: str topic: str format: str status: str progress: str | None = None step: int | None = None error_msg: str | None = None created_at: str updated_at: str class ChatMessage(BaseModel): role: Literal["user", "assistant"] content: str = Field(min_length=1, max_length=8000) class GuideChatRequest(BaseModel): section: str = Field(default="", max_length=20000) outline: str = Field(default="", max_length=8000) messages: list[ChatMessage] = Field(min_length=1) provider: ProviderType = "claude" class GuideChatResponse(BaseModel): reply: str class ElementResponse(BaseModel): id: str topic: str title: str description: str = "" examples: list[str] = [] hints: list[str] = [] created_at: str updated_at: str class ElementCreateRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) hint: str = Field(default="", max_length=500) provider: ProviderType = "claude" class ElementUpdateRequest(BaseModel): title: str | None = Field(default=None, max_length=200) description: str | None = None examples: list[str] | None = None hints: list[str] | None = None class ElementCheckRequest(BaseModel): provider: ProviderType = "claude" class ElementSuggestion(BaseModel): text: str target: Literal["description", "examples", "hints"] content: str class ElementCheckResponse(BaseModel): suggestions: list[ElementSuggestion] class ElementStyleChange(BaseModel): text: str action: Literal["entfernen", "anpassen", "hinzufuegen"] target: Literal["title", "description", "examples", "hints"] index: int | None = None content: str = "" class ElementStyleResponse(BaseModel): changes: list[ElementStyleChange] class ElementChatRequest(BaseModel): messages: list[ChatMessage] = Field(min_length=1) provider: ProviderType = "claude" class ElementChatResponse(BaseModel): reply: str changes: list[ElementStyleChange] = [] class ElementRefineRequest(BaseModel): suggestion: ElementStyleChange instruction: str = Field(min_length=1, max_length=2000) provider: ProviderType = "claude" class ElementRefineResponse(BaseModel): change: ElementStyleChange class ProgressUpdate(BaseModel): chapter: str = Field(min_length=1, max_length=100) done: bool class ProgressResponse(BaseModel): chapters: list[str] # --- Baustein-Lernen --- VertiefungArt = Literal["vertiefung", "deepdive"] class VertiefungRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) baustein: str = Field(min_length=1, max_length=200) section: str = Field(default="", max_length=20000) art: VertiefungArt = "vertiefung" provider: ProviderType = "claude" class VertiefungResponse(BaseModel): md: str class BausteinChatRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) baustein: str = Field(min_length=1, max_length=200) section: str = Field(default="", max_length=20000) messages: list[ChatMessage] = Field(min_length=1) provider: ProviderType = "claude" class BausteinChatResponse(BaseModel): reply: str class BausteinPruefungRequest(BaseModel): topic: str = Field(min_length=1, max_length=100) baustein: str = Field(min_length=1, max_length=200) section: str = Field(default="", max_length=20000) aktion: Literal["frage", "diskussion", "antwort"] = "frage" 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 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 provider: ProviderType = "claude" class BausteinPruefungResponse(BaseModel): frage: str | None = None reply: str | None = None feedback: str | None = None bewertung: Literal["gut", "schlecht"] | None = None gute_antworten: int absolviert: bool verstanden: bool = False gemeistert: bool = False class BausteinLernstand(BaseModel): gute_antworten: int absolviert: bool verstanden: bool gemeistert: bool vertiefung: bool deepdive: bool class BausteinLernstandResponse(BaseModel): bausteine: dict[str, BausteinLernstand]