from __future__ import annotations from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field SourceType = Literal[ "pdf", "image", "syllabus_text", "chapter_text", "pyq_paper", "notes", "link", ] MAX_SOURCE_TITLE_CHARS = 240 MAX_SOURCE_TEXT_CHARS = 200_000 MAX_SOURCE_METADATA_CHARS = 120 class SourceTextCreate(BaseModel): title: str = Field(min_length=1, max_length=MAX_SOURCE_TITLE_CHARS) text: str = Field(min_length=1, max_length=MAX_SOURCE_TEXT_CHARS) source_type: SourceType = "syllabus_text" subject: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) chapter: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) syllabus: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) class SourceUpdate(BaseModel): title: str | None = Field(default=None, min_length=1, max_length=MAX_SOURCE_TITLE_CHARS) text: str | None = Field(default=None, min_length=1, max_length=MAX_SOURCE_TEXT_CHARS) subject: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) chapter: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) syllabus: str | None = Field(default=None, max_length=MAX_SOURCE_METADATA_CHARS) class SourceRead(BaseModel): id: str user_id: str title: str source_type: str status: str file_name: str | None = None file_type: str | None = None subject: str | None = None chapter: str | None = None syllabus: str | None = None word_count: int = 0 chunk_count: int = 0 preview_text: str = "" extraction_error: str | None = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) class SourceList(BaseModel): sources: list[SourceRead] = Field(default_factory=list)