Update main.py
Browse files
main.py
CHANGED
|
@@ -1271,62 +1271,111 @@ def view_quizzes():
|
|
| 1271 |
|
| 1272 |
@app.route('/api/user/performance', methods=['GET'])
|
| 1273 |
def get_user_performance():
|
| 1274 |
-
"""Retrieves user's quiz performance
|
| 1275 |
try:
|
| 1276 |
# Authentication
|
| 1277 |
user, error = verify_token(request.headers.get('Authorization'))
|
| 1278 |
-
if error:
|
|
|
|
| 1279 |
|
| 1280 |
-
#
|
| 1281 |
attempts_res = supabase.table('quiz_attempts') \
|
| 1282 |
-
.select('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1283 |
.eq('user_id', user.id) \
|
| 1284 |
.order('submitted_at', desc=True) \
|
| 1285 |
-
.
|
| 1286 |
-
|
| 1287 |
-
|
| 1288 |
-
|
| 1289 |
-
|
| 1290 |
-
|
| 1291 |
-
|
| 1292 |
-
|
| 1293 |
-
|
| 1294 |
-
|
| 1295 |
-
|
| 1296 |
-
|
| 1297 |
-
|
| 1298 |
-
|
| 1299 |
-
|
| 1300 |
-
|
| 1301 |
-
|
| 1302 |
-
|
| 1303 |
-
|
| 1304 |
-
|
| 1305 |
-
|
| 1306 |
-
|
| 1307 |
-
|
| 1308 |
-
|
| 1309 |
-
|
| 1310 |
-
|
| 1311 |
-
|
| 1312 |
-
|
| 1313 |
-
|
| 1314 |
-
|
| 1315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1316 |
|
| 1317 |
return jsonify({
|
| 1318 |
'success': True,
|
| 1319 |
-
'average_score': round(
|
| 1320 |
-
'
|
| 1321 |
'suggestions': suggestions
|
| 1322 |
})
|
| 1323 |
-
|
| 1324 |
except Exception as e:
|
| 1325 |
-
|
| 1326 |
-
logging.error(f"Performance endpoint error: {str(e)}")
|
| 1327 |
-
logging.error(traceback.format_exc())
|
| 1328 |
return jsonify({'error': str(e)}), 500
|
| 1329 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1330 |
|
| 1331 |
# === Admin Endpoints (Adapted for Supabase) ===
|
| 1332 |
|
|
|
|
| 1271 |
|
| 1272 |
@app.route('/api/user/performance', methods=['GET'])
|
| 1273 |
def get_user_performance():
|
| 1274 |
+
"""Retrieves user's quiz performance grouped by quiz"""
|
| 1275 |
try:
|
| 1276 |
# Authentication
|
| 1277 |
user, error = verify_token(request.headers.get('Authorization'))
|
| 1278 |
+
if error:
|
| 1279 |
+
return jsonify({'error': error['error']}), error['status']
|
| 1280 |
|
| 1281 |
+
# Get all quiz attempts with related data
|
| 1282 |
attempts_res = supabase.table('quiz_attempts') \
|
| 1283 |
+
.select('''
|
| 1284 |
+
id,
|
| 1285 |
+
quiz_id,
|
| 1286 |
+
score,
|
| 1287 |
+
submitted_at,
|
| 1288 |
+
quizzes(
|
| 1289 |
+
id,
|
| 1290 |
+
difficulty,
|
| 1291 |
+
created_at,
|
| 1292 |
+
notes!inner(
|
| 1293 |
+
id,
|
| 1294 |
+
study_materials!inner(title)
|
| 1295 |
+
)
|
| 1296 |
+
)
|
| 1297 |
+
''') \
|
| 1298 |
.eq('user_id', user.id) \
|
| 1299 |
.order('submitted_at', desc=True) \
|
| 1300 |
+
.execute()
|
| 1301 |
+
|
| 1302 |
+
if attempts_res.error:
|
| 1303 |
+
raise Exception(attempts_res.error.message)
|
| 1304 |
+
|
| 1305 |
+
# Group attempts by quiz
|
| 1306 |
+
quizzes = {}
|
| 1307 |
+
for attempt in attempts_res.data:
|
| 1308 |
+
quiz_id = attempt['quizzes']['id']
|
| 1309 |
+
if quiz_id not in quizzes:
|
| 1310 |
+
quizzes[quiz_id] = {
|
| 1311 |
+
'quiz_info': {
|
| 1312 |
+
'id': quiz_id,
|
| 1313 |
+
'title': attempt['quizzes']['notes']['study_materials']['title'],
|
| 1314 |
+
'difficulty': attempt['quizzes']['difficulty'],
|
| 1315 |
+
'created_at': attempt['quizzes']['created_at']
|
| 1316 |
+
},
|
| 1317 |
+
'attempts': [],
|
| 1318 |
+
'average_score': 0
|
| 1319 |
+
}
|
| 1320 |
+
quizzes[quiz_id]['attempts'].append(attempt)
|
| 1321 |
+
|
| 1322 |
+
# Calculate averages and format
|
| 1323 |
+
performance_data = []
|
| 1324 |
+
for quiz in quizzes.values():
|
| 1325 |
+
scores = [a['score'] for a in quiz['attempts']]
|
| 1326 |
+
quiz['average_score'] = sum(scores) / len(scores) if scores else 0
|
| 1327 |
+
quiz['attempt_count'] = len(scores)
|
| 1328 |
+
performance_data.append(quiz)
|
| 1329 |
+
|
| 1330 |
+
# Sort quizzes by most recent attempt
|
| 1331 |
+
performance_data.sort(
|
| 1332 |
+
key=lambda x: max(a['submitted_at'] for a in x['attempts']),
|
| 1333 |
+
reverse=True
|
| 1334 |
+
)
|
| 1335 |
+
|
| 1336 |
+
# Generate suggestions
|
| 1337 |
+
overall_avg = sum(q['average_score'] for q in performance_data) / len(performance_data) if performance_data else 0
|
| 1338 |
+
suggestions = generate_suggestions(performance_data, overall_avg)
|
| 1339 |
|
| 1340 |
return jsonify({
|
| 1341 |
'success': True,
|
| 1342 |
+
'average_score': round(overall_avg, 2),
|
| 1343 |
+
'quizzes': performance_data,
|
| 1344 |
'suggestions': suggestions
|
| 1345 |
})
|
| 1346 |
+
|
| 1347 |
except Exception as e:
|
| 1348 |
+
logging.error(f"Performance error: {traceback.format_exc()}")
|
|
|
|
|
|
|
| 1349 |
return jsonify({'error': str(e)}), 500
|
| 1350 |
|
| 1351 |
+
def generate_suggestions(quizzes, overall_avg):
|
| 1352 |
+
"""Generate personalized suggestions based on quiz performance"""
|
| 1353 |
+
suggestions = []
|
| 1354 |
+
|
| 1355 |
+
if overall_avg < 60:
|
| 1356 |
+
suggestions.append("Your average score is a bit low. Try reviewing notes before retaking quizzes.")
|
| 1357 |
+
elif overall_avg > 85:
|
| 1358 |
+
suggestions.append("Great job! Challenge yourself with harder difficulty levels.")
|
| 1359 |
+
else:
|
| 1360 |
+
suggestions.append("Keep practicing! Focus on your weaker areas for improvement.")
|
| 1361 |
+
|
| 1362 |
+
# Find weakest quiz
|
| 1363 |
+
weakest = min(quizzes, key=lambda x: x['average_score'], default=None)
|
| 1364 |
+
if weakest and weakest['average_score'] < 60:
|
| 1365 |
+
title = weakest['quiz_info']['title'] or "your recent quizzes"
|
| 1366 |
+
suggestions.append(f"Focus on improving in '{title}' (current average: {weakest['average_score']:.0f}%).")
|
| 1367 |
+
|
| 1368 |
+
# Check for difficulty distribution
|
| 1369 |
+
difficulty_count = {}
|
| 1370 |
+
for quiz in quizzes:
|
| 1371 |
+
diff = quiz['quiz_info']['difficulty']
|
| 1372 |
+
difficulty_count[diff] = difficulty_count.get(diff, 0) + 1
|
| 1373 |
+
|
| 1374 |
+
if difficulty_count.get('easy', 0) / len(quizzes) > 0.7:
|
| 1375 |
+
suggestions.append("Try more medium difficulty quizzes to push your skills!")
|
| 1376 |
+
|
| 1377 |
+
return suggestions
|
| 1378 |
+
|
| 1379 |
|
| 1380 |
# === Admin Endpoints (Adapted for Supabase) ===
|
| 1381 |
|