Gyan.AI / src /services /learning_service.py
cryogenic22's picture
Create learning_service.py
e205871 verified
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']}")