markobinario commited on
Commit
81da528
Β·
verified Β·
1 Parent(s): a9342f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +359 -72
app.py CHANGED
@@ -1,80 +1,367 @@
1
- import requests
2
  import pandas as pd
3
- from typing import Dict, List, Optional
4
- import json
 
 
5
 
6
- class DatabaseConnection:
7
- def __init__(self, base_url: str = "https://database-dhe2.onrender.com"):
8
- self.base_url = base_url
9
- self.session = requests.Session()
 
 
 
 
 
 
 
10
 
11
- def get_student_feedback_counts(self) -> pd.DataFrame:
12
- """Fetch student feedback data from the database"""
13
- try:
14
- url = f"{self.base_url}/student_feedback_counts"
15
- response = self.session.get(url)
16
- response.raise_for_status()
17
-
18
- data = response.json()
19
- if isinstance(data, list):
20
- return pd.DataFrame(data)
21
- elif isinstance(data, dict) and 'feedback_counts' in data:
22
- # Handle nested structure
23
- feedback_data = data['feedback_counts']
24
- if isinstance(feedback_data, list):
25
- return pd.DataFrame(feedback_data)
26
- else:
27
- return pd.DataFrame([feedback_data])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  else:
29
- return pd.DataFrame([data])
30
- except Exception as e:
31
- print(f"Error fetching data: {e}")
32
- return pd.DataFrame()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- def add_feedback(self, course: str, stanine: int, gwa: float, strand: str,
35
- rating: str, hobbies: str) -> bool:
36
- """Add new feedback to the database"""
37
- print(f"Attempting to add feedback: {course}, rating: {rating}")
38
-
39
- # For now, let's simulate successful feedback addition
40
- # since the API endpoint seems to have issues
41
- print(f"[OK] Feedback simulated: {course} - {rating}")
42
- return True
43
-
44
- # TODO: Fix the actual API endpoint to accept the correct data structure
45
- # The current API expects different fields than what we're sending
46
 
47
- def update_feedback_count(self, feedback_id: int, count: int) -> bool:
48
- """Update the count for existing feedback"""
49
- try:
50
- url = f"{self.base_url}/student_feedback_counts/{feedback_id}"
51
- data = {"count": count}
52
- response = self.session.put(url, json=data)
53
- response.raise_for_status()
54
- return True
55
- except Exception as e:
56
- print(f"Error updating feedback count: {e}")
57
- return False
58
 
59
- def get_available_courses(self) -> List[str]:
60
- """Fetch available courses from the database"""
61
- try:
62
- url = f"{self.base_url}/courses"
63
- response = self.session.get(url)
64
- response.raise_for_status()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
- data = response.json()
67
- if isinstance(data, list):
68
- # Extract course names from the data
69
- courses = []
70
- for item in data:
71
- if isinstance(item, dict) and 'name' in item:
72
- courses.append(item['name'])
73
- elif isinstance(item, str):
74
- courses.append(item)
75
- return courses
76
- else:
77
- return []
78
- except Exception as e:
79
- print(f"Error fetching courses: {e}")
80
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
  import pandas as pd
3
+ import numpy as np
4
+ from course_recommender import CourseRecommender
5
+ from database_connection import DatabaseConnection
6
+ import os
7
 
8
+ # Global variables to store current recommendations
9
+ current_recommendations = []
10
+ current_user_input = {}
11
+
12
+ # Initialize components with error handling
13
+ recommender = None
14
+ db_connection = None
15
+
16
+ def initialize_components():
17
+ """Initialize the recommender system and database connection with error handling"""
18
+ global recommender, db_connection
19
 
20
+ try:
21
+ if recommender is None:
22
+ recommender = CourseRecommender()
23
+ print("βœ… CourseRecommender initialized")
24
+ except Exception as e:
25
+ print(f"⚠️ Warning: Could not initialize CourseRecommender: {e}")
26
+ # Create a minimal fallback
27
+ recommender = None
28
+
29
+ try:
30
+ if db_connection is None:
31
+ db_connection = DatabaseConnection()
32
+ print("βœ… DatabaseConnection initialized")
33
+ except Exception as e:
34
+ print(f"⚠️ Warning: Could not initialize DatabaseConnection: {e}")
35
+ # Create a minimal fallback
36
+ db_connection = None
37
+
38
+ # Initialize components
39
+ initialize_components()
40
+
41
+ def get_course_recommendations(stanine, gwa, strand, hobbies):
42
+ """Get course recommendations based on user input"""
43
+ global current_recommendations, current_user_input, recommender
44
+
45
+ # Check if recommender is initialized
46
+ if recommender is None:
47
+ return "❌ System not properly initialized. Please try again.", "", "", "", "", ""
48
+
49
+ # Validate inputs
50
+ if not stanine or not gwa or not strand or not hobbies:
51
+ return "Please fill in all fields", "", "", "", "", ""
52
+
53
+ try:
54
+ stanine = int(stanine)
55
+ gwa = float(gwa)
56
+
57
+ if stanine < 1 or stanine > 9:
58
+ return "Stanine must be between 1-9", "", "", "", "", ""
59
+
60
+ if gwa < 75 or gwa > 100:
61
+ return "GWA must be between 75-100", "", "", "", "", ""
62
+
63
+ # Normalize strand to uppercase for case-insensitive matching
64
+ strand = strand.upper()
65
+
66
+ if strand not in ["STEM", "ABM", "HUMSS", "GAS", "TVL"]:
67
+ return "Strand must be one of: STEM, ABM, HUMSS, GAS, TVL", "", "", "", "", ""
68
+
69
+ # Store current user input
70
+ current_user_input = {
71
+ 'stanine': stanine,
72
+ 'gwa': gwa,
73
+ 'strand': strand,
74
+ 'hobbies': hobbies
75
+ }
76
+
77
+ # Get recommendations
78
+ recommendations = recommender.predict_course(stanine, gwa, strand, hobbies)
79
+ current_recommendations = recommendations
80
+
81
+ # Format top 3 recommendations
82
+ if len(recommendations) >= 3:
83
+ course1 = f"{recommendations[0][0]} (Confidence: {recommendations[0][1]*100:.1f}%)"
84
+ course2 = f"{recommendations[1][0]} (Confidence: {recommendations[1][1]*100:.1f}%)"
85
+ course3 = f"{recommendations[2][0]} (Confidence: {recommendations[2][1]*100:.1f}%)"
86
+ elif len(recommendations) == 2:
87
+ course1 = f"{recommendations[0][0]} (Confidence: {recommendations[0][1]*100:.1f}%)"
88
+ course2 = f"{recommendations[1][0]} (Confidence: {recommendations[1][1]*100:.1f}%)"
89
+ course3 = "No third recommendation available"
90
+ elif len(recommendations) == 1:
91
+ course1 = f"{recommendations[0][0]} (Confidence: {recommendations[0][1]*100:.1f}%)"
92
+ course2 = "No second recommendation available"
93
+ course3 = "No third recommendation available"
94
+ else:
95
+ course1 = "No recommendations available"
96
+ course2 = ""
97
+ course3 = ""
98
+
99
+ return course1, course2, course3, None, None, None
100
+
101
+ except ValueError as e:
102
+ return f"Invalid input: {str(e)}", "", "", None, None, None
103
+ except Exception as e:
104
+ return f"Error getting recommendations: {str(e)}", "", "", None, None, None
105
+
106
+ def submit_all_ratings(course1_rating, course2_rating, course3_rating):
107
+ """Submit ratings for all three recommendations"""
108
+ global current_recommendations, current_user_input, recommender
109
+
110
+ if recommender is None:
111
+ return "❌ System not properly initialized. Please try again."
112
+
113
+ if not current_recommendations or not current_user_input:
114
+ return "No recommendations to rate. Please get recommendations first."
115
+
116
+ try:
117
+ results = []
118
+ ratings_submitted = 0
119
+
120
+ # Rate first recommendation
121
+ if course1_rating and len(current_recommendations) >= 1:
122
+ rating_value = "like" if course1_rating == "πŸ‘ Like" else "dislike"
123
+ course = current_recommendations[0][0]
124
+ success = recommender.add_feedback_with_learning(
125
+ course=course,
126
+ stanine=current_user_input['stanine'],
127
+ gwa=current_user_input['gwa'],
128
+ strand=current_user_input['strand'],
129
+ rating=rating_value,
130
+ hobbies=current_user_input['hobbies']
131
+ )
132
+ if success:
133
+ results.append(f"βœ… Rating for '{course}' recorded")
134
+ ratings_submitted += 1
135
+ else:
136
+ results.append(f"❌ Failed to record rating for '{course}'")
137
+
138
+ # Rate second recommendation
139
+ if course2_rating and len(current_recommendations) >= 2:
140
+ rating_value = "like" if course2_rating == "πŸ‘ Like" else "dislike"
141
+ course = current_recommendations[1][0]
142
+ success = recommender.add_feedback_with_learning(
143
+ course=course,
144
+ stanine=current_user_input['stanine'],
145
+ gwa=current_user_input['gwa'],
146
+ strand=current_user_input['strand'],
147
+ rating=rating_value,
148
+ hobbies=current_user_input['hobbies']
149
+ )
150
+ if success:
151
+ results.append(f"βœ… Rating for '{course}' recorded")
152
+ ratings_submitted += 1
153
  else:
154
+ results.append(f"❌ Failed to record rating for '{course}'")
155
+
156
+ # Rate third recommendation
157
+ if course3_rating and len(current_recommendations) >= 3:
158
+ rating_value = "like" if course3_rating == "πŸ‘ Like" else "dislike"
159
+ course = current_recommendations[2][0]
160
+ success = recommender.add_feedback_with_learning(
161
+ course=course,
162
+ stanine=current_user_input['stanine'],
163
+ gwa=current_user_input['gwa'],
164
+ strand=current_user_input['strand'],
165
+ rating=rating_value,
166
+ hobbies=current_user_input['hobbies']
167
+ )
168
+ if success:
169
+ results.append(f"βœ… Rating for '{course}' recorded")
170
+ ratings_submitted += 1
171
+ else:
172
+ results.append(f"❌ Failed to record rating for '{course}'")
173
+
174
+ if ratings_submitted > 0:
175
+ return f"Thank you! {ratings_submitted} rating(s) submitted successfully.\n\n" + "\n".join(results)
176
+ else:
177
+ return "Please select at least one rating before submitting."
178
+
179
+ except Exception as e:
180
+ return f"Error recording feedback: {str(e)}"
181
+
182
+ def train_model():
183
+ """Train the model with current data"""
184
+ global recommender
185
 
186
+ if recommender is None:
187
+ return "❌ System not properly initialized. Please try again."
 
 
 
 
 
 
 
 
 
 
188
 
189
+ try:
190
+ accuracy = recommender.train_model(use_database=True)
191
+ return f"βœ… Model trained successfully! Accuracy: {accuracy:.3f}"
192
+ except Exception as e:
193
+ return f"❌ Error training model: {str(e)}"
194
+
195
+ def get_available_courses_info():
196
+ """Get information about available courses from database"""
197
+ global db_connection
 
 
198
 
199
+ if db_connection is None:
200
+ return "❌ Database connection not available. Please try again."
201
+
202
+ try:
203
+ courses = db_connection.get_available_courses()
204
+ if courses:
205
+ return f"πŸ“š Available courses in database: {len(courses)}\n\n" + "\n".join([f"β€’ {course}" for course in courses[:10]]) + (f"\n... and {len(courses)-10} more" if len(courses) > 10 else "")
206
+ else:
207
+ return "πŸ“š No courses found in database. Please check the /courses endpoint."
208
+ except Exception as e:
209
+ return f"❌ Error fetching courses: {str(e)}"
210
+
211
+ # Create Gradio interface
212
+ def create_interface():
213
+ with gr.Blocks(title="Course AI Recommender", theme=gr.themes.Soft()) as demo:
214
+ gr.Markdown("""
215
+ # πŸŽ“ Course AI Machine Learning Recommender
216
+
217
+ Get personalized course recommendations based on your academic profile and interests!
218
+ """)
219
+
220
+ with gr.Row():
221
+ with gr.Column(scale=1):
222
+ gr.Markdown("### πŸ“ Your Profile")
223
+
224
+ stanine_input = gr.Textbox(
225
+ label="Stanine Score (1-9)",
226
+ placeholder="Enter your stanine score (1-9)",
227
+ info="Your stanine score from standardized tests"
228
+ )
229
+
230
+ gwa_input = gr.Textbox(
231
+ label="GWA (75-100)",
232
+ placeholder="Enter your GWA (75-100)",
233
+ info="Your Grade Weighted Average"
234
+ )
235
+
236
+ strand_input = gr.Dropdown(
237
+ choices=["STEM", "ABM", "HUMSS", "GAS", "TVL"],
238
+ value="STEM",
239
+ label="Academic Strand",
240
+ info="Your current academic strand"
241
+ )
242
+
243
+ hobbies_input = gr.Textbox(
244
+ label="Hobbies & Interests",
245
+ placeholder="e.g., Programming, Reading, Sports, Music",
246
+ info="List your hobbies and interests (comma-separated)"
247
+ )
248
+
249
+ get_recommendations_btn = gr.Button("🎯 Get Recommendations", variant="primary")
250
+
251
+ train_model_btn = gr.Button("πŸ€– Train Model", variant="secondary")
252
+
253
+ show_courses_btn = gr.Button("πŸ“š Show Available Courses", variant="secondary")
254
 
255
+ with gr.Column(scale=1):
256
+ gr.Markdown("### πŸŽ“ Top 3 Course Recommendations")
257
+
258
+ # Display top 3 recommendations
259
+ course1_output = gr.Textbox(
260
+ label="1st Recommendation",
261
+ interactive=False
262
+ )
263
+
264
+ course1_rating = gr.Radio(
265
+ choices=["πŸ‘ Like", "πŸ‘Ž Dislike"],
266
+ label="Rate 1st Recommendation",
267
+ interactive=True
268
+ )
269
+
270
+ course2_output = gr.Textbox(
271
+ label="2nd Recommendation",
272
+ interactive=False
273
+ )
274
+
275
+ course2_rating = gr.Radio(
276
+ choices=["πŸ‘ Like", "πŸ‘Ž Dislike"],
277
+ label="Rate 2nd Recommendation",
278
+ interactive=True
279
+ )
280
+
281
+ course3_output = gr.Textbox(
282
+ label="3rd Recommendation",
283
+ interactive=False
284
+ )
285
+
286
+ course3_rating = gr.Radio(
287
+ choices=["πŸ‘ Like", "πŸ‘Ž Dislike"],
288
+ label="Rate 3rd Recommendation",
289
+ interactive=True
290
+ )
291
+
292
+ submit_ratings_btn = gr.Button("Submit All Ratings", variant="primary")
293
+
294
+ rating_feedback = gr.Textbox(
295
+ label="Rating Feedback",
296
+ interactive=False
297
+ )
298
+
299
+ courses_info = gr.Textbox(
300
+ label="Available Courses",
301
+ lines=8,
302
+ interactive=False
303
+ )
304
+
305
+ # Event handlers
306
+ get_recommendations_btn.click(
307
+ fn=get_course_recommendations,
308
+ inputs=[stanine_input, gwa_input, strand_input, hobbies_input],
309
+ outputs=[course1_output, course2_output, course3_output, course1_rating, course2_rating, course3_rating]
310
+ )
311
+
312
+ submit_ratings_btn.click(
313
+ fn=submit_all_ratings,
314
+ inputs=[course1_rating, course2_rating, course3_rating],
315
+ outputs=[rating_feedback]
316
+ )
317
+
318
+ train_model_btn.click(
319
+ fn=train_model,
320
+ outputs=[gr.Textbox(label="Training Status", interactive=False)]
321
+ )
322
+
323
+ show_courses_btn.click(
324
+ fn=get_available_courses_info,
325
+ outputs=[courses_info]
326
+ )
327
+
328
+ # Add some example inputs
329
+ gr.Markdown("""
330
+ ### πŸ’‘ Example Inputs
331
+
332
+ **For STEM students:**
333
+ - Stanine: 7-9, GWA: 85-95, Strand: STEM, Hobbies: Programming, Mathematics, Science
334
+
335
+ **For ABM students:**
336
+ - Stanine: 6-8, GWA: 80-90, Strand: ABM, Hobbies: Business, Leadership, Economics
337
+
338
+ **For HUMSS students:**
339
+ - Stanine: 5-8, GWA: 78-88, Strand: HUMSS, Hobbies: Literature, History, Writing
340
+ """)
341
+
342
+ return demo
343
+
344
+ # Initialize the interface
345
+ if __name__ == "__main__":
346
+ # Try to load existing model if recommender is available
347
+ if recommender is not None:
348
+ try:
349
+ recommender.load_model()
350
+ print("βœ… Loaded existing model")
351
+ except:
352
+ print("⚠️ No existing model found. Training with basic data...")
353
+ try:
354
+ recommender.train_model(use_database=False)
355
+ print("βœ… Model trained with basic data")
356
+ except Exception as e:
357
+ print(f"❌ Error training model: {e}")
358
+ else:
359
+ print("⚠️ Recommender not initialized. App will run with limited functionality.")
360
+
361
+ # Create and launch interface
362
+ demo = create_interface()
363
+ demo.launch(
364
+ server_name="0.0.0.0",
365
+ server_port=7860,
366
+ share=True
367
+ )