AI_math / scripts /generate_curriculum.py
NSamson1's picture
Create scripts/generate_curriculum.py
6bdf07a verified
"""
scripts/generate_curriculum.py
Expands the seed curriculum with additional generated items and writes
data/T3.1_Math_Tutor/curriculum_full.json
Run once before starting the app:
python3 scripts/generate_curriculum.py
"""
from __future__ import annotations
import json, random, sys
from pathlib import Path
SEED_PATH = Path("data/T3.1_Math_Tutor/curriculum_seed.json")
OUT_PATH = Path("data/T3.1_Math_Tutor/curriculum_full.json")
# โ”€โ”€ Generators โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def _counting_items(n_start: int) -> list[dict]:
items = []
for count in range(1, 11):
diff = max(1, round(count / 2))
for label in ["apple","star","ball","flower"]:
items.append({
"id": f"cnt_gen_{count}_{label}",
"skill": "counting",
"difficulty": diff,
"answer_int": count,
"stem_en": f"How many {label}s do you see?",
"stem_fr": f"Combien de {label}s vois-tu ?",
"stem_kin": f"Ubona {label} zingahe?",
"stem_sw": f"Unaona {label} ngapi?",
"visual": f"{label}_{count}",
})
return items
def _addition_items() -> list[dict]:
items = []
for a in range(0, 8):
for b in range(0, 8):
if a + b > 10:
continue
diff = max(1, min(9, a + b))
items.append({
"id": f"add_gen_{a}_{b}",
"skill": "addition",
"difficulty": diff,
"answer_int": a + b,
"stem_en": f"{a} + {b} = ?",
"stem_fr": f"{a} + {b} = ?",
"stem_kin": f"{a} + {b} = ?",
"stem_sw": f"{a} + {b} = ?",
"visual": "",
})
return items
def _subtraction_items() -> list[dict]:
items = []
for a in range(1, 11):
for b in range(0, a + 1):
diff = max(2, min(9, a))
items.append({
"id": f"sub_gen_{a}_{b}",
"skill": "subtraction",
"difficulty": diff,
"answer_int": a - b,
"stem_en": f"{a} - {b} = ?",
"stem_fr": f"{a} - {b} = ?",
"stem_kin": f"{a} - {b} = ?",
"stem_sw": f"{a} - {b} = ?",
"visual": "",
})
return items
def _number_sense_items() -> list[dict]:
items = []
for n in range(1, 10):
items.append({
"id": f"ns_gen_after_{n}",
"skill": "number_sense", "difficulty": max(1, n//2),
"answer_int": n + 1,
"stem_en": f"What number comes after {n}?",
"stem_fr": f"Quel nombre vient aprรจs {n} ?",
"stem_kin": f"Ni umubare ukomeza {n}?",
"stem_sw": f"Nambari gani inakuja baada ya {n}?",
"visual": "",
})
items.append({
"id": f"ns_gen_before_{n+1}",
"skill": "number_sense", "difficulty": max(1, n//2),
"answer_int": n,
"stem_en": f"What number comes before {n+1}?",
"stem_fr": f"Quel nombre vient avant {n+1} ?",
"stem_kin": f"Ni umubare uba imbere ya {n+1}?",
"stem_sw": f"Nambari gani inakuja kabla ya {n+1}?",
"visual": "",
})
return items
# โ”€โ”€ Main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def main():
with open(SEED_PATH, "r", encoding="utf-8") as f:
seed = json.load(f)
existing_ids = {item["id"] for item in seed}
generated = (
_counting_items(len(seed))
+ _addition_items()
+ _subtraction_items()
+ _number_sense_items()
)
# De-duplicate against seed
new_items = [i for i in generated if i["id"] not in existing_ids]
full = seed + new_items
random.shuffle(full)
OUT_PATH.parent.mkdir(parents=True, exist_ok=True)
with open(OUT_PATH, "w", encoding="utf-8") as f:
json.dump(full, f, ensure_ascii=False, indent=2)
print(f"โœ… Generated {len(full)} items ({len(seed)} seed + {len(new_items)} new)")
print(f" Saved to {OUT_PATH}")
if __name__ == "__main__":
main()