nex_math/backend/services/mastery_engine.py

84 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""掌握度引擎:状态分级、按全局知识点节点答题后更新。"""
from __future__ import annotations
from dataclasses import dataclass
from sqlalchemy.orm import Session
from models import Knowledge, UserKnowledge
from services.knowledge_service import ensure_knowledge, ensure_user_knowledge
MASTERY_DELTA = {
"chapter": (5, 4),
"legacy": (4, 3),
"imported": (0, 0),
}
@dataclass
class KnowledgeView:
id: int
knowledge_id: int
name: str
mastery: int
position: int
domain: str
category: str
def status_for(mastery: int) -> str:
if mastery >= 85:
return "已掌握"
if mastery >= 75:
return "基本掌握"
if mastery >= 60:
return "待加强"
return "重点"
def action_for(mastery: int) -> str:
if mastery < 60:
return "优先强化"
if mastery < 75:
return "继续练习"
return "保持复习"
def snapshot(db: Session, user_id: int) -> list[KnowledgeView]:
rows = (
db.query(UserKnowledge, Knowledge)
.join(Knowledge, Knowledge.id == UserKnowledge.knowledge_id)
.filter(UserKnowledge.user_id == user_id)
.order_by(UserKnowledge.position.asc(), UserKnowledge.id.asc())
.all()
)
return [
KnowledgeView(
id=user_knowledge.id,
knowledge_id=knowledge.id,
name=knowledge.name,
mastery=user_knowledge.mastery,
position=user_knowledge.position,
domain=knowledge.domain,
category=knowledge.category,
)
for user_knowledge, knowledge in rows
]
def apply_answers(
db: Session,
user_id: int,
mode: str,
answered: list[tuple[str, bool]],
) -> None:
"""按题目全量知识点逐点调整掌握度(答对加分、答错扣分,封顶 0-100)。"""
plus, minus = MASTERY_DELTA.get(mode, (4, 3))
for knowledge_name, is_correct in answered:
knowledge = ensure_knowledge(db, knowledge_name)
row = ensure_user_knowledge(db, user_id, knowledge)
row.mastery = max(
0, min(100, row.mastery + (plus if is_correct else -minus))
)