34 lines
968 B
Python
34 lines
968 B
Python
from __future__ import annotations
|
|
from pydantic import BaseModel, Field
|
|
from typing import Literal
|
|
|
|
EvidenceKind = Literal["checkpoint", "project", "exercise", "review"]
|
|
|
|
class MasteryRecord(BaseModel):
|
|
concept_id: str
|
|
dimension: str
|
|
score: float = 0.0
|
|
confidence: float = 0.0
|
|
evidence_count: int = 0
|
|
last_updated: str = ""
|
|
|
|
class EvidenceEvent(BaseModel):
|
|
concept_id: str
|
|
dimension: str
|
|
score: float
|
|
confidence_hint: float = 0.5
|
|
timestamp: str
|
|
kind: EvidenceKind = "exercise"
|
|
source_id: str = ""
|
|
|
|
class LearnerState(BaseModel):
|
|
learner_id: str
|
|
records: list[MasteryRecord] = Field(default_factory=list)
|
|
history: list[EvidenceEvent] = Field(default_factory=list)
|
|
|
|
def get_record(self, concept_id: str, dimension: str) -> MasteryRecord | None:
|
|
for rec in self.records:
|
|
if rec.concept_id == concept_id and rec.dimension == dimension:
|
|
return rec
|
|
return None
|