From e7580c36f5ad5390515ec5c1c2fec67ec8c75654 Mon Sep 17 00:00:00 2001 From: Mann Patel <130435633+MannPatel0@users.noreply.github.com> Date: Wed, 2 Apr 2025 19:53:42 -0600 Subject: [PATCH] update --- frontend/src/App.jsx | 5 +- .../__pycache__/server.cpython-313.pyc | Bin 0 -> 1595 bytes recommondation-engine/example.py | 325 ++++++++++++++---- recommondation-engine/example1.py | 221 ++++++++++++ 4 files changed, 473 insertions(+), 78 deletions(-) create mode 100644 recommondation-engine/__pycache__/server.cpython-313.pyc create mode 100644 recommondation-engine/example1.py diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 12b3231..6703948 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -298,10 +298,7 @@ function App() { // Save to localStorage to persist across refreshes sessionStorage.setItem("isAuthenticated", "true"); sessionStorage.setItem("user", JSON.stringify(userObj)); - - // After successful signup, send session data to server sendSessionDataToServer(); // Call it after signup - sessionStorage.getItem("user"); console.log("Login successful for:", userData.email); @@ -388,7 +385,7 @@ function App() { console.log("Sending user data to the server:", requestData); // Send data to Python server (replace with your actual server URL) - const response = await fetch("http://localhost:5000/api/user/session", { + const response = await fetch("http://0.0.0.0:5000/api/user/session", { method: "POST", headers: { "Content-Type": "application/json", diff --git a/recommondation-engine/__pycache__/server.cpython-313.pyc b/recommondation-engine/__pycache__/server.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f9faf72f3a6b5e3b07c6c4d8c2c15b08c6db95f GIT binary patch literal 1595 zcmZ`(&2Jk;6rcU_u46l!k2YzND%k|1#Hg*4Hea<0C~1S^RHRilmY|7PZSAqM)ZR5S zyAkmLrGQi)(?eBrfr?YO<;bx_`~lkCT#%hzCPUlQg4P=U%^2P+I>R#?QYaEMdr9ebT$5s;vOO=b*i z`evBpS4i9x$XRTjiCkRkZbG+rl~egBqY9T<)i(%c8Up0s^r>R(9RTzmKwqA2zi4u* zr25qkHE@~ukqu^pkJpSs9HMQ6s)eA<{ z!4O3;#MrP*kH2|CT_*}+9@<-08mF3O=q`~z$quM}M522DhQS8Ct*fRvacs zf;FKnX>uyl%!|pqM1yTCDfnfI>Dt@O_di>NaoupVK53d>YYS!M4*oYVDc}Z29rENYQ=N{ ziC05yB(-yz#q0>_ER$d0!;L+|WWej(2*@xIdDZjL$|cgC0Q0($^JD`rIQAAaZ6l@I zklrI?p<*y$ZtFQCt)z8ZH}**Bipm;HL1P=Hl}6p`vY3)2fJ)+8Oey-$DN7WUu-)gB z6Sy&jb_d3K78b|UY;RBD)(2qMoYrc(8w3_pUu1Bnaa?tE1mgW?)x0N<8x2O-+b0P zSdKq>&mEes^v)b$w>RbnW6!0K+ckO6f8hUm;PK4kaW`?x-MHi4%DJ8S?JW{ zZ71vTTNar;e8EEYY9!zZ89J2ckOlSH9~Zl$eygP{gb|&$6xY=AP}4k4FBCihS&j|s ziS{_;m|uY!(E_Nyu6reKrJWpn1HDR)bns%GkSfP8%+Db51VnxUL%;e0rR7hoUG7J~ z@2a2re_{B019u19!0>+GzO*~wGE;xCGBa1>0DG}Yx#}3;gQa4H8#v;{d-1#Ry>R*6 S{q^1WQ~qL=1N', methods=['GET']) +def recommend(user_id): + # Check if products are loaded + if recommender.products_df is None: + products = get_all_products() + if not products: + return jsonify({'error': 'No products available'}), 500 + recommender.load_products(products) + + # Generate recommendations using cosine similarity + recommendations = recommender.recommend_products_for_user(user_id) + + # Store recommendations in database + if store_user_recommendations(user_id, recommendations): + return jsonify({ + 'userId': user_id, + 'recommendations': recommendations, + 'count': len(recommendations) + }) + else: + return jsonify({'error': 'Failed to store recommendations'}), 500 + +@app.route('/api/user/session', methods=['POST']) +def handle_session_data(): + try: + data = request.get_json() + print("Received data:", data) # Debug print + + user_id = data.get('userId') + email = data.get('email') + is_authenticated = data.get('isAuthenticated') + + if not user_id or not email or is_authenticated is None: + print("Missing required fields") # Debug print + return jsonify({'error': 'Invalid data'}), 400 + + print(f"Processing session data: User ID: {user_id}, Email: {email}, Authenticated: {is_authenticated}") + + # Test database connection first + try: + conn = get_db_connection() + conn.close() + print("Database connection successful") + except Exception as db_err: + print(f"Database connection error: {db_err}") + return jsonify({'error': f'Database connection error: {str(db_err)}'}), 500 + + # Continue with the rest of your code... + + except Exception as e: + import traceback + print(f"Error in handle_session_data: {e}") + print(traceback.format_exc()) # Print full stack trace + return jsonify({'error': f'Server error: {str(e)}'}), 500 + +if __name__ == '__main__': + # Load products on startup + products = get_all_products() + if products: + recommender.load_products(products) + print(f"Loaded {len(products)} products at startup") + else: + print("Warning: No products loaded at startup") + + app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/recommondation-engine/example1.py b/recommondation-engine/example1.py new file mode 100644 index 0000000..5686e9a --- /dev/null +++ b/recommondation-engine/example1.py @@ -0,0 +1,221 @@ + +import pandas as pd +import numpy as np +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity + +''' +Recommender system using content-based filtering +''' +class Recommender: + def __init__(self): + # Initialize data structures + self.products_df = None + self.user_profiles = {} + self.tfidf_matrix = None + self.tfidf_vectorizer = None + self.product_indices = None + + def load_products(self, products_data): + """ + Load product data into the recommender system + + products_data: list of dictionaries with product info (id, name, description, category, etc.) + """ + self.products_df = pd.DataFrame(products_data) + + # Create a text representation for each product (combining various features) + self.products_df['content'] = ( + self.products_df['category'] + ' ' + + self.products_df['name'] + ' ' + + self.products_df['description'] + ) + + # Initialize TF-IDF vectorizer to convert text to vectors + self.tfidf_vectorizer = TfidfVectorizer( + stop_words='english', + max_features=5000, # Limit features to avoid sparse matrices + ngram_range=(1, 2) # Use both unigrams and bigrams + ) + + # Compute TF-IDF matrix + self.tfidf_matrix = self.tfidf_vectorizer.fit_transform(self.products_df['content']) + + # Create a mapping from product_id to index + self.product_indices = pd.Series( + self.products_df.index, + index=self.products_df['product_id'] + ).drop_duplicates() + + def track_user_click(self, user_id, product_id): + """ + Track user clicks on products to build user profiles + """ + if user_id not in self.user_profiles: + self.user_profiles[user_id] = { + 'clicks': {}, + 'category_weights': { + 'electronics': 0, + 'school supplies': 0, + 'rental place': 0, + 'furniture': 0 + } + } + + # Get the clicked product's index and details + if product_id in self.product_indices: + product_idx = self.product_indices[product_id] + product_category = self.products_df.iloc[product_idx]['category'] + + # Update click count + if product_id in self.user_profiles[user_id]['clicks']: + self.user_profiles[user_id]['clicks'][product_id] += 1 + else: + self.user_profiles[user_id]['clicks'][product_id] = 1 + + # Update category weight + self.user_profiles[user_id]['category_weights'][product_category] += 1 + + def get_user_profile_vector(self, user_id): + """ + Generate a user profile vector based on their click history + """ + if user_id not in self.user_profiles or not self.user_profiles[user_id]['clicks']: + # Return a zero vector if no click history + return np.zeros((1, self.tfidf_matrix.shape[1])) + + # Create a weighted average of all clicked products' TF-IDF vectors + clicked_product_vectors = [] + weights = [] + + for product_id, click_count in self.user_profiles[user_id]['clicks'].items(): + if product_id in self.product_indices: + product_idx = self.product_indices[product_id] + product_category = self.products_df.iloc[product_idx]['category'] + category_weight = self.user_profiles[user_id]['category_weights'][product_category] + + # Weight is based on both click count and category preference + weight = click_count * (1 + 0.5 * category_weight) + weights.append(weight) + clicked_product_vectors.append(self.tfidf_matrix[product_idx]) + + # Normalize weights + weights = np.array(weights) / np.sum(weights) + + # Compute weighted average + user_profile = np.zeros((1, self.tfidf_matrix.shape[1])) + for i, vector in enumerate(clicked_product_vectors): + user_profile += weights[i] * vector.toarray() + + return user_profile + + def recommend_products(self, user_id, n=5, category_filter=None): + """ + Recommend products to a user based on their profile + + user_id: ID of the user + n: Number of recommendations to return + category_filter: Optional filter to limit recommendations to a specific category + """ + # Get user profile vector + user_profile = self.get_user_profile_vector(user_id) + + # If user has no profile, recommend popular products (not implemented) + if np.sum(user_profile) == 0: + return self._get_popular_products(n, category_filter) + + # Calculate similarity scores + sim_scores = cosine_similarity(user_profile, self.tfidf_matrix) + sim_scores = sim_scores.flatten() + + # Create a DataFrame for easier filtering + recommendations_df = pd.DataFrame({ + 'product_id': self.products_df['product_id'], + 'score': sim_scores, + 'category': self.products_df['category'] + }) + + # Filter out products that the user has already clicked on + if user_id in self.user_profiles and self.user_profiles[user_id]['clicks']: + clicked_products = list(self.user_profiles[user_id]['clicks'].keys()) + recommendations_df = recommendations_df[~recommendations_df['product_id'].isin(clicked_products)] + + # Apply category filter if provided + if category_filter: + recommendations_df = recommendations_df[recommendations_df['category'] == category_filter] + + # Sort by similarity score and get top n recommendations + recommendations_df = recommendations_df.sort_values('score', ascending=False).head(n) + + # Return recommended product IDs + return recommendations_df['product_id'].tolist() + + def _get_popular_products(self, n=5, category_filter=None): + """ + Return popular products when a user has no profile + (This would typically be implemented with actual popularity metrics) + """ + filtered_df = self.products_df + + if category_filter: + filtered_df = filtered_df[filtered_df['category'] == category_filter] + + # Just return random products for now (in a real system you'd use popularity metrics) + if len(filtered_df) >= n: + return filtered_df.sample(n)['product_id'].tolist() + else: + return filtered_df['product_id'].tolist() + + def recommend_by_category_preference(self, user_id, n=5): + """ + Recommend products based primarily on the user's category preferences + """ + if user_id not in self.user_profiles: + return self._get_popular_products(n) + + # Get the user's most clicked category + category_weights = self.user_profiles[user_id]['category_weights'] + + # If no category has been clicked, return popular products + if sum(category_weights.values()) == 0: + return self._get_popular_products(n) + + # Sort categories by number of clicks + sorted_categories = sorted( + category_weights.items(), + key=lambda x: x[1], + reverse=True + ) + + recommendations = [] + remaining = n + + # Allocate recommendations proportionally across categories + for category, weight in sorted_categories: + if weight > 0: + # Allocate recommendations proportionally to category weight + category_allocation = max(1, int(remaining * (weight / sum(category_weights.values())))) + if category_allocation > remaining: + category_allocation = remaining + + # Get recommendations for this category + category_recs = self.recommend_products(user_id, category_allocation, category) + recommendations.extend(category_recs) + + # Update remaining slots + remaining -= len(category_recs) + + if remaining <= 0: + break + + # If we still have slots to fill, add general recommendations + if remaining > 0: + general_recs = self.recommend_products(user_id, remaining) + # Filter out duplicates + general_recs = [rec for rec in general_recs if rec not in recommendations] + recommendations.extend(general_recs[:remaining]) + + return recommendations + + +exported = Recommender()