Initial commit: WordLoop 单词学习应用
Vue 前端 + FastAPI 后端,含部署脚本与词典数据。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user