MatanKriel commited on
Commit
26e1d1d
Β·
verified Β·
1 Parent(s): b2aba87

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -17
app.py CHANGED
@@ -2,6 +2,7 @@ import gradio as gr
2
  import torch
3
  import pandas as pd
4
  import numpy as np
 
5
  from PIL import Image
6
  from transformers import AutoProcessor, AutoModel
7
  from datasets import load_dataset
@@ -32,13 +33,12 @@ try:
32
  print("βœ… System Ready!")
33
  except Exception as e:
34
  print(f"❌ Error loading parquet file: {e}")
35
- print("⚠️ Please ensure 'food_embeddings_siglip.parquet' is uploaded to the Files tab.")
36
  db_features = None
37
 
38
- # --- 4. CORE SEARCH LOGIC ---
39
  def find_best_matches(query_features, top_k=3):
40
  if db_features is None:
41
- return [None] * top_k # Return empty list if DB failed
42
 
43
  # Normalize query
44
  query_features = F.normalize(query_features, p=2, dim=1)
@@ -50,9 +50,20 @@ def find_best_matches(query_features, top_k=3):
50
  results = []
51
  for idx, score in zip(indices[0], scores[0]):
52
  idx = idx.item()
53
- img = dataset[idx]['image']
 
 
 
 
 
 
 
 
54
  label = df.iloc[idx]['label_name']
55
- results.append((img, f"{label} ({score:.2f})"))
 
 
 
56
  return results
57
 
58
  # --- 5. GRADIO FUNCTIONS ---
@@ -70,24 +81,87 @@ def search_by_text(input_text):
70
  features = model.get_text_features(**inputs)
71
  return find_best_matches(features)
72
 
73
- # --- 6. BUILD UI ---
74
- with gr.Blocks(title="Food Matcher AI") as demo:
75
- gr.Markdown("# πŸ” Visual Dish Matcher")
76
- gr.Markdown("Upload a photo of food (or describe it) to find similar dishes in our database.")
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- with gr.Tab("Image Search"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  with gr.Row():
80
- img_input = gr.Image(type="pil", label="Upload Food Image")
81
- img_gallery = gr.Gallery(label="Top Matches")
82
- btn_img = gr.Button("Find Similar Dishes")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  btn_img.click(search_by_image, inputs=img_input, outputs=img_gallery)
84
 
85
- with gr.Tab("Text Search"):
86
  with gr.Row():
87
- txt_input = gr.Textbox(label="Describe the food (e.g., 'Spicy Tacos')")
88
- txt_gallery = gr.Gallery(label="Top Matches")
89
- btn_txt = gr.Button("Search by Description")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  btn_txt.click(search_by_text, inputs=txt_input, outputs=txt_gallery)
91
 
 
 
 
 
92
  # Launch
93
  demo.launch()
 
2
  import torch
3
  import pandas as pd
4
  import numpy as np
5
+ import os
6
  from PIL import Image
7
  from transformers import AutoProcessor, AutoModel
8
  from datasets import load_dataset
 
33
  print("βœ… System Ready!")
34
  except Exception as e:
35
  print(f"❌ Error loading parquet file: {e}")
 
36
  db_features = None
37
 
38
+ # --- 4. CORE SEARCH LOGIC (FIXED) ---
39
  def find_best_matches(query_features, top_k=3):
40
  if db_features is None:
41
+ return []
42
 
43
  # Normalize query
44
  query_features = F.normalize(query_features, p=2, dim=1)
 
50
  results = []
51
  for idx, score in zip(indices[0], scores[0]):
52
  idx = idx.item()
53
+
54
+ # CRITICAL FIX: Save image to disk instead of returning raw PIL object
55
+ # This prevents the "Too much data" error
56
+ img_data = dataset[idx]['image']
57
+
58
+ # Create a unique filename for the cache
59
+ save_path = f"temp_result_{idx}.jpg"
60
+ img_data.save(save_path)
61
+
62
  label = df.iloc[idx]['label_name']
63
+
64
+ # Return the PATH (string) instead of the IMAGE (object)
65
+ results.append((save_path, f"{label} ({score:.2f})"))
66
+
67
  return results
68
 
69
  # --- 5. GRADIO FUNCTIONS ---
 
81
  features = model.get_text_features(**inputs)
82
  return find_best_matches(features)
83
 
84
+ # --- 6. BUILD UI (Centered & Fixed) ---
85
+
86
+ # CSS to center the app and limit width to 1000px
87
+ custom_css = """
88
+ .gradio-container {
89
+ width: 100%;
90
+ max-width: 1000px;
91
+ margin: 0 auto !important;
92
+ }
93
+ h1 {
94
+ text-align: center;
95
+ color: #E67E22;
96
+ }
97
+ """
98
+
99
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="Food Matcher AI") as demo:
100
 
101
+ # --- Header ---
102
+ with gr.Row():
103
+ gr.Markdown("# πŸ” Visual Dish Matcher (SigLIP)")
104
+
105
+ gr.Markdown(
106
+ "Upload a food photo or describe a craving. We'll find the closest matches from our database.",
107
+ elem_classes=["center-text"]
108
+ )
109
+
110
+ # --- Video Accordion ---
111
+ with gr.Accordion("πŸ“Ί Watch Demo Video", open=False):
112
+ gr.HTML('<div style="display:flex; justify-content:center;"><iframe width="560" height="315" src="https://www.youtube.com/embed/IXeIxYHi0Es" frameborder="0" allowfullscreen></iframe></div>')
113
+
114
+ # --- Main Interface ---
115
+ with gr.Tab("πŸ–ΌοΈ Search by Image"):
116
+ # Split layout: 1/3 Left (Input), 2/3 Right (Results)
117
  with gr.Row():
118
+
119
+ # --- Left Column: Input ---
120
+ with gr.Column(scale=1):
121
+ img_input = gr.Image(
122
+ type="pil",
123
+ label="Your Photo",
124
+ height=300 # Fixed height
125
+ )
126
+ btn_img = gr.Button("πŸ” Find Matches", variant="primary", size="lg")
127
+
128
+ # --- Right Column: Output ---
129
+ with gr.Column(scale=2):
130
+ img_gallery = gr.Gallery(
131
+ label="Similar Dishes",
132
+ columns=3,
133
+ height=350,
134
+ object_fit="contain"
135
+ )
136
+
137
  btn_img.click(search_by_image, inputs=img_input, outputs=img_gallery)
138
 
139
+ with gr.Tab("πŸ“ Search by Text"):
140
  with gr.Row():
141
+
142
+ # --- Left Column: Input ---
143
+ with gr.Column(scale=1):
144
+ txt_input = gr.Textbox(
145
+ label="Describe it",
146
+ placeholder="e.g. 'Spicy Tacos' or 'Chocolate Cake'",
147
+ lines=4
148
+ )
149
+ btn_txt = gr.Button("πŸ” Search", variant="primary", size="lg")
150
+
151
+ # --- Right Column: Output ---
152
+ with gr.Column(scale=2):
153
+ txt_gallery = gr.Gallery(
154
+ label="Similar Dishes",
155
+ columns=3,
156
+ height=350,
157
+ object_fit="contain"
158
+ )
159
+
160
  btn_txt.click(search_by_text, inputs=txt_input, outputs=txt_gallery)
161
 
162
+ # --- Footer ---
163
+ gr.Markdown("---")
164
+ gr.Markdown("By Matan Kriel & Odeya Shmuel | Powered by Google SigLIP", elem_id="footer")
165
+
166
  # Launch
167
  demo.launch()