from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field DocumentStatus = Literal["uploaded", "processing", "ready", "failed"] EducationExtractionStatus = Literal[ "uploaded", "classifying", "extracting", "ready", "needs_review", "extraction_failed", ] class DocumentRead(BaseModel): id: str user_id: str title: str file_name: str file_type: str # file_path intentionally excluded — server filesystem path must not reach the client # extracted_text intentionally excluded — raw OCR text is private document content # extraction_error intentionally excluded — internal processing state must not leak subject: str | None chapter: str | None syllabus: str | None status: str chunk_count: int source_type: str = "pdf" material_type: str = "unknown" education_extraction_status: str = "uploaded" education_extraction_error: str | None = None education_warnings_json: list[str] = Field(default_factory=list) syllabus_items_count: int = 0 pyq_questions_count: int = 0 pyq_years_json: list[int] = Field(default_factory=list) extracted_text_length: int | None = None processing_started_at: datetime | None = None processing_completed_at: datetime | None = None created_at: datetime model_config = ConfigDict(from_attributes=True) class DocumentUploadResponse(BaseModel): id: str user_id: str title: str file_name: str file_type: str # extracted_text intentionally excluded — raw OCR text is private document content subject: str | None chapter: str | None syllabus: str | None status: str chunk_count: int source_type: str = "pdf" material_type: str = "unknown" education_extraction_status: str = "uploaded" education_extraction_error: str | None = None education_warnings_json: list[str] = Field(default_factory=list) syllabus_items_count: int = 0 pyq_questions_count: int = 0 pyq_years_json: list[int] = Field(default_factory=list) extracted_text_length: int | None = None processing_started_at: datetime | None = None processing_completed_at: datetime | None = None created_at: datetime model_config = ConfigDict(from_attributes=True) class DocumentPreview(BaseModel): id: str title: str file_name: str status: str extracted_text_preview: str extracted_text_length: int chunk_count: int