cryogenic22 commited on
Commit
e205871
Β·
verified Β·
1 Parent(s): ce2143e

Create learning_service.py

Browse files
Files changed (1) hide show
  1. src/services/learning_service.py +217 -0
src/services/learning_service.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from typing import Dict, List, Set
3
+ import streamlit as st
4
+ from src.utils.session import get_user_progress
5
+
6
+ class LearningService:
7
+ def __init__(self):
8
+ self.load_curriculum()
9
+
10
+ def load_curriculum(self):
11
+ """Load the complete curriculum structure"""
12
+ self.curriculum = {
13
+ 'python_basics': {
14
+ 'name': 'Python Programming Basics',
15
+ 'description': 'Master the fundamental concepts of Python programming.',
16
+ 'prerequisites': [],
17
+ 'modules': [
18
+ {
19
+ 'id': 'intro_python',
20
+ 'name': 'Introduction to Python',
21
+ 'concepts': ['programming_basics', 'python_environment', 'basic_syntax'],
22
+ 'difficulty': 'beginner',
23
+ 'estimated_hours': 2
24
+ },
25
+ {
26
+ 'id': 'variables_types',
27
+ 'name': 'Variables and Data Types',
28
+ 'concepts': ['variables', 'numbers', 'strings', 'type_conversion'],
29
+ 'difficulty': 'beginner',
30
+ 'estimated_hours': 3
31
+ },
32
+ {
33
+ 'id': 'control_flow',
34
+ 'name': 'Control Flow',
35
+ 'concepts': ['conditionals', 'loops', 'break_continue'],
36
+ 'difficulty': 'beginner',
37
+ 'estimated_hours': 4
38
+ },
39
+ {
40
+ 'id': 'functions_basics',
41
+ 'name': 'Functions',
42
+ 'concepts': ['function_definition', 'parameters', 'return_values'],
43
+ 'difficulty': 'beginner',
44
+ 'estimated_hours': 4
45
+ }
46
+ ]
47
+ },
48
+ 'data_structures': {
49
+ 'name': 'Data Structures',
50
+ 'description': 'Learn essential Python data structures and their operations.',
51
+ 'prerequisites': ['python_basics'],
52
+ 'modules': [
53
+ {
54
+ 'id': 'lists_tuples',
55
+ 'name': 'Lists and Tuples',
56
+ 'concepts': ['list_operations', 'tuple_basics', 'sequence_types'],
57
+ 'difficulty': 'intermediate',
58
+ 'estimated_hours': 4
59
+ },
60
+ {
61
+ 'id': 'dictionaries',
62
+ 'name': 'Dictionaries',
63
+ 'concepts': ['dict_operations', 'key_value_pairs', 'dict_methods'],
64
+ 'difficulty': 'intermediate',
65
+ 'estimated_hours': 3
66
+ },
67
+ {
68
+ 'id': 'sets',
69
+ 'name': 'Sets',
70
+ 'concepts': ['set_operations', 'set_methods', 'set_theory'],
71
+ 'difficulty': 'intermediate',
72
+ 'estimated_hours': 3
73
+ },
74
+ {
75
+ 'id': 'advanced_ops',
76
+ 'name': 'Advanced Operations',
77
+ 'concepts': ['comprehensions', 'generators', 'iterators'],
78
+ 'difficulty': 'intermediate',
79
+ 'estimated_hours': 5
80
+ }
81
+ ]
82
+ }
83
+ }
84
+
85
+ def check_prerequisites(self, prerequisites: List[str]) -> bool:
86
+ """Check if prerequisites are met"""
87
+ state = get_user_progress()
88
+ for prereq in prerequisites:
89
+ prereq_modules = {m['id'] for m in self.curriculum[prereq]['modules']}
90
+ if not prereq_modules.issubset(state['completed_modules']):
91
+ return False
92
+ return True
93
+
94
+ def get_path_progress(self, path_id: str) -> float:
95
+ """Get progress percentage for a path"""
96
+ state = get_user_progress()
97
+ path_modules = {m['id'] for m in self.curriculum[path_id]['modules']}
98
+ completed = path_modules.intersection(state['completed_modules'])
99
+ return len(completed) / len(path_modules)
100
+
101
+ def is_module_completed(self, module_id: str) -> bool:
102
+ """Check if a module is completed"""
103
+ state = get_user_progress()
104
+ return module_id in state['completed_modules']
105
+
106
+ def get_concept_mastery(self, concept: str) -> float:
107
+ """Get mastery level for a concept"""
108
+ state = get_user_progress()
109
+ return state['mastery_levels'].get(concept, 0.0)
110
+
111
+ def format_mastery(self, mastery: float) -> str:
112
+ """Format mastery level for display"""
113
+ if mastery >= 0.8:
114
+ return "🌟 Mastered"
115
+ elif mastery >= 0.5:
116
+ return "πŸ“ˆ In Progress"
117
+ else:
118
+ return "πŸ”Έ Not Started"
119
+
120
+ def start_module(self, module_id: str, path_id: str):
121
+ """Start a learning module"""
122
+ state = get_user_progress()
123
+ state['current_module'] = module_id
124
+ state['current_path'] = path_id
125
+ self.update_learning_streak()
126
+
127
+ def complete_module(self, module_id: str, path_id: str):
128
+ """Complete a learning module"""
129
+ state = get_user_progress()
130
+
131
+ # Mark module as completed
132
+ state['completed_modules'].add(module_id)
133
+
134
+ # Update concept mastery
135
+ module = next(m for m in self.curriculum[path_id]['modules']
136
+ if m['id'] == module_id)
137
+ for concept in module['concepts']:
138
+ self.update_concept_mastery(concept)
139
+
140
+ # Check for achievements
141
+ self.check_achievements(module_id, path_id)
142
+
143
+ # Update streak
144
+ self.update_learning_streak()
145
+
146
+ def update_concept_mastery(self, concept: str, score: float = 0.8):
147
+ """Update mastery level for a concept"""
148
+ state = get_user_progress()
149
+ current = state['mastery_levels'].get(concept, 0.0)
150
+ state['mastery_levels'][concept] = min(1.0, current + score)
151
+
152
+ def launch_quiz(self, module_id: str):
153
+ """Initialize module quiz"""
154
+ st.session_state.quiz_active = True
155
+ st.session_state.current_quiz_module = module_id
156
+
157
+ def update_learning_streak(self):
158
+ """Update learning streak"""
159
+ state = get_user_progress()
160
+ today = datetime.now().date()
161
+
162
+ if state['last_active'] is None:
163
+ state['learning_streak'] = 1
164
+ else:
165
+ last_active = datetime.strptime(state['last_active'], "%Y-%m-%d").date()
166
+ if (today - last_active).days == 1:
167
+ state['learning_streak'] += 1
168
+ elif (today - last_active).days > 1:
169
+ state['learning_streak'] = 1
170
+
171
+ state['last_active'] = today.strftime("%Y-%m-%d")
172
+
173
+ def check_achievements(self, module_id: str, path_id: str):
174
+ """Check and award achievements"""
175
+ state = get_user_progress()
176
+ new_achievements = []
177
+
178
+ # First module achievement
179
+ if len(state['completed_modules']) == 1:
180
+ new_achievements.append({
181
+ 'name': 'First Steps! πŸŽ‰',
182
+ 'description': 'Completed your first module',
183
+ 'date': datetime.now().strftime("%Y-%m-%d")
184
+ })
185
+
186
+ # Path completion achievement
187
+ path_modules = {m['id'] for m in self.curriculum[path_id]['modules']}
188
+ if path_modules.issubset(state['completed_modules']):
189
+ new_achievements.append({
190
+ 'name': f'Path Master: {self.curriculum[path_id]["name"]} πŸ†',
191
+ 'description': f'Completed the entire {self.curriculum[path_id]["name"]} path',
192
+ 'date': datetime.now().strftime("%Y-%m-%d")
193
+ })
194
+
195
+ # Learning streak achievements
196
+ streak_achievements = {
197
+ 7: 'Week Warrior! πŸ—“οΈ',
198
+ 30: 'Monthly Master! πŸ“…',
199
+ 100: 'Centurion! πŸ’―'
200
+ }
201
+
202
+ for days, name in streak_achievements.items():
203
+ if state['learning_streak'] >= days:
204
+ achievement_exists = any(a['name'] == name for a in state['achievements'])
205
+ if not achievement_exists:
206
+ new_achievements.append({
207
+ 'name': name,
208
+ 'description': f'Maintained a {days}-day learning streak',
209
+ 'date': datetime.now().strftime("%Y-%m-%d")
210
+ })
211
+
212
+ # Add and display new achievements
213
+ for achievement in new_achievements:
214
+ if achievement not in state['achievements']:
215
+ state['achievements'].append(achievement)
216
+ st.balloons()
217
+ st.success(f"πŸ† New Achievement: {achievement['name']} - {achievement['description']}")