from typing import Optional from pydantic import BaseModel, Field # Auth class UserRegister(BaseModel): username: str = Field(min_length=2, max_length=50) password: str = Field(min_length=6, max_length=100) class UserLogin(BaseModel): username: str password: str class TokenResponse(BaseModel): access_token: str token_type: str = "bearer" class UserOut(BaseModel): id: int username: str created_at: str class Config: from_attributes = True # Translate class TranslateRequest(BaseModel): text: str = Field(min_length=1) class TranslateResponse(BaseModel): source_text: str target_text: str source_lang: str target_lang: str phonetic: Optional[str] = None example_en: Optional[str] = None example_cn: Optional[str] = None # Words class WordCreate(BaseModel): source_text: str target_text: str source_lang: str target_lang: str phonetic: Optional[str] = None example_en: Optional[str] = None example_cn: Optional[str] = None class WordUpdate(BaseModel): status: Optional[str] = None class WordOut(BaseModel): id: int user_id: int source_text: str target_text: str source_lang: str target_lang: str phonetic: Optional[str] = None example_en: Optional[str] = None example_cn: Optional[str] = None status: str correct_count: int wrong_count: int consecutive_correct_count: int mastery_score: int review_due_date: Optional[str] = None last_reviewed_at: Optional[str] = None created_at: str class Config: from_attributes = True # Quiz class QuizOption(BaseModel): label: str text: str class QuizQuestion(BaseModel): word_id: int question_type: str prompt: str options: list[QuizOption] correct_answer: str class DailyQuizResponse(BaseModel): questions: list[QuizQuestion] total: int class QuizAnswerRequest(BaseModel): word_id: int question_type: str user_answer: str correct_answer: str class QuizAnswerResponse(BaseModel): is_correct: bool correct_answer: str word: WordOut class QuizStatsResponse(BaseModel): total_words: int new_count: int learning_count: int mastered_count: int weak_count: int today_quiz_count: int today_correct_count: int today_accuracy: float daily_target: int today_completed: int streak_days: int # Settings class SettingsOut(BaseModel): daily_target: int master_required_count: int weak_wrong_threshold: int class Config: from_attributes = True class SettingsUpdate(BaseModel): daily_target: Optional[int] = Field(None, ge=1, le=100) master_required_count: Optional[int] = Field(None, ge=1, le=20) weak_wrong_threshold: Optional[int] = Field(None, ge=1, le=20)