diff --git a/dashboard_api.py b/dashboard_api.py index 2505429..0dbf7e0 100644 --- a/dashboard_api.py +++ b/dashboard_api.py @@ -1,10 +1,10 @@ import os -from flask import Flask, jsonify, render_template +from flask import Flask, jsonify, render_template, request from flask_cors import CORS from dotenv import load_dotenv from src.database.manager import setup_database_tables -from src.database.preference_operations import get_training_data_from_database, get_unrated_videos_with_features_from_database, get_rated_count_from_database +from src.database.preference_operations import get_training_data_from_database, get_unrated_videos_with_features_from_database, get_rated_count_from_database, save_video_rating_to_database from src.database.video_operations import get_unrated_videos_from_database from src.ml.model_training import create_recommendation_model, train_model_on_user_preferences from src.ml.predictions import predict_video_preferences_with_model @@ -79,6 +79,51 @@ def get_recommendations(): 'error': str(e) }), 500 +@app.route('/api/rate', methods=['POST']) +def rate_video(): + try: + data = request.json + video_id = data.get('video_id') + liked = data.get('liked') + + if not video_id or liked is None: + return jsonify({ + 'success': False, + 'error': 'Missing video_id or liked parameter' + }), 400 + + # Save the rating + save_video_rating_to_database(video_id, liked, "", dashboard_api.db_path) + + # Check if we should retrain the model + model_retrained = False + rated_count = get_rated_count_from_database(dashboard_api.db_path) + + if rated_count >= 10: # Minimum ratings needed for training + # Retrain the model with new data + if not dashboard_api.model: + dashboard_api.model = create_recommendation_model() + + training_data = get_training_data_from_database(dashboard_api.db_path) + success = train_model_on_user_preferences(dashboard_api.model, training_data) + + if success: + dashboard_api.model_trained = True + model_retrained = True + + return jsonify({ + 'success': True, + 'message': 'Rating saved successfully', + 'model_retrained': model_retrained, + 'total_ratings': rated_count + }) + + except Exception as e: + return jsonify({ + 'success': False, + 'error': str(e) + }), 500 + def format_view_count(count): if count >= 1000000: return f"{count/1000000:.1f}M views" diff --git a/templates/dashboard.html b/templates/dashboard.html index 4571954..44da3ef 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -209,6 +209,56 @@ font-size: 14px; } + .rating-buttons { + display: flex; + gap: 8px; + margin-top: 8px; + justify-content: center; + } + + .rating-btn { + padding: 6px 12px; + border: 1px solid #333; + border-radius: 20px; + background-color: #222; + color: white; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + gap: 4px; + transition: all 0.2s ease; + } + + .rating-btn:hover { + transform: scale(1.05); + } + + .rating-btn.like-btn:hover { + background-color: #00d400; + border-color: #00d400; + } + + .rating-btn.dislike-btn:hover { + background-color: #ff4444; + border-color: #ff4444; + } + + .rating-btn.liked { + background-color: #00d400; + border-color: #00d400; + } + + .rating-btn.disliked { + background-color: #ff4444; + border-color: #ff4444; + } + + .rating-btn:disabled { + opacity: 0.6; + cursor: not-allowed; + } + .loading { text-align: center; padding: 60px; @@ -343,20 +393,28 @@ } videoGrid.innerHTML = videos.map(video => ` -