| """tutor/curriculum_loader.py — loads curriculum JSON and samples items.""" |
| from __future__ import annotations |
| import json, random |
| from pathlib import Path |
| from typing import List, Dict, Any |
|
|
|
|
| def load(path) -> List[Dict[str, Any]]: |
| path = Path(path) |
| if not path.exists(): |
| raise FileNotFoundError(f"Curriculum not found: {path}") |
| with open(path, "r", encoding="utf-8") as f: |
| data = json.load(f) |
| return data if isinstance(data, list) else data.get("items", []) |
|
|
|
|
| def sample_diagnostic_probes( |
| items: List[Dict[str, Any]], |
| n_per_skill: int = 1, |
| diff_min: float = 1, |
| diff_max: float = 10, |
| ) -> List[Dict[str, Any]]: |
| by_skill: Dict[str, List[Dict]] = {} |
| for item in items: |
| if diff_min <= item.get("difficulty", 5) <= diff_max: |
| by_skill.setdefault(item.get("skill", "unknown"), []).append(item) |
| probes = [] |
| for skill_items in by_skill.values(): |
| probes.extend(random.sample(skill_items, min(n_per_skill, len(skill_items)))) |
| random.shuffle(probes) |
| return probes |
|
|
|
|
| def filter_by_skill(items, skill, diff_min=1, diff_max=10): |
| return [i for i in items |
| if i.get("skill") == skill and diff_min <= i.get("difficulty", 5) <= diff_max] |
|
|