Spaces:
Build error
Build error
| from datetime import datetime | |
| from typing import Dict, List, Set | |
| import streamlit as st | |
| from src.utils.session import get_user_progress | |
| class LearningService: | |
| def __init__(self): | |
| self.load_curriculum() | |
| def load_curriculum(self): | |
| """Load the complete curriculum structure""" | |
| self.curriculum = { | |
| 'python_basics': { | |
| 'name': 'Python Programming Basics', | |
| 'description': 'Master the fundamental concepts of Python programming.', | |
| 'prerequisites': [], | |
| 'modules': [ | |
| { | |
| 'id': 'intro_python', | |
| 'name': 'Introduction to Python', | |
| 'concepts': ['programming_basics', 'python_environment', 'basic_syntax'], | |
| 'difficulty': 'beginner', | |
| 'estimated_hours': 2 | |
| }, | |
| { | |
| 'id': 'variables_types', | |
| 'name': 'Variables and Data Types', | |
| 'concepts': ['variables', 'numbers', 'strings', 'type_conversion'], | |
| 'difficulty': 'beginner', | |
| 'estimated_hours': 3 | |
| }, | |
| { | |
| 'id': 'control_flow', | |
| 'name': 'Control Flow', | |
| 'concepts': ['conditionals', 'loops', 'break_continue'], | |
| 'difficulty': 'beginner', | |
| 'estimated_hours': 4 | |
| }, | |
| { | |
| 'id': 'functions_basics', | |
| 'name': 'Functions', | |
| 'concepts': ['function_definition', 'parameters', 'return_values'], | |
| 'difficulty': 'beginner', | |
| 'estimated_hours': 4 | |
| } | |
| ] | |
| }, | |
| 'data_structures': { | |
| 'name': 'Data Structures', | |
| 'description': 'Learn essential Python data structures and their operations.', | |
| 'prerequisites': ['python_basics'], | |
| 'modules': [ | |
| { | |
| 'id': 'lists_tuples', | |
| 'name': 'Lists and Tuples', | |
| 'concepts': ['list_operations', 'tuple_basics', 'sequence_types'], | |
| 'difficulty': 'intermediate', | |
| 'estimated_hours': 4 | |
| }, | |
| { | |
| 'id': 'dictionaries', | |
| 'name': 'Dictionaries', | |
| 'concepts': ['dict_operations', 'key_value_pairs', 'dict_methods'], | |
| 'difficulty': 'intermediate', | |
| 'estimated_hours': 3 | |
| }, | |
| { | |
| 'id': 'sets', | |
| 'name': 'Sets', | |
| 'concepts': ['set_operations', 'set_methods', 'set_theory'], | |
| 'difficulty': 'intermediate', | |
| 'estimated_hours': 3 | |
| }, | |
| { | |
| 'id': 'advanced_ops', | |
| 'name': 'Advanced Operations', | |
| 'concepts': ['comprehensions', 'generators', 'iterators'], | |
| 'difficulty': 'intermediate', | |
| 'estimated_hours': 5 | |
| } | |
| ] | |
| } | |
| } | |
| def check_prerequisites(self, prerequisites: List[str]) -> bool: | |
| """Check if prerequisites are met""" | |
| state = get_user_progress() | |
| for prereq in prerequisites: | |
| prereq_modules = {m['id'] for m in self.curriculum[prereq]['modules']} | |
| if not prereq_modules.issubset(state['completed_modules']): | |
| return False | |
| return True | |
| def get_path_progress(self, path_id: str) -> float: | |
| """Get progress percentage for a path""" | |
| state = get_user_progress() | |
| path_modules = {m['id'] for m in self.curriculum[path_id]['modules']} | |
| completed = path_modules.intersection(state['completed_modules']) | |
| return len(completed) / len(path_modules) | |
| def is_module_completed(self, module_id: str) -> bool: | |
| """Check if a module is completed""" | |
| state = get_user_progress() | |
| return module_id in state['completed_modules'] | |
| def get_concept_mastery(self, concept: str) -> float: | |
| """Get mastery level for a concept""" | |
| state = get_user_progress() | |
| return state['mastery_levels'].get(concept, 0.0) | |
| def format_mastery(self, mastery: float) -> str: | |
| """Format mastery level for display""" | |
| if mastery >= 0.8: | |
| return "π Mastered" | |
| elif mastery >= 0.5: | |
| return "π In Progress" | |
| else: | |
| return "πΈ Not Started" | |
| def start_module(self, module_id: str, path_id: str): | |
| """Start a learning module""" | |
| state = get_user_progress() | |
| state['current_module'] = module_id | |
| state['current_path'] = path_id | |
| self.update_learning_streak() | |
| def complete_module(self, module_id: str, path_id: str): | |
| """Complete a learning module""" | |
| state = get_user_progress() | |
| # Mark module as completed | |
| state['completed_modules'].add(module_id) | |
| # Update concept mastery | |
| module = next(m for m in self.curriculum[path_id]['modules'] | |
| if m['id'] == module_id) | |
| for concept in module['concepts']: | |
| self.update_concept_mastery(concept) | |
| # Check for achievements | |
| self.check_achievements(module_id, path_id) | |
| # Update streak | |
| self.update_learning_streak() | |
| def update_concept_mastery(self, concept: str, score: float = 0.8): | |
| """Update mastery level for a concept""" | |
| state = get_user_progress() | |
| current = state['mastery_levels'].get(concept, 0.0) | |
| state['mastery_levels'][concept] = min(1.0, current + score) | |
| def launch_quiz(self, module_id: str): | |
| """Initialize module quiz""" | |
| st.session_state.quiz_active = True | |
| st.session_state.current_quiz_module = module_id | |
| def update_learning_streak(self): | |
| """Update learning streak""" | |
| state = get_user_progress() | |
| today = datetime.now().date() | |
| if state['last_active'] is None: | |
| state['learning_streak'] = 1 | |
| else: | |
| last_active = datetime.strptime(state['last_active'], "%Y-%m-%d").date() | |
| if (today - last_active).days == 1: | |
| state['learning_streak'] += 1 | |
| elif (today - last_active).days > 1: | |
| state['learning_streak'] = 1 | |
| state['last_active'] = today.strftime("%Y-%m-%d") | |
| def check_achievements(self, module_id: str, path_id: str): | |
| """Check and award achievements""" | |
| state = get_user_progress() | |
| new_achievements = [] | |
| # First module achievement | |
| if len(state['completed_modules']) == 1: | |
| new_achievements.append({ | |
| 'name': 'First Steps! π', | |
| 'description': 'Completed your first module', | |
| 'date': datetime.now().strftime("%Y-%m-%d") | |
| }) | |
| # Path completion achievement | |
| path_modules = {m['id'] for m in self.curriculum[path_id]['modules']} | |
| if path_modules.issubset(state['completed_modules']): | |
| new_achievements.append({ | |
| 'name': f'Path Master: {self.curriculum[path_id]["name"]} π', | |
| 'description': f'Completed the entire {self.curriculum[path_id]["name"]} path', | |
| 'date': datetime.now().strftime("%Y-%m-%d") | |
| }) | |
| # Learning streak achievements | |
| streak_achievements = { | |
| 7: 'Week Warrior! ποΈ', | |
| 30: 'Monthly Master! π ', | |
| 100: 'Centurion! π―' | |
| } | |
| for days, name in streak_achievements.items(): | |
| if state['learning_streak'] >= days: | |
| achievement_exists = any(a['name'] == name for a in state['achievements']) | |
| if not achievement_exists: | |
| new_achievements.append({ | |
| 'name': name, | |
| 'description': f'Maintained a {days}-day learning streak', | |
| 'date': datetime.now().strftime("%Y-%m-%d") | |
| }) | |
| # Add and display new achievements | |
| for achievement in new_achievements: | |
| if achievement not in state['achievements']: | |
| state['achievements'].append(achievement) | |
| st.balloons() | |
| st.success(f"π New Achievement: {achievement['name']} - {achievement['description']}") |