Add spell practice, memory analytics, auth persistence, and word library UX.
Includes per-word training stats and curves, quiz session auto-save, remember-login, paginated word list with floating page arrows, and Obsidian-style relationship graph baseline. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -118,6 +118,27 @@ class QuizService:
|
||||
correct_answer=correct,
|
||||
)
|
||||
|
||||
def build_spell_question(self, word: Word) -> QuizQuestion:
|
||||
zh = word.source_text if word.source_lang == "zh" else word.target_text
|
||||
en = word.target_text if word.source_lang == "zh" else word.source_text
|
||||
return QuizQuestion(
|
||||
word_id=word.id,
|
||||
question_type="spell",
|
||||
prompt=zh,
|
||||
phonetic=word.phonetic,
|
||||
options=[],
|
||||
correct_answer=en,
|
||||
)
|
||||
|
||||
def get_spell_quiz(self, db: Session, user: User) -> dict:
|
||||
settings = self.get_settings(db, user)
|
||||
words = self.select_daily_words(db, user, settings.daily_target)
|
||||
questions = [self.build_spell_question(w) for w in words]
|
||||
return {
|
||||
"questions": questions,
|
||||
"total": len(questions),
|
||||
}
|
||||
|
||||
def get_daily_quiz(self, db: Session, user: User) -> dict:
|
||||
settings = self.get_settings(db, user)
|
||||
words = self.select_daily_words(db, user, settings.daily_target)
|
||||
@@ -143,6 +164,7 @@ class QuizService:
|
||||
question_type: str,
|
||||
user_answer: str,
|
||||
correct_answer: str,
|
||||
duration_seconds: int = 0,
|
||||
) -> dict:
|
||||
word = db.query(Word).filter(Word.id == word_id, Word.user_id == user.id).first()
|
||||
if not word:
|
||||
@@ -150,9 +172,15 @@ class QuizService:
|
||||
raise HTTPException(status_code=404, detail="单词不存在")
|
||||
|
||||
settings = self.get_settings(db, user)
|
||||
is_correct = user_answer.strip() == correct_answer.strip()
|
||||
if question_type == "spell":
|
||||
is_correct = (
|
||||
user_answer.strip().lower() == correct_answer.strip().lower()
|
||||
)
|
||||
else:
|
||||
is_correct = user_answer.strip() == correct_answer.strip()
|
||||
now = utc_now_iso()
|
||||
today = today_str()
|
||||
duration_seconds = max(0, min(int(duration_seconds or 0), 3600))
|
||||
|
||||
if is_correct:
|
||||
word.correct_count += 1
|
||||
@@ -175,6 +203,8 @@ class QuizService:
|
||||
|
||||
word.mastery_score = calc_mastery_score(word.correct_count, word.wrong_count)
|
||||
word.last_reviewed_at = now
|
||||
word.train_count += 1
|
||||
word.total_train_seconds += duration_seconds
|
||||
|
||||
record = QuizRecord(
|
||||
user_id=user.id,
|
||||
@@ -183,6 +213,7 @@ class QuizService:
|
||||
user_answer=user_answer,
|
||||
correct_answer=correct_answer,
|
||||
is_correct=1 if is_correct else 0,
|
||||
duration_seconds=duration_seconds,
|
||||
created_at=now,
|
||||
)
|
||||
db.add(record)
|
||||
|
||||
Reference in New Issue
Block a user