from pydantic import BaseModel, EmailStr, field_validator from typing import List, Optional, Dict, Any from datetime import datetime # User Schemas class UserBase(BaseModel): email: EmailStr class UserCreate(UserBase): password: str class UserLogin(BaseModel): email: EmailStr password: str class UserResponse(UserBase): id: int is_active: bool = True class Config: from_attributes = True class ForgotPasswordRequest(BaseModel): email: EmailStr class VerifyOTPRequest(BaseModel): email: EmailStr otp: str class ResetPasswordRequest(BaseModel): new_password: str class ChangePasswordRequest(BaseModel): new_password: str # Token Schemas class Token(BaseModel): access_token: str token_type: str class TokenData(BaseModel): email: Optional[str] = None # Source Schemas class SourceFileResponse(BaseModel): id: int filename: str s3_key: str public_url: str private_url: Optional[str] = None size: int created_at: datetime rag_id: Optional[int] = None azure_doc_id: Optional[str] = None class Config: from_attributes = True # Podcast Schemas class PodcastGenerateRequest(BaseModel): user_prompt: str model: str = "gpt-4o" duration_minutes: int = 10 podcast_format: str = "deep dive" file_key: Optional[str] = None tts_model: str = "gemini-2.5-flash-preview-tts" spk1_voice: str = "Zephyr" spk2_voice: str = "Charon" bgm_choice: str = "No BGM" temperature: float = 1.0 class PodcastResponse(BaseModel): id: int title: Optional[str] s3_key: Optional[str] s3_url: Optional[str] script: Optional[str] status: Optional[str] = "completed" error_message: Optional[str] parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None created_at: datetime class Config: from_attributes = True # Flashcard Schemas class FlashcardItem(BaseModel): question: str answer: str class FlashcardGenerateRequest(BaseModel): file_key: Optional[str] = None text_input: Optional[str] = None difficulty: str = "medium" quantity: str = "standard" topic: Optional[str] = None language: str = "English" class FlashcardResponse(BaseModel): id: int question: str answer: str class Config: from_attributes = True class FlashcardSetResponse(BaseModel): id: int title: Optional[str] difficulty: str status: Optional[str] = "completed" error_message: Optional[str] = None created_at: datetime parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None flashcards: List[FlashcardResponse] = [] class Config: from_attributes = True # Mind Map Schemas class MindMapGenerateRequest(BaseModel): file_key: Optional[str] = None text_input: Optional[str] = None title: Optional[str] = None class MindMapResponse(BaseModel): id: Optional[int] = None title: str mermaid_code: Optional[str] = None status: Optional[str] = "completed" error_message: Optional[str] = None parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None created_at: Optional[datetime] = None message: Optional[str] = None class Config: from_attributes = True # Quiz Schemas class QuizGenerateRequest(BaseModel): file_key: Optional[str] = None text_input: Optional[str] = None difficulty: str = "medium" topic: Optional[str] = None language: str = "English" count: str = "STANDARD" # FEWER, STANDARD, MORE class QuizChoice(BaseModel) : value: str label: str class QuizQuestionResponse(BaseModel): id: int question: str hint: Optional[str] choices: List[QuizChoice] answer: str explanation: Optional[str] @field_validator('choices', mode='before') @classmethod def validate_choices(cls, v): if isinstance(v, dict): # Convert {"1": "label1", "2": "label2"} to [{"value": "1", "label": "label1"}, ...] return [{"value": key, "label": value} for key, value in v.items()] return v class Config: from_attributes = True class QuizSetResponse(BaseModel): id: int title: Optional[str] difficulty: str status: Optional[str] = "completed" error_message: Optional[str] = None created_at: datetime parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None questions: List[QuizQuestionResponse] = [] class Config: from_attributes = True # Report Schemas class ReportFormatSuggestion(BaseModel): name: str description: str prompt: str class ReportFormatSuggestionResponse(BaseModel): suggestions: List[ReportFormatSuggestion] class ReportGenerateRequest(BaseModel): file_key: Optional[str] = None text_input: Optional[str] = None format_key: str # briefing_doc, study_guide, blog_post, custom, or suggested_X custom_prompt: Optional[str] = None language: str = "Japanese" class ReportResponse(BaseModel): id: int title: str content: Optional[str] = None format_key: str status: Optional[str] = "completed" error_message: Optional[str] = None parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None created_at: datetime class Config: from_attributes = True # Video Summary Schemas class VideoSummaryGenerateRequest(BaseModel): file_key: str language: str = "Japanese" voice_name: str = "Kore" # Kore, Fenrir, etc. use_slides_transformation: bool = True custom_prompt: Optional[str] = "" class VideoSummaryResponse(BaseModel): id: int title: str s3_key: Optional[str] = None public_url: Optional[str] = None private_url: Optional[str] = None status: Optional[str] = "completed" error_message: Optional[str] = None parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None created_at: datetime class Config: from_attributes = True # RAG Schemas class RAGDocumentUploadRequest(BaseModel): source_id: Optional[int] = None # Link to existing source file class RAGSearchRequest(BaseModel): query: str top_k: int = 5 class RAGDocumentResponse(BaseModel): id: int filename: str azure_doc_id: str blob_url: Optional[str] content_preview: Optional[str] chunk_count: int created_at: datetime class Config: from_attributes = True class RAGSearchResult(BaseModel): content: str score: float source: str metadata: Dict[str, Any] = {} class RAGSearchResponse(BaseModel): results: List[RAGSearchResult] answer: Optional[str] = None # RAG Query Request (Simplified) class RAGQueryRequest(BaseModel): file_key: str # S3 key of the source file query: str top_k: int = 3 # Number of relevant chunks to use # Chat Schemas class ChatMessageCreate(BaseModel): query: str # The user's question or message rag_doc_id: Optional[int] = None # Optional: Link to a specific document for context class ChatMessageResponse(BaseModel): id: int role: str content: str # keeping 'content' here as it represents the stored/returned textual data rag_doc_id: Optional[int] created_at: datetime class Config: from_attributes = True # Canvas Schemas class CanvasCreateRequest(BaseModel): file_key: Optional[str] = None text_input: Optional[str] = None title: Optional[str] = None class CanvasEditRequest(BaseModel): text: str # The manually edited markdown text class CanvasResponse(BaseModel): id: int title: str text: Optional[str] status: str error_message: Optional[str] = None parent_file_id: Optional[int] = None parent_file_key: Optional[str] = None created_at: datetime updated_at: datetime class Config: from_attributes = True