BiteWise-App / app.py
galcomis's picture
Update app.py
1459687 verified
import gradio as gr
import pandas as pd
import numpy as np
import pickle
import os
import zipfile
import glob
import random
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# --- 1. הכנת תמונות ---
IMAGE_DIR = "extracted_images"
if os.path.exists('images.zip'):
with zipfile.ZipFile('images.zip', 'r') as zip_ref:
zip_ref.extractall(IMAGE_DIR)
def find_dish_image(idx):
pattern = os.path.join(IMAGE_DIR, "Dishes_Images", f"dish_{idx}_*.jpg")
files = glob.glob(pattern)
if not files:
files = glob.glob(os.path.join(IMAGE_DIR, "**", f"dish_{idx}_*.jpg"), recursive=True)
return f"file/{files[0]}" if files else "https://via.placeholder.com/400x400?text=BiteWise+Dish"
# --- 2. טעינה וסנכרון ברזל ---
model = SentenceTransformer('all-MiniLM-L6-v2')
def load_data():
df = pd.read_csv('bitewise_clean_dataset.csv').fillna("N/A")
dish_emb = np.load('BiteWise_Dish_Embeddings.npy')
with open('BiteWise_User_Embeddings.pkl', 'rb') as f:
u_emb = pickle.load(f)
if isinstance(u_emb, list): u_emb = np.array(u_emb)
min_l = min(len(df), len(dish_emb), len(u_emb))
return df.iloc[:min_l].reset_index(drop=True), dish_emb[:min_l], u_emb[:min_l]
main_df, dish_embeddings, user_embeddings = load_data()
NAMES = ["James Miller", "Sarah Johnson", "Michael Brown", "Emily Davis", "Robert Wilson"]
# --- 3. מנוע החיפוש ---
def run_discovery(query, origin, hobbies, style):
q_vec = model.encode([str(query)])
u_dna = f"Origin: {origin}, Hobbies: {hobbies}, Style: {style}"
u_vec = model.encode([u_dna])
scores = (cosine_similarity(q_vec, dish_embeddings).flatten() * 0.7) + (cosine_similarity(u_vec, user_embeddings).flatten() * 0.3)
res = main_df.copy()
res['similarity_score'] = scores
top = res.sort_values('similarity_score', ascending=False).head(10)
html = ""
seen = set()
for idx, row in top.iterrows():
u_name = row['user_name'] if row['user_name'] != "N/A" else random.choice(NAMES)
if u_name not in seen:
pct = f"{min(99.0, 85 + (row['similarity_score'] * 15)):.1f}%"
img = find_dish_image(idx)
html += f"""
<div style="border: 1px solid #C4A484; padding: 25px; margin-bottom: 25px; background: #FFF9F5; border-left: 10px solid #3E2723; display: flex; gap: 20px; color: #3E2723;">
<img src="{img}" style="width: 200px; height: 200px; object-fit: cover; border: 1px solid #D2B48C; background: white;">
<div style="flex: 1;">
<div style="display: flex; justify-content: space-between;">
<h2 style="margin: 0; font-family: Serif;">{row['dish_name']}</h2>
<span style="background: #3E2723; color: white; padding: 2px 10px; border-radius: 20px; font-size: 0.8em;">{pct} MATCH</span>
</div>
<p style="margin: 5px 0; font-weight: bold;">📍 {row['restaurant_name']} | {row.get('cuisine_type', 'Gourmet')}</p>
<p style="font-style: italic;">"{row['taste_review']}"</p>
<div style="margin: 10px 0;">
<span style="background: #EEDDCC; padding: 4px 8px; border: 1px solid #D2B48C; font-size: 0.8em;">💰 {row.get('price_range', '$$')}</span>
<span style="background: #EEDDCC; padding: 4px 8px; border: 1px solid #D2B48C; font-size: 0.8em;">👥 BEST FOR: {row.get('best_for', 'Friends')}</span>
</div>
<p style="font-size: 0.85em;"><b>Twin:</b> {u_name} from {row['user_origin']}</p>
</div>
</div>
"""
seen.add(u_name)
if len(seen) == 3: break
return html
# --- 4. הממשק (זרימת מסכים אמיתית) ---
custom_css = """
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,700;1,400&display=swap');
.gradio-container { background-color: #FDFCF8 !important; }
button.primary { background: #3E2723 !important; color: white !important; border-radius: 0px !important; text-transform: uppercase; letter-spacing: 2px; }
"""
with gr.Blocks(css=custom_css) as demo:
gr.HTML("<h1 style='text-align: center; color: #3E2723; font-family: \"Playfair Display\", serif; font-size: 4em; font-style: italic; border-bottom: 2px double #D2B48C; margin-bottom: 40px;'>BiteWise</h1>")
# מסך 1: DNA
with gr.Column(visible=True) as screen_dna:
with gr.Row():
u_n = gr.Textbox(label="IDENTIFICATION")
u_o = gr.Dropdown(list(main_df['user_origin'].unique()), label="ORIGIN", value="Tel Aviv")
with gr.Row():
u_h = gr.Dropdown(list(main_df['user_hobbies'].unique()), label="INTERESTS")
u_s = gr.Dropdown(list(main_df['user_fashion_style'].unique()) + ["Vintage/Retro"], label="STYLE", value="Vintage/Retro")
btn_sync = gr.Button("SYNC PERSONALITY", variant="primary")
# מסך 2: Discovery
with gr.Column(visible=False) as screen_discovery:
q_in = gr.Textbox(label="CRAVING", placeholder="What are you in the mood for?")
btn_search = gr.Button("COMMENCE SEARCH", variant="primary")
out_html = gr.HTML()
with gr.Row():
btn_back_to_dna = gr.Button("⬅ BACK TO DNA")
btn_to_archive = gr.Button("✚ ADD DISCOVERY")
# מסך 3: Archive
with gr.Column(visible=False) as screen_archive:
gr.Markdown("### ARCHIVE A NEW CULINARY DISCOVERY")
with gr.Row():
gr.Textbox(label="DISH")
gr.Textbox(label="ESTABLISHMENT")
gr.Textbox(label="REVIEW", lines=3)
btn_submit = gr.Button("SUBMIT & SHARE", variant="primary")
status_msg = gr.Markdown()
btn_back_to_disc = gr.Button("⬅ BACK TO DISCOVERY")
# פונקציות מעבר בין מסכים
def show_discovery(): return {screen_dna: gr.update(visible=False), screen_discovery: gr.update(visible=True), screen_archive: gr.update(visible=False)}
def show_dna(): return {screen_dna: gr.update(visible=True), screen_discovery: gr.update(visible=False), screen_archive: gr.update(visible=False)}
def show_archive(): return {screen_dna: gr.update(visible=False), screen_discovery: gr.update(visible=False), screen_archive: gr.update(visible=True)}
btn_sync.click(show_discovery, None, [screen_dna, screen_discovery, screen_archive])
btn_back_to_dna.click(show_dna, None, [screen_dna, screen_discovery, screen_archive])
btn_to_archive.click(show_archive, None, [screen_dna, screen_discovery, screen_archive])
btn_back_to_disc.click(show_discovery, None, [screen_dna, screen_discovery, screen_archive])
btn_search.click(run_discovery, [q_in, u_o, u_h, u_s], out_html)
btn_submit.click(lambda: "### Thank you! \nYour discovery has been successfully shared.", None, status_msg)
demo.launch(allowed_paths=["."])