File size: 7,034 Bytes
fef3901
 
 
b8bb1b3
fef3901
723ac7f
8dbe1d6
8be8159
fef3901
 
 
b34e44f
8be8159
0fd2d60
8be8159
 
d8399cc
1459687
 
 
 
 
 
 
 
fef3901
 
1459687
8be8159
 
 
1459687
 
 
 
0e1fbe4
1459687
491c2dd
e8220c4
1459687
8be8159
e8220c4
8be8159
 
1459687
bcd2fbe
e8220c4
1459687
 
8be8159
1459687
 
 
491c2dd
1459687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e8220c4
d310c93
1459687
 
 
 
723ac7f
1459687
7abb4fe
 
1459687
 
7abb4fe
8be8159
7abb4fe
dbf6e24
e8220c4
1459687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b7dac73
1459687
 
 
 
 
 
b7dac73
8be8159
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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=["."])