Clementio commited on
Commit
a15bdc1
Β·
verified Β·
1 Parent(s): 10a72dd

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +57 -2
app.py CHANGED
@@ -120,7 +120,12 @@ class RankingFunction:
120
  prereqs = list(self.graph.predecessors(topic_id))
121
  readiness = 1.0 if not prereqs else sum(1 for p in prereqs if mastery_vector.is_mastered(p))/len(prereqs)
122
  downstream = self._downstream.get(topic_id, 0.0)
123
- return round(self.w_gap*gap + self.w_ready*readiness + self.w_downstream*downstream, 3)
 
 
 
 
 
124
 
125
  class LearningRecommendationPipeline:
126
  def __init__(self, graph, threshold=0.70, soft_threshold=0.50, top_n=5):
@@ -183,6 +188,54 @@ def what_if_analysis(topic_id, graph):
183
  blocked_labels = [graph.nodes[n].get('label',n) for n in blocked_by]
184
  return {'direct_unlocks': unlock_labels, 'all_unlocks': all_unlock_labels, 'blocked_by': blocked_labels, 'total_unlocked': len(unlocks)}
185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  def get_attention_weights(model, config, skill_seq, correct_seq, device):
187
  max_len=config['max_seq_len']; n_skills=config['num_skills']
188
  if len(skill_seq)>max_len: skill_seq=skill_seq[-max_len:]; correct_seq=correct_seq[-max_len:]
@@ -252,7 +305,9 @@ def main():
252
  }).sort_values('Mastery', ascending=False).head(10)
253
  st.markdown('**πŸ“ˆ Simulated Learner Mastery Signal (top 10 topics):**')
254
  st.bar_chart(mastery_df.set_index('Topic'))
255
- n_mastered = sum(1 for s in scores if s >= threshold)
 
 
256
  st.success(f'Learner simulation complete β€” {n_mastered}/{n_topics} topics above mastery threshold')
257
  if st.button('πŸš€ Generate Recommendations', type='primary'):
258
  output=pipeline.run(mastery_vector)
 
120
  prereqs = list(self.graph.predecessors(topic_id))
121
  readiness = 1.0 if not prereqs else sum(1 for p in prereqs if mastery_vector.is_mastered(p))/len(prereqs)
122
  downstream = self._downstream.get(topic_id, 0.0)
123
+ # Near-mastery boost: topics the student has already started
124
+ # rank higher than untouched topics with the same gap score
125
+ near_mastery_boost = 0.0
126
+ if 0.10 <= current < self.threshold:
127
+ near_mastery_boost = 0.15 * (current / self.threshold)
128
+ return round(self.w_gap*gap + self.w_ready*readiness + self.w_downstream*downstream + near_mastery_boost, 3)
129
 
130
  class LearningRecommendationPipeline:
131
  def __init__(self, graph, threshold=0.70, soft_threshold=0.50, top_n=5):
 
188
  blocked_labels = [graph.nodes[n].get('label',n) for n in blocked_by]
189
  return {'direct_unlocks': unlock_labels, 'all_unlocks': all_unlock_labels, 'blocked_by': blocked_labels, 'total_unlocked': len(unlocks)}
190
 
191
+ def cascade_mastery(mastery_vector, graph):
192
+ """
193
+ If a student has high mastery on a topic, infer that their
194
+ prerequisites are also likely mastered (propagate upward).
195
+ A student who scores 80% on Modular Arithmetic almost certainly
196
+ knows Whole Numbers β€” cascade fills these realistic gaps.
197
+ """
198
+ changed = True
199
+ while changed:
200
+ changed = False
201
+ for node in graph.nodes:
202
+ node_mastery = mastery_vector.get_mastery(node)
203
+ if node_mastery < 0.40:
204
+ continue
205
+ # For each prerequisite of this node
206
+ for prereq in graph.predecessors(node):
207
+ prereq_mastery = mastery_vector.get_mastery(prereq)
208
+ # Infer prerequisite mastery as at least 85% of descendant mastery
209
+ inferred = min(node_mastery * 0.85, 0.95)
210
+ if inferred > prereq_mastery:
211
+ mastery_vector.update(prereq, inferred)
212
+ changed = True
213
+ return mastery_vector
214
+
215
+ def cascade_mastery(mastery_vector, graph):
216
+ """
217
+ If a student has high mastery on a topic, infer that their
218
+ prerequisites are also likely mastered (propagate upward).
219
+ A student who scores 80% on Modular Arithmetic almost certainly
220
+ knows Whole Numbers β€” cascade fills these realistic gaps.
221
+ """
222
+ changed = True
223
+ while changed:
224
+ changed = False
225
+ for node in graph.nodes:
226
+ node_mastery = mastery_vector.get_mastery(node)
227
+ if node_mastery < 0.40:
228
+ continue
229
+ # For each prerequisite of this node
230
+ for prereq in graph.predecessors(node):
231
+ prereq_mastery = mastery_vector.get_mastery(prereq)
232
+ # Infer prerequisite mastery as at least 85% of descendant mastery
233
+ inferred = min(node_mastery * 0.85, 0.95)
234
+ if inferred > prereq_mastery:
235
+ mastery_vector.update(prereq, inferred)
236
+ changed = True
237
+ return mastery_vector
238
+
239
  def get_attention_weights(model, config, skill_seq, correct_seq, device):
240
  max_len=config['max_seq_len']; n_skills=config['num_skills']
241
  if len(skill_seq)>max_len: skill_seq=skill_seq[-max_len:]; correct_seq=correct_seq[-max_len:]
 
305
  }).sort_values('Mastery', ascending=False).head(10)
306
  st.markdown('**πŸ“ˆ Simulated Learner Mastery Signal (top 10 topics):**')
307
  st.bar_chart(mastery_df.set_index('Topic'))
308
+ # Cascade mastery upward through DAG
309
+ mastery_vector = cascade_mastery(mastery_vector, graph)
310
+ n_mastered = sum(1 for t in topic_nodes if mastery_vector.is_mastered(t))
311
  st.success(f'Learner simulation complete β€” {n_mastered}/{n_topics} topics above mastery threshold')
312
  if st.button('πŸš€ Generate Recommendations', type='primary'):
313
  output=pipeline.run(mastery_vector)