galcomis commited on
Commit
3bfb218
·
verified ·
1 Parent(s): 476f798

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +21 -4
app.py CHANGED
@@ -39,7 +39,7 @@ for root, _, files in os.walk("."):
39
  ALL_IMAGE_PATHS.append(os.path.join(root, f))
40
 
41
  def find_any_matching_image(dish_name):
42
- """Robust image search logic."""
43
  name_clean = str(dish_name).lower()
44
  keywords = [kw for kw in re.findall(r'\w+', name_clean) if len(kw) > 2]
45
  if not keywords: return None
@@ -67,13 +67,19 @@ def get_hybrid_recommendations(user_query, user_name, city, hobbies, style, alph
67
  return [None, "### ⚠️ Identity required."] * 3
68
 
69
  user_profile_text = f"{user_name} from {city} loves {hobbies} and has a {style} style."
 
 
70
  query_emb = model.encode([user_query])
71
  profile_emb = model.encode([user_profile_text])
72
 
 
73
  content_sim = cosine_similarity(query_emb, dish_embeddings).flatten()
74
  user_sim = cosine_similarity(profile_emb, user_embeddings).flatten()
 
 
75
  raw_scores = (alpha * content_sim) + (1 - alpha) * user_sim
76
 
 
77
  min_s, max_s = raw_scores.min(), raw_scores.max()
78
  scaled_scores = 0.74 + (raw_scores - min_s) * (0.25) / (max_s - min_s) if max_s > min_s else raw_scores
79
 
@@ -84,14 +90,25 @@ def get_hybrid_recommendations(user_query, user_name, city, hobbies, style, alph
84
  output = []
85
  for _, row in top_results.iterrows():
86
  image_path = find_any_matching_image(row['dish_name'])
 
 
 
 
 
87
  res_text = f"""
88
  <div style='font-family: serif; color: #4a3f35; padding: 15px; background: #fffcf7; border: 1px solid #e0d8c3; margin-bottom: 10px;'>
89
  <h2 style='margin-bottom: 2px; color: #5d4037; font-weight: normal; letter-spacing: 1px;'>{row['dish_name'].upper()}</h2>
90
  <p style='font-style: italic; margin-top: 0; color: #8c7b6c;'>{row['restaurant_name']} — {row['food_vibe']}</p>
91
- <p style='font-size: 0.8em; letter-spacing: 1.5px;'>MATCH: {row['final_score']:.2%} | ⭐ {row['rating']}</p>
 
 
 
 
 
 
92
  <hr style='border: 0; border-top: 1px solid #f0ece2; margin: 12px 0;'>
93
- <p style='line-height: 1.6;'><b>Vision:</b> {row['visual_description']}</p>
94
- <p style='line-height: 1.6;'><b>Experience:</b> {row['taste_review']}</p>
95
  </div>
96
  """
97
  output.extend([image_path, res_text])
 
39
  ALL_IMAGE_PATHS.append(os.path.join(root, f))
40
 
41
  def find_any_matching_image(dish_name):
42
+ """Robust image search logic based on keyword matching."""
43
  name_clean = str(dish_name).lower()
44
  keywords = [kw for kw in re.findall(r'\w+', name_clean) if len(kw) > 2]
45
  if not keywords: return None
 
67
  return [None, "### ⚠️ Identity required."] * 3
68
 
69
  user_profile_text = f"{user_name} from {city} loves {hobbies} and has a {style} style."
70
+
71
+ # NEW: Create embeddings for both query and persona
72
  query_emb = model.encode([user_query])
73
  profile_emb = model.encode([user_profile_text])
74
 
75
+ # Calculate similarities (The Hybrid Logic)
76
  content_sim = cosine_similarity(query_emb, dish_embeddings).flatten()
77
  user_sim = cosine_similarity(profile_emb, user_embeddings).flatten()
78
+
79
+ # Weighting: 65% Craving (Content) + 35% Persona (Demographics)
80
  raw_scores = (alpha * content_sim) + (1 - alpha) * user_sim
81
 
82
+ # Normalizing scores for display (74%-99%)
83
  min_s, max_s = raw_scores.min(), raw_scores.max()
84
  scaled_scores = 0.74 + (raw_scores - min_s) * (0.25) / (max_s - min_s) if max_s > min_s else raw_scores
85
 
 
90
  output = []
91
  for _, row in top_results.iterrows():
92
  image_path = find_any_matching_image(row['dish_name'])
93
+
94
+ # NEW: Generate the 'Culinary Twin' profile from the dataset metadata
95
+ # This provides transparency on WHY this dish was recommended
96
+ twin_info = f"A {row['user_age']} year old from {row['user_origin']}, with a {row['user_fashion_style']} style."
97
+
98
  res_text = f"""
99
  <div style='font-family: serif; color: #4a3f35; padding: 15px; background: #fffcf7; border: 1px solid #e0d8c3; margin-bottom: 10px;'>
100
  <h2 style='margin-bottom: 2px; color: #5d4037; font-weight: normal; letter-spacing: 1px;'>{row['dish_name'].upper()}</h2>
101
  <p style='font-style: italic; margin-top: 0; color: #8c7b6c;'>{row['restaurant_name']} — {row['food_vibe']}</p>
102
+
103
+ <div style='background-color: #f0ece2; padding: 10px; margin: 10px 0; border-radius: 4px; font-size: 0.9em; border-left: 4px solid #5d4037;'>
104
+ <strong style='color: #5d4037;'>👤 Recommended by your Culinary Twin:</strong><br>
105
+ {twin_info}
106
+ </div>
107
+
108
+ <p style='font-size: 0.8em; letter-spacing: 1.5px;'>MATCH SCORE: {row['final_score']:.2%} | ⭐ {row['rating']}</p>
109
  <hr style='border: 0; border-top: 1px solid #f0ece2; margin: 12px 0;'>
110
+ <p style='line-height: 1.6;'><b>The Vision:</b> {row['visual_description']}</p>
111
+ <p style='line-height: 1.6;'><b>The Experience:</b> {row['taste_review']}</p>
112
  </div>
113
  """
114
  output.extend([image_path, res_text])