Apply ZIP update: 205-didactopus-learner-state-progression-update.zip [2026-03-14T13:20:33]
This commit is contained in:
parent
adac1e1637
commit
ed60c1d8f2
|
|
@ -6,18 +6,7 @@ build-backend = "setuptools.build_meta"
|
|||
name = "didactopus"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"pydantic>=2.7",
|
||||
"fastapi>=0.115",
|
||||
"uvicorn>=0.30",
|
||||
"sqlalchemy>=2.0",
|
||||
"passlib[bcrypt]>=1.7",
|
||||
"python-jose[cryptography]>=3.3"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
didactopus-api = "didactopus.api:main"
|
||||
didactopus-export-svg = "didactopus.export_svg:main"
|
||||
dependencies = ["pydantic>=2.7", "pyyaml>=6.0"]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
from __future__ import annotations
|
||||
from datetime import datetime, timezone
|
||||
from .learner_state import LearnerState, EvidenceEvent, MasteryRecord
|
||||
|
||||
def _parse_ts(ts: str) -> datetime:
|
||||
return datetime.fromisoformat(ts.replace("Z", "+00:00"))
|
||||
|
||||
def apply_evidence(
|
||||
state: LearnerState,
|
||||
event: EvidenceEvent,
|
||||
|
|
@ -19,13 +23,34 @@ def apply_evidence(
|
|||
)
|
||||
state.records.append(rec)
|
||||
|
||||
prev_score = rec.score
|
||||
prev_conf = rec.confidence
|
||||
|
||||
# weighted incremental update
|
||||
weight = max(0.05, min(1.0, event.confidence_hint))
|
||||
rec.score = ((rec.score * rec.evidence_count) + (event.score * weight)) / max(1, rec.evidence_count + 1)
|
||||
rec.score = ((prev_score * rec.evidence_count) + (event.score * weight)) / max(1, rec.evidence_count + 1)
|
||||
|
||||
# confidence grows with repeated evidence and quality, but is bounded
|
||||
rec.confidence = min(
|
||||
1.0,
|
||||
max(0.0, rec.confidence * (1.0 - decay) + reinforcement * weight + 0.10 * max(0.0, min(1.0, event.score))),
|
||||
max(
|
||||
0.0,
|
||||
prev_conf * (1.0 - decay) + reinforcement * weight + 0.10 * max(0.0, min(1.0, event.score))
|
||||
),
|
||||
)
|
||||
|
||||
rec.evidence_count += 1
|
||||
rec.last_updated = event.timestamp
|
||||
state.history.append(event)
|
||||
return state
|
||||
|
||||
def decay_confidence(state: LearnerState, now_ts: str, daily_decay: float = 0.0025) -> LearnerState:
|
||||
now = _parse_ts(now_ts)
|
||||
for rec in state.records:
|
||||
if not rec.last_updated:
|
||||
continue
|
||||
then = _parse_ts(rec.last_updated)
|
||||
delta_days = max(0.0, (now - then).total_seconds() / 86400.0)
|
||||
factor = max(0.0, 1.0 - daily_decay * delta_days)
|
||||
rec.confidence = max(0.0, rec.confidence * factor)
|
||||
return state
|
||||
|
|
|
|||
|
|
@ -13,7 +13,14 @@ def recommend_next_concepts(
|
|||
for concept in concepts:
|
||||
cid = concept.get("id")
|
||||
prereqs = list(concept.get("prerequisites", []) or [])
|
||||
ready = concept_ready(state, cid, prereqs, dimension=dimension, min_score=min_score, min_confidence=min_confidence)
|
||||
ready = concept_ready(
|
||||
state,
|
||||
cid,
|
||||
prereqs,
|
||||
dimension=dimension,
|
||||
min_score=min_score,
|
||||
min_confidence=min_confidence,
|
||||
)
|
||||
if ready:
|
||||
existing = state.get_record(cid, dimension)
|
||||
if existing is None or existing.score < min_score or existing.confidence < min_confidence:
|
||||
|
|
|
|||
Loading…
Reference in New Issue