File size: 6,468 Bytes
7644eac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
Educational resource handling for the AI Learning Path Generator.
Manages resource recommendation and categorization.
"""
from typing import List, Dict, Any, Optional
import json
from pathlib import Path

from src.ml.model_orchestrator import ModelOrchestrator
from src.utils.helpers import difficulty_to_score
from src.utils.config import RESOURCE_TYPES, LEARNING_STYLES

class ResourceManager:
    """
    Manages educational resources and recommendations.
    """
    def __init__(self, api_key: Optional[str] = None):
        """
        Initialize the resource manager.
        
        Args:
            api_key: Optional OpenAI API key
        """
        self.model_orchestrator = ModelOrchestrator(api_key)
        self.cached_resources = {}
    
    def recommend_resources(
        self,
        topic: str,
        learning_style: str,
        expertise_level: str,
        count: int = 5,
        resource_type: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """
        Recommend educational resources for a topic.
        
        Args:
            topic: The topic to find resources for
            learning_style: Preferred learning style
            expertise_level: User's expertise level
            count: Number of resources to recommend
            resource_type: Optional specific resource type
            
        Returns:
            List of resource recommendations
        """
        # Check cache first
        cache_key = f"{topic}_{learning_style}_{expertise_level}_{resource_type}"
        if cache_key in self.cached_resources:
            resources = self.cached_resources[cache_key]
            return resources[:count]
        
        # Generate resources using the model
        resources = self.model_orchestrator.generate_resource_recommendations(
            topic=topic,
            learning_style=learning_style,
            expertise_level=expertise_level,
            count=count
        )
        
        # Filter by resource type if specified
        if resource_type and resources:
            resources = [r for r in resources if r.get("type") == resource_type]
        
        # Cache the results
        self.cached_resources[cache_key] = resources
        
        return resources
    
    def categorize_by_learning_style(
        self,
        resources: List[Dict[str, Any]]
    ) -> Dict[str, List[Dict[str, Any]]]:
        """
        Categorize resources by most suitable learning style.
        
        Args:
            resources: List of resource dictionaries
            
        Returns:
            Dictionary of resources grouped by learning style
        """
        result = {style: [] for style in LEARNING_STYLES}
        
        for resource in resources:
            resource_type = resource.get("type", "article")
            
            # Find the learning style with highest score for this resource type
            best_style = "reading"  # Default
            best_score = 0
            
            if resource_type in RESOURCE_TYPES:
                for style, score in RESOURCE_TYPES[resource_type].items():
                    if score > best_score:
                        best_score = score
                        best_style = style
            
            # Add resource to the appropriate category
            result[best_style].append(resource)
        
        return result
    
    def load_curated_resources(
        self,
        file_path: str = "data/curated_resources.json"
    ) -> List[Dict[str, Any]]:
        """
        Load curated resources from a JSON file.
        
        Args:
            file_path: Path to the JSON file
            
        Returns:
            List of resource dictionaries
        """
        try:
            with open(file_path, "r") as f:
                resources = json.load(f)
                return resources
        except (FileNotFoundError, json.JSONDecodeError):
            return []
    
    def save_curated_resources(
        self,
        resources: List[Dict[str, Any]],
        file_path: str = "data/curated_resources.json"
    ) -> bool:
        """
        Save curated resources to a JSON file.
        
        Args:
            resources: List of resource dictionaries
            file_path: Path to save to
            
        Returns:
            Success status
        """
        try:
            # Ensure directory exists
            Path(file_path).parent.mkdir(exist_ok=True, parents=True)
            
            with open(file_path, "w") as f:
                json.dump(resources, f, indent=2)
            return True
        except Exception:
            return False
    
    def analyze_difficulty(self, resource: Dict[str, Any]) -> float:
        """
        Analyze the difficulty level of a resource.
        
        Args:
            resource: Resource dictionary with description
            
        Returns:
            Difficulty score between 0 and 1
        """
        # Try to extract difficulty from the resource directly
        if "difficulty" in resource:
            return difficulty_to_score(resource["difficulty"])
        
        # Analyze the description
        description = resource.get("description", "")
        if description:
            return self.model_orchestrator.analyze_difficulty(description)
        
        # Default to medium difficulty
        return 0.5
    
    def filter_by_difficulty(
        self,
        resources: List[Dict[str, Any]],
        max_difficulty: float = 1.0,
        min_difficulty: float = 0.0
    ) -> List[Dict[str, Any]]:
        """
        Filter resources by difficulty level.
        
        Args:
            resources: List of resource dictionaries
            max_difficulty: Maximum difficulty score (0-1)
            min_difficulty: Minimum difficulty score (0-1)
            
        Returns:
            Filtered list of resources
        """
        result = []
        
        for resource in resources:
            # Get or calculate difficulty score
            if "difficulty_score" in resource:
                score = float(resource["difficulty_score"])
            else:
                difficulty = resource.get("difficulty", "intermediate")
                score = difficulty_to_score(difficulty)
            
            # Add to result if within range
            if min_difficulty <= score <= max_difficulty:
                result.append(resource)
        
        return result