galcomis commited on
Commit
bcd2fbe
·
verified ·
1 Parent(s): 723ac7f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -82
app.py CHANGED
@@ -8,55 +8,31 @@ import glob
8
  from sentence_transformers import SentenceTransformer
9
  from sklearn.metrics.pairwise import cosine_similarity
10
 
11
- # --- 1. חילוץ תמונות (עם בדיקה) ---
 
12
  if os.path.exists('images.zip'):
13
- try:
14
- with zipfile.ZipFile('images.zip', 'r') as zip_ref:
15
- zip_ref.extractall('extracted_images')
16
- print("✅ Images extracted")
17
- except Exception as e:
18
- print(f"❌ Zip error: {e}")
19
 
20
- # --- 2. טעינת נתונים עם "הגנה" מקריסה ---
21
  model = SentenceTransformer('all-MiniLM-L6-v2')
22
 
23
- def load_colab_data():
24
- try:
25
- if not os.path.exists('bitewise_clean_dataset.csv'):
26
- print("❌ CSV MISSING")
27
- return pd.DataFrame(), None, None
28
-
29
- df = pd.read_csv('bitewise_clean_dataset.csv').fillna("N/A")
30
- dish_emb = np.load('BiteWise_Dish_Embeddings.npy')
31
-
32
- with open('BiteWise_User_Embeddings.pkl', 'rb') as f:
33
- user_emb = pickle.load(f)
34
- if isinstance(user_emb, list): user_emb = np.array(user_emb)
35
-
36
- # סנכרון כפוי
37
- min_l = min(len(df), len(dish_emb), len(user_emb))
38
- print(f"✅ Data loaded. Syncing to {min_l} rows.")
39
- return df.iloc[:min_l], dish_emb[:min_l], user_emb[:min_l]
40
- except Exception as e:
41
- print(f"❌ Loading error: {e}")
42
- return pd.DataFrame(), None, None
43
-
44
- main_df, dish_embeddings, user_embeddings = load_colab_data()
45
 
46
- # יצירת רשימות לבחירה (עם ערכי ברירת מחדל אם הטעינה נכשלה)
47
- origins = list(main_df['user_origin'].unique()) if not main_df.empty else ["Tel Aviv"]
48
- hobbies = list(main_df['user_hobbies'].unique()) if not main_df.empty else ["Photography"]
49
- styles = list(main_df['user_fashion_style'].unique()) if not main_df.empty else ["Modern/Minimalist"]
50
 
51
- # --- 3. לוגיקת המלצה ---
52
- def run_discovery(query, origin, hobbies_val, style):
53
- if main_df.empty or dish_embeddings is None:
54
- return "<h3>Error: Database not loaded. Check your files.</h3>"
55
-
56
  alpha = 0.7
57
  q_vec = model.encode([str(query)])
58
- u_dna_str = f"Origin: {origin}, Hobbies: {hobbies_val}, Style: {style}"
59
- u_vec = model.encode([u_dna_str])
60
 
61
  dish_sim = cosine_similarity(q_vec, dish_embeddings).flatten()
62
  user_sim = cosine_similarity(u_vec, user_embeddings).flatten()
@@ -64,70 +40,92 @@ def run_discovery(query, origin, hobbies_val, style):
64
 
65
  res = main_df.copy()
66
  res['score'] = final_scores
67
- top_matches = res.sort_values('score', ascending=False).drop_duplicates('restaurant_name').head(3)
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  html_output = ""
70
- for idx, row in top_matches.iterrows():
 
71
  pct = f"{min(98.8, 88 + (row['score'] * 20)):.1f}%"
72
 
73
- # חיפוש תמונה חכם (טיפול ב-IndexError)
74
- pattern = f"extracted_images/**/dish_{idx}_*.jpg"
75
  files = glob.glob(pattern, recursive=True)
76
  img_url = f"file/{files[0]}" if files else "https://via.placeholder.com/300?text=BiteWise"
77
 
78
  html_output += f"""
79
- <div style="border: 2px solid #3E2723; border-radius: 15px; padding: 25px; margin-bottom: 25px; display: flex; gap: 25px; background: white; border-left: 12px solid #3E2723;">
80
- <img src="{img_url}" style="width: 280px; height: 280px; object-fit: cover; border-radius: 12px;">
81
- <div style="flex: 1;">
82
- <div style="display: flex; justify-content: space-between;">
83
- <h2 style="margin: 0; font-family: Serif; color: #3E2723; font-size: 2.2em;">{row['dish_name']}</h2>
84
- <span style="background: #3E2723; color: white; padding: 5px 15px; border-radius: 20px; font-weight: bold; font-size: 0.8em;">{pct} MATCH</span>
85
- </div>
86
- <p style="color: #7F4F24; font-weight: 600; margin: 5px 0;">📍 {row['restaurant_name']}</p>
87
- <div style="margin: 15px 0; display: flex; gap: 10px;">
88
- <span style="background: #F5F1EE; color: #5D4037; padding: 5px 12px; border-radius: 6px; font-weight: bold; font-size: 0.8em;">🍽️ {row['food_vibe']}</span>
89
- <span style="background: #F5F1EE; color: #5D4037; padding: 5px 12px; border-radius: 6px; font-weight: bold; font-size: 0.8em;">👥 {row['ideal_context']}</span>
90
- <span style="background: #F5F1EE; color: #5D4037; padding: 5px 12px; border-radius: 6px; font-weight: bold; font-size: 0.8em;">{row['rating']}</span>
91
- </div>
92
- <p style="font-style: italic; color: #4E342E; font-size: 1.15em; border-left: 3px solid #D7CCC8; padding-left: 15px;">"{row['taste_review']}"</p>
93
- <div style="background: #FFF9F0; padding: 15px; border-radius: 10px; border: 1px solid #FFE0B2;">
94
- <strong>The Twin Bio:</strong> Your culinary twin from <b>{origin}</b> who shares your <b>{hobbies_val}</b> interests recommends this <b>{style}</b> experience.
 
 
 
 
95
  </div>
96
  </div>
97
  </div>
98
  """
99
  return html_output
100
 
101
- # --- 4. הממשק ---
102
- with gr.Blocks() as demo:
103
- gr.HTML("<h1 style='text-align: center; font-family: Serif; color: #3E2723; font-size: 3.5em;'>BiteWise</h1>")
 
 
 
 
 
 
 
104
 
105
  with gr.Tabs() as tabs:
106
  with gr.Tab("01. YOUR DNA", id=0):
107
  with gr.Row():
108
- u_name = gr.Textbox(label="User Name", placeholder="What's your name?")
109
- u_origin = gr.Dropdown(origins, label="Origin", value=origins[0])
110
  with gr.Row():
111
- u_hobbies_input = gr.Dropdown(hobbies, label="Hobbies", value=hobbies[0])
112
- u_style = gr.Dropdown(styles, label="Style", value=styles[0])
113
- btn1 = gr.Button("SYNC MY DNA", variant="primary")
114
  btn1.click(lambda: gr.update(selected=1), None, tabs)
115
 
116
  with gr.Tab("02. DISCOVERY", id=1):
117
- with gr.Row():
118
- q_in = gr.Textbox(label="What are you craving?", placeholder="e.g. Pasta", scale=4)
119
- btn2 = gr.Button("FIND", variant="primary", scale=1)
120
  out_html = gr.HTML()
121
- btn2.click(run_discovery, [q_in, u_origin, u_hobbies_input, u_style], out_html)
122
 
123
  with gr.Tab("03. SHARE", id=2):
124
- gr.Markdown("### 📸 Share your culinary discovery with the community")
125
- s_dish = gr.Textbox(label="Dish Name")
126
- s_rest = gr.Textbox(label="Restaurant")
127
- s_rev = gr.Textbox(label="Your Review", lines=3)
128
- s_btn = gr.Button("UPLOAD TO COMMUNITY")
129
- s_msg = gr.Markdown()
130
- s_btn.click(lambda: "### ✅ Thank you! Your review has been added to our database.", None, s_msg)
131
 
132
- # הפעלה
133
- demo.launch(allowed_paths=["."])
 
8
  from sentence_transformers import SentenceTransformer
9
  from sklearn.metrics.pairwise import cosine_similarity
10
 
11
+ # --- 1. פתרון שורש לתמונות: פריקה לתיקייה קבועה ---
12
+ IMAGE_DIR = "extracted_images"
13
  if os.path.exists('images.zip'):
14
+ with zipfile.ZipFile('images.zip', 'r') as zip_ref:
15
+ zip_ref.extractall(IMAGE_DIR)
 
 
 
 
16
 
 
17
  model = SentenceTransformer('all-MiniLM-L6-v2')
18
 
19
+ def load_data():
20
+ df = pd.read_csv('bitewise_clean_dataset.csv').fillna("N/A")
21
+ dish_emb = np.load('BiteWise_Dish_Embeddings.npy')
22
+ with open('BiteWise_User_Embeddings.pkl', 'rb') as f:
23
+ user_emb = pickle.load(f)
24
+ if isinstance(user_emb, list): user_emb = np.array(user_emb)
25
+ min_l = min(len(df), len(dish_emb), len(user_emb))
26
+ return df.iloc[:min_l], dish_emb[:min_l], user_emb[:min_l]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ main_df, dish_embeddings, user_embeddings = load_data()
 
 
 
29
 
30
+ # --- 2. לוגיקת 3 ממליצים שונים ---
31
+ def run_discovery(query, origin, hobbies, style):
 
 
 
32
  alpha = 0.7
33
  q_vec = model.encode([str(query)])
34
+ u_dna = f"Origin: {origin}, Hobbies: {hobbies}, Style: {style}"
35
+ u_vec = model.encode([u_dna])
36
 
37
  dish_sim = cosine_similarity(q_vec, dish_embeddings).flatten()
38
  user_sim = cosine_similarity(u_vec, user_embeddings).flatten()
 
40
 
41
  res = main_df.copy()
42
  res['score'] = final_scores
 
43
 
44
+ # בחירת 3 ממליצים שונים (מסננים לפי שם משתמש ב-CSV)
45
+ top_matches = []
46
+ used_users = set()
47
+
48
+ sorted_res = res.sort_values('score', ascending=False)
49
+
50
+ for _, row in sorted_res.iterrows():
51
+ # לוגיקה: אם המשתמש (הממליץ) עוד לא הופיע, נוסיף אותו
52
+ if row['user_name'] not in used_users:
53
+ top_matches.append(row)
54
+ used_users.add(row['user_name'])
55
+ if len(top_matches) == 3:
56
+ break
57
+
58
  html_output = ""
59
+ for row in top_matches:
60
+ idx = row.name # האינדקס המקורי מה-CSV
61
  pct = f"{min(98.8, 88 + (row['score'] * 20)):.1f}%"
62
 
63
+ # חיפוש תמונה (שורש הבעיה: נתיב מלא)
64
+ pattern = os.path.join(IMAGE_DIR, "**", f"dish_{idx}_*.jpg")
65
  files = glob.glob(pattern, recursive=True)
66
  img_url = f"file/{files[0]}" if files else "https://via.placeholder.com/300?text=BiteWise"
67
 
68
  html_output += f"""
69
+ <div style="border: 1px solid #D7CCC8; border-radius: 12px; padding: 20px; margin-bottom: 30px; background: white; box-shadow: 0 4px 15px rgba(0,0,0,0.05);">
70
+ <div style="background: #EFEBE9; padding: 10px 15px; border-radius: 8px; margin-bottom: 15px; border-right: 5px solid #3E2723;">
71
+ <p style="margin:0; color:#3E2723; font-size: 0.9em;">
72
+ <b>Culinary Twin:</b> {row['user_name']} from {row['user_origin']}
73
+ (Loves {row['user_hobbies']} | Style: {row['user_fashion_style']})
74
+ </p>
75
+ </div>
76
+ <div style="display: flex; gap: 20px; align-items: start;">
77
+ <img src="{img_url}" style="width: 220px; height: 220px; object-fit: cover; border-radius: 8px;">
78
+ <div style="flex: 1;">
79
+ <div style="display: flex; justify-content: space-between;">
80
+ <h2 style="margin: 0; color: #3E2723; font-family: Serif;">{row['dish_name']}</h2>
81
+ <span style="background: #3E2723; color: white; padding: 4px 12px; border-radius: 20px; font-size: 0.8em;">{pct} Match</span>
82
+ </div>
83
+ <p style="color: #7F4F24; margin: 5px 0; font-weight: 600;">@{row['restaurant_name']}</p>
84
+ <p style="font-style: italic; color: #5D4037; margin: 15px 0;">"{row['taste_review']}"</p>
85
+ <div style="display: flex; gap: 8px;">
86
+ <span style="background: #F5F1EE; color: #7F4F24; padding: 3px 8px; border-radius: 4px; font-size: 0.75em;">{row['food_vibe']}</span>
87
+ <span style="background: #F5F1EE; color: #7F4F24; padding: 3px 8px; border-radius: 4px; font-size: 0.75em;">⭐ {row['rating']}</span>
88
+ </div>
89
  </div>
90
  </div>
91
  </div>
92
  """
93
  return html_output
94
 
95
+ # --- 3. ממשק חדש (ללא כתום) ---
96
+ custom_css = """
97
+ .gradio-container { background-color: #FAF9F6 !important; }
98
+ button.primary { background: #3E2723 !important; border: none !important; }
99
+ button.primary:hover { background: #5D4037 !important; }
100
+ .tabs { border-bottom: 2px solid #D7CCC8 !important; }
101
+ """
102
+
103
+ with gr.Blocks(css=custom_css) as demo:
104
+ gr.HTML("<h1 style='text-align: center; color: #3E2723; font-family: Serif; font-size: 3em;'>BiteWise</h1>")
105
 
106
  with gr.Tabs() as tabs:
107
  with gr.Tab("01. YOUR DNA", id=0):
108
  with gr.Row():
109
+ u_name = gr.Textbox(label="Your Name")
110
+ u_origin = gr.Dropdown(list(main_df['user_origin'].unique()), label="Origin", value="Tel Aviv")
111
  with gr.Row():
112
+ u_hobbies = gr.Dropdown(list(main_df['user_hobbies'].unique()), label="Hobbies")
113
+ u_style = gr.Dropdown(list(main_df['user_fashion_style'].unique()), label="Style")
114
+ btn1 = gr.Button("SYNC DNA", variant="primary")
115
  btn1.click(lambda: gr.update(selected=1), None, tabs)
116
 
117
  with gr.Tab("02. DISCOVERY", id=1):
118
+ q_in = gr.Textbox(label="What are you craving?", placeholder="e.g. Pasta")
119
+ btn2 = gr.Button("FIND MY MATCHES", variant="primary")
 
120
  out_html = gr.HTML()
121
+ btn2.click(run_discovery, [q_in, u_origin, u_hobbies, u_style], out_html)
122
 
123
  with gr.Tab("03. SHARE", id=2):
124
+ gr.Markdown("### Share a Review")
125
+ gr.Textbox(label="Dish")
126
+ gr.Textbox(label="Restaurant")
127
+ gr.Textbox(label="Review", lines=3)
128
+ gr.Button("UPLOAD", variant="primary")
 
 
129
 
130
+ # הוספת allowed_paths לתיקיית התמונות שפרקנו
131
+ demo.launch(allowed_paths=[IMAGE_DIR])