""" Abitur Document Store - Enums, Pydantic Models, Data Classes. Shared types for abitur_docs_api and abitur_docs_recognition. """ from datetime import datetime from typing import List, Dict, Any, Optional from enum import Enum from dataclasses import dataclass from pydantic import BaseModel, Field # ============================================================================ # Enums # ============================================================================ class Bundesland(str, Enum): """Bundesländer mit Zentralabitur.""" NIEDERSACHSEN = "niedersachsen" BAYERN = "bayern" BADEN_WUERTTEMBERG = "baden_wuerttemberg" NORDRHEIN_WESTFALEN = "nordrhein_westfalen" HESSEN = "hessen" SACHSEN = "sachsen" THUERINGEN = "thueringen" BERLIN = "berlin" HAMBURG = "hamburg" SCHLESWIG_HOLSTEIN = "schleswig_holstein" BREMEN = "bremen" BRANDENBURG = "brandenburg" MECKLENBURG_VORPOMMERN = "mecklenburg_vorpommern" SACHSEN_ANHALT = "sachsen_anhalt" RHEINLAND_PFALZ = "rheinland_pfalz" SAARLAND = "saarland" class Fach(str, Enum): """Abiturfächer.""" DEUTSCH = "deutsch" ENGLISCH = "englisch" MATHEMATIK = "mathematik" BIOLOGIE = "biologie" CHEMIE = "chemie" PHYSIK = "physik" GESCHICHTE = "geschichte" ERDKUNDE = "erdkunde" POLITIK_WIRTSCHAFT = "politik_wirtschaft" FRANZOESISCH = "franzoesisch" SPANISCH = "spanisch" LATEIN = "latein" GRIECHISCH = "griechisch" KUNST = "kunst" MUSIK = "musik" SPORT = "sport" INFORMATIK = "informatik" EV_RELIGION = "ev_religion" KATH_RELIGION = "kath_religion" WERTE_NORMEN = "werte_normen" BRC = "brc" BVW = "bvw" ERNAEHRUNG = "ernaehrung" MECHATRONIK = "mechatronik" GESUNDHEIT_PFLEGE = "gesundheit_pflege" PAEDAGOGIK_PSYCHOLOGIE = "paedagogik_psychologie" class Niveau(str, Enum): """Anforderungsniveau.""" EA = "eA" GA = "gA" class DokumentTyp(str, Enum): """Dokumenttyp.""" AUFGABE = "aufgabe" ERWARTUNGSHORIZONT = "erwartungshorizont" DECKBLATT = "deckblatt" MATERIAL = "material" HOERVERSTEHEN = "hoerverstehen" SPRACHMITTLUNG = "sprachmittlung" BEWERTUNGSBOGEN = "bewertungsbogen" class VerarbeitungsStatus(str, Enum): """Status der Dokumentenverarbeitung.""" PENDING = "pending" PROCESSING = "processing" RECOGNIZED = "recognized" CONFIRMED = "confirmed" INDEXED = "indexed" ERROR = "error" # ============================================================================ # Fach-Mapping für Dateinamen # ============================================================================ FACH_NAME_MAPPING = { "deutsch": Fach.DEUTSCH, "englisch": Fach.ENGLISCH, "mathe": Fach.MATHEMATIK, "mathematik": Fach.MATHEMATIK, "biologie": Fach.BIOLOGIE, "bio": Fach.BIOLOGIE, "chemie": Fach.CHEMIE, "physik": Fach.PHYSIK, "geschichte": Fach.GESCHICHTE, "erdkunde": Fach.ERDKUNDE, "geographie": Fach.ERDKUNDE, "politikwirtschaft": Fach.POLITIK_WIRTSCHAFT, "politik": Fach.POLITIK_WIRTSCHAFT, "franzoesisch": Fach.FRANZOESISCH, "franz": Fach.FRANZOESISCH, "spanisch": Fach.SPANISCH, "latein": Fach.LATEIN, "griechisch": Fach.GRIECHISCH, "kunst": Fach.KUNST, "musik": Fach.MUSIK, "sport": Fach.SPORT, "informatik": Fach.INFORMATIK, "evreligion": Fach.EV_RELIGION, "kathreligion": Fach.KATH_RELIGION, "wertenormen": Fach.WERTE_NORMEN, "brc": Fach.BRC, "bvw": Fach.BVW, "ernaehrung": Fach.ERNAEHRUNG, "mecha": Fach.MECHATRONIK, "mechatronik": Fach.MECHATRONIK, "technikmecha": Fach.MECHATRONIK, "gespfl": Fach.GESUNDHEIT_PFLEGE, "paedpsych": Fach.PAEDAGOGIK_PSYCHOLOGIE, } # ============================================================================ # Pydantic Models # ============================================================================ class DokumentCreate(BaseModel): """Manuelles Erstellen eines Dokuments.""" bundesland: Bundesland fach: Fach jahr: int = Field(ge=2000, le=2100) niveau: Niveau typ: DokumentTyp aufgaben_nummer: Optional[str] = None class DokumentUpdate(BaseModel): """Update für erkannte Metadaten.""" bundesland: Optional[Bundesland] = None fach: Optional[Fach] = None jahr: Optional[int] = None niveau: Optional[Niveau] = None typ: Optional[DokumentTyp] = None aufgaben_nummer: Optional[str] = None status: Optional[VerarbeitungsStatus] = None class DokumentResponse(BaseModel): """Response für ein Dokument.""" id: str dateiname: str original_dateiname: str bundesland: Bundesland fach: Fach jahr: int niveau: Niveau typ: DokumentTyp aufgaben_nummer: Optional[str] status: VerarbeitungsStatus confidence: float file_path: str file_size: int indexed: bool vector_ids: List[str] created_at: datetime updated_at: datetime class ImportResult(BaseModel): """Ergebnis eines ZIP-Imports.""" total_files: int recognized: int errors: int documents: List[DokumentResponse] class RecognitionResult(BaseModel): """Ergebnis der Dokumentenerkennung.""" success: bool bundesland: Optional[Bundesland] fach: Optional[Fach] jahr: Optional[int] niveau: Optional[Niveau] typ: Optional[DokumentTyp] aufgaben_nummer: Optional[str] confidence: float raw_filename: str suggestions: List[Dict[str, Any]] @property def extracted(self) -> Dict[str, Any]: """Backwards-compatible property returning extracted values as dict.""" result = {} if self.bundesland: result["bundesland"] = self.bundesland.value if self.fach: result["fach"] = self.fach.value if self.jahr: result["jahr"] = self.jahr if self.niveau: result["niveau"] = self.niveau.value if self.typ: result["typ"] = self.typ.value if self.aufgaben_nummer: result["aufgaben_nummer"] = self.aufgaben_nummer return result @property def method(self) -> str: """Backwards-compatible property for recognition method.""" return "filename_pattern" # ============================================================================ # Internal Data Classes # ============================================================================ @dataclass class AbiturDokument: """Internes Dokument.""" id: str dateiname: str original_dateiname: str bundesland: Bundesland fach: Fach jahr: int niveau: Niveau typ: DokumentTyp aufgaben_nummer: Optional[str] status: VerarbeitungsStatus confidence: float file_path: str file_size: int indexed: bool vector_ids: List[str] created_at: datetime updated_at: datetime # ============================================================================ # Backwards-compatibility aliases (used by tests) # ============================================================================ AbiturFach = Fach Anforderungsniveau = Niveau class DocumentMetadata(BaseModel): """Backwards-compatible metadata model for tests.""" jahr: Optional[int] = None bundesland: Optional[str] = None fach: Optional[str] = None niveau: Optional[str] = None dokument_typ: Optional[str] = None aufgaben_nummer: Optional[str] = None class AbiturDokumentCompat(BaseModel): """Backwards-compatible AbiturDokument model for tests.""" id: str filename: str file_path: str metadata: DocumentMetadata status: VerarbeitungsStatus recognition_result: Optional[RecognitionResult] = None created_at: datetime updated_at: datetime class Config: arbitrary_types_allowed = True # ============================================================================ # Fach Labels (für Frontend Enum-Endpoint) # ============================================================================ FACH_LABELS = { Fach.DEUTSCH: "Deutsch", Fach.ENGLISCH: "Englisch", Fach.MATHEMATIK: "Mathematik", Fach.BIOLOGIE: "Biologie", Fach.CHEMIE: "Chemie", Fach.PHYSIK: "Physik", Fach.GESCHICHTE: "Geschichte", Fach.ERDKUNDE: "Erdkunde", Fach.POLITIK_WIRTSCHAFT: "Politik-Wirtschaft", Fach.FRANZOESISCH: "Französisch", Fach.SPANISCH: "Spanisch", Fach.LATEIN: "Latein", Fach.GRIECHISCH: "Griechisch", Fach.KUNST: "Kunst", Fach.MUSIK: "Musik", Fach.SPORT: "Sport", Fach.INFORMATIK: "Informatik", Fach.EV_RELIGION: "Ev. Religion", Fach.KATH_RELIGION: "Kath. Religion", Fach.WERTE_NORMEN: "Werte und Normen", Fach.BRC: "BRC (Betriebswirtschaft)", Fach.BVW: "BVW (Volkswirtschaft)", Fach.ERNAEHRUNG: "Ernährung", Fach.MECHATRONIK: "Mechatronik", Fach.GESUNDHEIT_PFLEGE: "Gesundheit-Pflege", Fach.PAEDAGOGIK_PSYCHOLOGIE: "Pädagogik-Psychologie", } DOKUMENT_TYP_LABELS = { DokumentTyp.AUFGABE: "Aufgabe", DokumentTyp.ERWARTUNGSHORIZONT: "Erwartungshorizont", DokumentTyp.DECKBLATT: "Deckblatt", DokumentTyp.MATERIAL: "Material", DokumentTyp.HOERVERSTEHEN: "Hörverstehen", DokumentTyp.SPRACHMITTLUNG: "Sprachmittlung", DokumentTyp.BEWERTUNGSBOGEN: "Bewertungsbogen", }