Spaces:
Sleeping
Sleeping
File size: 4,738 Bytes
f9766bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | """
utils.py
Helper utilities: progress persistence, notes, topic lists, learning paths, etc.
"""
import json
import os
from datetime import date
PROGRESS_FILE = "learning_progress.json"
NOTES_FILE = "notes.json"
TOPICS = [
"Photosynthesis",
"Machine Learning",
"World War II",
"Python Functions",
"Calculus",
"Climate Change",
"The French Revolution",
"DNA Replication",
"Object-Oriented Programming",
"The Solar System",
"Economics Supply & Demand",
"Quantum Mechanics",
]
LEARNING_PATHS = {
"machine learning": ["Python Functions", "Calculus", "Economics Supply & Demand", "Machine Learning"],
"quantum mechanics": ["Calculus", "The Solar System", "Quantum Mechanics"],
"dna replication": ["Photosynthesis", "DNA Replication"],
"calculus": ["Python Functions", "Calculus"],
"object-oriented programming": ["Python Functions", "Object-Oriented Programming"],
"climate change": ["Photosynthesis", "Economics Supply & Demand", "Climate Change"],
}
def get_topics() -> list:
return sorted(TOPICS)
def load_progress() -> dict:
"""Load progress from JSON file, or return empty structure."""
if os.path.exists(PROGRESS_FILE):
try:
with open(PROGRESS_FILE, "r") as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
pass
return {
"topics_studied": [],
"scores": [],
"best_score": 0,
"topic_scores": {}, # {topic: best_score_int}
"sessions": [], # [{topic, score, date}]
}
def save_progress(progress: dict, topic: str = None, score: int = None) -> None:
"""Update and persist progress data."""
if "topic_scores" not in progress:
progress["topic_scores"] = {}
if "sessions" not in progress:
progress["sessions"] = []
if topic:
studied = progress.get("topics_studied", [])
if topic not in studied:
studied.append(topic)
progress["topics_studied"] = studied
if score is not None:
scores = progress.get("scores", [])
scores.append(score)
progress["scores"] = scores
if score > progress.get("best_score", 0):
progress["best_score"] = score
# Per-topic best score (store single int, not list)
if topic:
ts = progress["topic_scores"]
existing = ts.get(topic, 0)
# Handle legacy list format
if isinstance(existing, list):
existing = max(existing) if existing else 0
ts[topic] = max(existing, score)
progress["topic_scores"] = ts
# Session log
sessions = progress.get("sessions", [])
sessions.append({
"topic": topic or "Unknown",
"score": score,
"date": str(date.today())
})
progress["sessions"] = sessions
try:
with open(PROGRESS_FILE, "w") as f:
json.dump(progress, f, indent=2)
except IOError:
pass
def get_weak_topics(progress: dict) -> list:
"""Return topics where the best score is below 60%."""
result = []
for topic, score in progress.get("topic_scores", {}).items():
# Handle legacy list format
if isinstance(score, list):
score = max(score) if score else 0
if score < 60:
result.append(topic)
return result
def get_learning_path(topic: str) -> list:
"""Return recommended learning path for a topic, or empty list."""
return LEARNING_PATHS.get(topic.lower().strip(), [])
# ββ Notes ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def load_notes() -> list:
"""Load saved notes from JSON file."""
if os.path.exists(NOTES_FILE):
try:
with open(NOTES_FILE, "r") as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
pass
return []
def save_note(note_text: str, topic: str) -> None:
"""Append a note and persist to file."""
notes = load_notes()
notes.append({
"topic": topic,
"note": note_text,
"date": str(date.today())
})
try:
with open(NOTES_FILE, "w") as f:
json.dump(notes, f, indent=2)
except IOError:
pass
def delete_note(index: int) -> None:
"""Delete a note by its index."""
notes = load_notes()
if 0 <= index < len(notes):
notes.pop(index)
try:
with open(NOTES_FILE, "w") as f:
json.dump(notes, f, indent=2)
except IOError:
pass |