markobinario commited on
Commit
9a83ce6
·
verified ·
1 Parent(s): 8ad66f6

Delete database_recommender.py

Browse files
Files changed (1) hide show
  1. database_recommender.py +0 -336
database_recommender.py DELETED
@@ -1,336 +0,0 @@
1
- import pandas as pd
2
- import numpy as np
3
- from sklearn.neighbors import KNeighborsClassifier
4
- from sklearn.preprocessing import LabelEncoder, StandardScaler
5
- import joblib
6
- import json
7
- import os
8
- import requests
9
-
10
- class CourseRecommender:
11
- def __init__(self):
12
- self.model = None
13
- self.label_encoders = {}
14
- self.scaler = StandardScaler()
15
- self.courses = self.get_courses()
16
- self.training_data = self.get_training_data()
17
- self.train_model()
18
-
19
- def get_courses(self):
20
- """Get static course data"""
21
- return {
22
- 'BSCS': 'Bachelor of Science in Computer Science',
23
- 'BSIT': 'Bachelor of Science in Information Technology',
24
- 'BSBA': 'Bachelor of Science in Business Administration',
25
- 'BSED': 'Bachelor of Science in Education',
26
- 'BSN': 'Bachelor of Science in Nursing',
27
- 'BSArch': 'Bachelor of Science in Architecture',
28
- 'BSIE': 'Bachelor of Science in Industrial Engineering',
29
- 'BSHM': 'Bachelor of Science in Hospitality Management',
30
- 'BSA': 'Bachelor of Science in Accountancy',
31
- 'BSPsych': 'Bachelor of Science in Psychology',
32
- 'BSAgri': 'Bachelor of Science in Agriculture'
33
- }
34
-
35
- def save_student_data(self, stanine, gwa, strand, course, rating, hobbies=None):
36
- """Save student feedback to in-memory storage (for demonstration purposes)"""
37
- try:
38
- # In a real implementation, you could save this to a file or external storage
39
- print(f"Student feedback saved: Stanine={stanine}, GWA={gwa}, Strand={strand}, Course={course}, Rating={rating}, Hobbies={hobbies}")
40
- return True
41
- except Exception as e:
42
- print(f"Error saving student feedback: {e}")
43
- return False
44
-
45
- def get_training_data(self):
46
- """Get static training data for demonstration purposes"""
47
- # Sample training data to demonstrate the recommender system
48
- training_data = [
49
- # STEM students
50
- (8, 95, 'STEM', 'BSCS', 5, 'programming, gaming, technology'),
51
- (7, 90, 'STEM', 'BSIT', 4, 'computers, software, coding'),
52
- (9, 98, 'STEM', 'BSCS', 5, 'programming, algorithms, math'),
53
- (6, 85, 'STEM', 'BSIT', 3, 'technology, computers'),
54
- (8, 92, 'STEM', 'BSArch', 4, 'design, drawing, creativity'),
55
- (7, 88, 'STEM', 'BSIE', 4, 'engineering, problem solving'),
56
-
57
- # ABM students
58
- (8, 90, 'ABM', 'BSBA', 5, 'business, management, leadership'),
59
- (7, 85, 'ABM', 'BSA', 4, 'accounting, numbers, finance'),
60
- (6, 82, 'ABM', 'BSBA', 3, 'business, marketing'),
61
- (9, 95, 'ABM', 'BSA', 5, 'accounting, finance, analysis'),
62
-
63
- # HUMSS students
64
- (8, 88, 'HUMSS', 'BSED', 5, 'teaching, helping, education'),
65
- (7, 85, 'HUMSS', 'BSPsych', 4, 'psychology, helping, people'),
66
- (6, 80, 'HUMSS', 'BSED', 3, 'teaching, children'),
67
- (9, 92, 'HUMSS', 'BSPsych', 5, 'psychology, counseling, people'),
68
-
69
- # General interests
70
- (7, 87, 'STEM', 'BSN', 4, 'helping, healthcare, caring'),
71
- (8, 89, 'ABM', 'BSHM', 4, 'hospitality, service, management'),
72
- (6, 83, 'HUMSS', 'BSAgri', 3, 'agriculture, environment, nature'),
73
- ]
74
-
75
- return pd.DataFrame(training_data, columns=['stanine', 'gwa', 'strand', 'course', 'rating', 'hobbies'])
76
-
77
- def train_model(self):
78
- """Train the recommendation model using the training data"""
79
- try:
80
- training_data = self.get_training_data()
81
-
82
- if training_data.empty:
83
- print("No training data available - using default recommendations")
84
- return
85
-
86
- # Prepare features (hobbies required)
87
- feature_columns = ['stanine', 'gwa', 'strand', 'hobbies']
88
-
89
- # Create feature matrix
90
- X = training_data[feature_columns].copy()
91
- y = training_data['course']
92
-
93
- # Handle categorical variables
94
- categorical_columns = ['strand', 'hobbies']
95
-
96
- # Refit encoders every training to incorporate new categories
97
- for col in categorical_columns:
98
- if col in X.columns:
99
- X[col] = X[col].fillna('unknown')
100
- self.label_encoders[col] = LabelEncoder()
101
- X[col] = self.label_encoders[col].fit_transform(X[col])
102
-
103
- # Scale numerical features
104
- numerical_columns = ['stanine', 'gwa']
105
- if not X[numerical_columns].empty:
106
- X[numerical_columns] = self.scaler.fit_transform(X[numerical_columns])
107
-
108
- # Train KNN model
109
- self.model = KNeighborsClassifier(n_neighbors=3, weights='distance')
110
- self.model.fit(X, y)
111
-
112
- print("✅ Model trained successfully (hobbies required and encoded)")
113
-
114
- except Exception as e:
115
- print(f"Error training model: {e}")
116
- self.model = None
117
-
118
- def get_default_recommendations(self, stanine, gwa, strand):
119
- """Provide default recommendations based on basic rules when no training data is available"""
120
- courses = self.courses
121
- recommendations = []
122
-
123
- # Basic rules for recommendations
124
- if strand == 'STEM':
125
- if stanine >= 8 and gwa >= 90:
126
- priority_courses = ['BSCS', 'BSIT']
127
- else:
128
- priority_courses = ['BSIT', 'BSCS']
129
- elif strand == 'ABM':
130
- priority_courses = ['BSBA']
131
- elif strand == 'HUMSS':
132
- priority_courses = ['BSED']
133
- else:
134
- priority_courses = list(courses.keys())
135
-
136
- # Add courses with default probabilities
137
- for i, course in enumerate(priority_courses[:2]): # Only take top 2
138
- if course in courses:
139
- recommendations.append({
140
- 'code': course,
141
- 'name': courses[course],
142
- 'probability': 1.0 - (i * 0.2) # Decreasing probability for each course
143
- })
144
-
145
- return recommendations
146
-
147
- def recommend_courses(self, stanine, gwa, strand, hobbies=None, top_n=5):
148
- """Recommend courses based on student profile (hobbies required)"""
149
- try:
150
- if self.model is None:
151
- return self.get_default_recommendations(stanine, gwa, strand)
152
-
153
- # Prepare input features
154
- input_data = pd.DataFrame([{
155
- 'stanine': stanine,
156
- 'gwa': gwa,
157
- 'strand': strand,
158
- 'hobbies': (hobbies or '').strip()
159
- }])
160
- # Validate hobbies
161
- if not input_data['hobbies'].iloc[0]:
162
- raise ValueError('hobbies is required for recommendations')
163
-
164
- # Encode categorical variables
165
- for col in ['strand', 'hobbies']:
166
- if col in input_data.columns and col in self.label_encoders:
167
- value = input_data[col].iloc[0]
168
- if value not in self.label_encoders[col].classes_:
169
- # Extend encoder classes to include unseen value at inference
170
- self.label_encoders[col].classes_ = np.append(self.label_encoders[col].classes_, value)
171
- input_data[col] = self.label_encoders[col].transform(input_data[col])
172
-
173
- # Scale numerical features
174
- numerical_columns = ['stanine', 'gwa']
175
- if not input_data[numerical_columns].empty:
176
- input_data[numerical_columns] = self.scaler.transform(input_data[numerical_columns])
177
-
178
- # Get predictions
179
- predictions = self.model.predict_proba(input_data)
180
- courses = self.model.classes_
181
-
182
- # Get top recommendations
183
- top_indices = np.argsort(predictions[0])[-top_n:][::-1]
184
- recommendations = []
185
-
186
- course_map = self.courses
187
- for idx in top_indices:
188
- code = courses[idx]
189
- confidence = predictions[0][idx]
190
- recommendations.append({
191
- 'code': code,
192
- 'name': course_map.get(code, code),
193
- 'rating': round(confidence * 100, 1)
194
- })
195
-
196
- return recommendations
197
-
198
- except Exception as e:
199
- print(f"Error recommending courses: {e}")
200
- return self.get_default_recommendations(stanine, gwa, strand)
201
-
202
- def _get_recommendation_reason(self, course, stanine, gwa, strand, hobbies, interests, personality_type, learning_style, career_goals):
203
- """Generate personalized reason for recommendation"""
204
- reasons = []
205
-
206
- # Academic performance reasons
207
- if stanine >= 8:
208
- reasons.append("Excellent academic performance")
209
- elif stanine >= 6:
210
- reasons.append("Good academic foundation")
211
-
212
- if gwa >= 85:
213
- reasons.append("High academic achievement")
214
- elif gwa >= 80:
215
- reasons.append("Strong academic record")
216
-
217
- # Strand alignment
218
- if strand == "STEM" and course in ["BSCS", "BSIT", "BSArch", "BSIE", "BSN"]:
219
- reasons.append("Perfect match with your STEM background")
220
- elif strand == "ABM" and course in ["BSBA", "BSA"]:
221
- reasons.append("Excellent alignment with your ABM strand")
222
- elif strand == "HUMSS" and course in ["BSED", "BSPsych"]:
223
- reasons.append("Great fit with your HUMSS background")
224
-
225
- # Hobbies and interests alignment
226
- if hobbies and any(hobby in hobbies.lower() for hobby in ["gaming", "programming", "technology", "computers"]):
227
- if course in ["BSCS", "BSIT"]:
228
- reasons.append("Matches your technology interests")
229
-
230
- if hobbies and any(hobby in hobbies.lower() for hobby in ["business", "leadership", "management"]):
231
- if course in ["BSBA", "BSA"]:
232
- reasons.append("Aligns with your business interests")
233
-
234
- if hobbies and any(hobby in hobbies.lower() for hobby in ["helping", "teaching", "caring"]):
235
- if course in ["BSED", "BSN", "BSPsych"]:
236
- reasons.append("Perfect for your helping nature")
237
-
238
- # Personality type alignment
239
- if personality_type == "introvert" and course in ["BSCS", "BSA", "BSArch"]:
240
- reasons.append("Suits your introverted personality")
241
- elif personality_type == "extrovert" and course in ["BSBA", "BSED", "BSHM"]:
242
- reasons.append("Great for your outgoing personality")
243
-
244
- # Learning style alignment
245
- if learning_style == "hands-on" and course in ["BSIT", "BSHM", "BSAgri"]:
246
- reasons.append("Matches your hands-on learning preference")
247
- elif learning_style == "visual" and course in ["BSArch", "BSCS"]:
248
- reasons.append("Perfect for your visual learning style")
249
-
250
- # Career goals alignment
251
- if career_goals and any(goal in career_goals.lower() for goal in ["developer", "programmer", "software"]):
252
- if course in ["BSCS", "BSIT"]:
253
- reasons.append("Direct path to your career goals")
254
-
255
- if career_goals and any(goal in career_goals.lower() for goal in ["business", "entrepreneur", "manager"]):
256
- if course in ["BSBA", "BSA"]:
257
- reasons.append("Direct path to your business goals")
258
-
259
- # Default reason if no specific matches
260
- if not reasons:
261
- reasons.append("Good academic and personal fit")
262
-
263
- return " • ".join(reasons[:3]) # Limit to top 3 reasons
264
-
265
- def save_model(self, model_path='course_recommender_model.joblib'):
266
- """Save the trained model"""
267
- if self.model is None:
268
- raise Exception("No model to save!")
269
-
270
- model_data = {
271
- 'model': self.model,
272
- 'scaler': self.scaler,
273
- 'label_encoders': self.label_encoders
274
- }
275
- joblib.dump(model_data, model_path)
276
-
277
- def load_model(self, model_path='course_recommender_model.joblib'):
278
- """Load a trained model"""
279
- model_data = joblib.load(model_path)
280
- self.model = model_data['model']
281
- self.scaler = model_data['scaler']
282
- self.label_encoders = model_data['label_encoders']
283
-
284
-
285
- # ===== UI helper for Hugging Face integration =====
286
- def get_course_recommendations_ui(recommender: "CourseRecommender", stanine, gwa, strand, hobbies) -> str:
287
- if recommender is None:
288
- return "Sorry, the recommendation system is not available at the moment. Please try again later."
289
- try:
290
- try:
291
- stanine = int(stanine.strip()) if isinstance(stanine, str) else int(stanine)
292
- except (ValueError, TypeError, AttributeError):
293
- return "❌ Stanine score must be a valid number between 1 and 9"
294
- try:
295
- gwa = float(gwa.strip()) if isinstance(gwa, str) else float(gwa)
296
- except (ValueError, TypeError, AttributeError):
297
- return "❌ GWA must be a valid number between 75 and 100"
298
- if not (1 <= stanine <= 9):
299
- return "❌ Stanine score must be between 1 and 9"
300
- if not (75 <= gwa <= 100):
301
- return "❌ GWA must be between 75 and 100"
302
- if not strand:
303
- return "❌ Please select a strand"
304
- if not hobbies or not str(hobbies).strip():
305
- return "❌ Please enter your hobbies/interests"
306
-
307
- recommendations = recommender.recommend_courses(
308
- stanine=stanine,
309
- gwa=gwa,
310
- strand=strand,
311
- hobbies=str(hobbies)
312
- )
313
- if not recommendations:
314
- return "No recommendations available at the moment."
315
- response = f"## 🎯 Course Recommendations for You\n\n"
316
- response += f"**Profile:** Stanine {stanine}, GWA {gwa}, {strand} Strand\n"
317
- response += f"**Interests:** {hobbies}\n\n"
318
- for i, rec in enumerate(recommendations, 1):
319
- response += f"### {i}. {rec['code']} - {rec['name']}\n"
320
- response += f"**Match Score:** {rec.get('rating', rec.get('probability', 0)):.1f}%\n\n"
321
- return response
322
- except Exception as e:
323
- return f"❌ Error getting recommendations: {str(e)}"
324
-
325
- # Example usage
326
- if __name__ == "__main__":
327
- recommender = CourseRecommender()
328
-
329
- # Example recommendation
330
- recommendations = recommender.recommend_courses(
331
- stanine=8,
332
- gwa=95,
333
- strand='STEM',
334
- hobbies='programming, gaming, technology'
335
- )
336
- print("Recommended courses:", json.dumps(recommendations, indent=2))