matanzig commited on
Commit
78646c1
Β·
verified Β·
1 Parent(s): ec7cfbf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +112 -8
app.py CHANGED
@@ -4,8 +4,9 @@ import numpy as np
4
  import torch
5
  from transformers import CLIPProcessor, CLIPModel
6
  from datasets import load_dataset
7
- from diffusers import StableDiffusionPipeline
8
  from sklearn.metrics.pairwise import cosine_similarity
 
9
  import warnings
10
  warnings.filterwarnings('ignore')
11
 
@@ -120,6 +121,21 @@ button.primary:hover {
120
  box-shadow: 0 0 15px rgba(255, 215, 0, 0.2) !important;
121
  transform: translateY(-2px) !important;
122
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  """
124
 
125
  # --- 1. Load Dataset & Embeddings ---
@@ -143,6 +159,11 @@ pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4",
143
  pipe = pipe.to(device)
144
  pipe.enable_attention_slicing()
145
 
 
 
 
 
 
146
  # --- 3. Core Engine Logic ---
147
 
148
  def get_recommendations_from_vector(user_vector):
@@ -197,6 +218,43 @@ def generate_and_recommend(prompt):
197
 
198
  return generated_image, rec1, score1, rec2, score2, rec3, score3
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  # --- 4. Gradio User Interface (Premium UI) ---
201
 
202
  custom_theme = gr.themes.Monochrome(
@@ -205,7 +263,7 @@ custom_theme = gr.themes.Monochrome(
205
  font=[gr.themes.GoogleFont("Montserrat"), "ui-sans-serif", "system-ui", "sans-serif"]
206
  )
207
 
208
- with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
209
  gr.HTML("""
210
  <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; margin-top: 20px;">
211
  <img src="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/viss1.jpeg"
@@ -216,10 +274,10 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
216
  </div>
217
  """)
218
 
219
- with gr.Tabs():
220
 
221
  # --- TAB 1: Classic Search by Image ---
222
- with gr.TabItem("πŸ–ΌοΈ Search by Image"):
223
  gr.Markdown("Upload an inspiration photo to instantly discover visually and stylistically similar rooms from our curated catalog.")
224
  with gr.Row():
225
  with gr.Column(scale=1):
@@ -231,12 +289,15 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
231
  with gr.Column():
232
  img_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
233
  img_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
234
  with gr.Column():
235
  img_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
236
  img_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
237
  with gr.Column():
238
  img_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
239
  img_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
240
 
241
  img_submit_btn.click(
242
  fn=search_by_image, inputs=[image_input],
@@ -244,7 +305,7 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
244
  )
245
 
246
  # --- TAB 2: Fast Text Search (CLIP Multi-modal) ---
247
- with gr.TabItem("πŸ” Fast Text Search"):
248
  gr.Markdown("Describe a room in text. Our multi-modal vision engine will instantly search the catalog for matching designs.")
249
  with gr.Row():
250
  with gr.Column(scale=1):
@@ -265,12 +326,15 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
265
  with gr.Column():
266
  ft_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
267
  ft_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
268
  with gr.Column():
269
  ft_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
270
  ft_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
271
  with gr.Column():
272
  ft_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
273
  ft_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
274
 
275
  fast_txt_submit_btn.click(
276
  fn=search_by_text_only, inputs=[fast_text_input],
@@ -278,7 +342,7 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
278
  )
279
 
280
  # --- TAB 3: Advanced GenAI Search ---
281
- with gr.TabItem("✨ AI Design Studio"):
282
  gr.Markdown("Describe your ideal space. Our Generative AI will draft a concept from scratch, and then find the closest real-world equivalents.")
283
  with gr.Row():
284
  with gr.Column(scale=1):
@@ -291,21 +355,61 @@ with gr.Blocks(css=custom_css, theme=custom_theme) as demo:
291
  with gr.Column():
292
  txt_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
293
  txt_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
294
  with gr.Column():
295
  txt_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
296
  txt_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
297
  with gr.Column():
298
  txt_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
299
  txt_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
 
300
 
301
  txt_submit_btn.click(
302
  fn=generate_and_recommend, inputs=[text_input],
303
  outputs=[gen_output, txt_rec1, txt_score1, txt_rec2, txt_score2, txt_rec3, txt_score3]
304
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
 
306
- # --- TAB 4: Presentation Video ---
307
- with gr.TabItem("πŸŽ₯ Presentation Video"):
 
 
 
 
 
308
  gr.Markdown("### πŸŽ“ Project Presentation & Walkthrough \nWatch the video below to see a full walkthrough of the dataset, EDA, model pipeline, and the live application.")
309
  gr.Video(value="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/A3.presentation.mp4", interactive=False)
310
 
 
 
 
 
 
 
 
 
 
 
311
  demo.launch()
 
4
  import torch
5
  from transformers import CLIPProcessor, CLIPModel
6
  from datasets import load_dataset
7
+ from diffusers import StableDiffusionPipeline, StableDiffusionInpaintPipeline
8
  from sklearn.metrics.pairwise import cosine_similarity
9
+ from PIL import Image
10
  import warnings
11
  warnings.filterwarnings('ignore')
12
 
 
121
  box-shadow: 0 0 15px rgba(255, 215, 0, 0.2) !important;
122
  transform: translateY(-2px) !important;
123
  }
124
+
125
+ .edit-btn {
126
+ background: rgba(20, 20, 20, 0.8) !important;
127
+ border: 1px solid rgba(255, 215, 0, 0.3) !important;
128
+ color: #ffd700 !important;
129
+ font-size: 0.9rem !important;
130
+ margin-top: 5px !important;
131
+ transition: all 0.3s ease !important;
132
+ }
133
+
134
+ .edit-btn:hover {
135
+ background: rgba(255, 215, 0, 0.15) !important;
136
+ border: 1px solid rgba(255, 215, 0, 0.8) !important;
137
+ box-shadow: 0 0 10px rgba(255, 215, 0, 0.3) !important;
138
+ }
139
  """
140
 
141
  # --- 1. Load Dataset & Embeddings ---
 
159
  pipe = pipe.to(device)
160
  pipe.enable_attention_slicing()
161
 
162
+ print("Loading Stable Diffusion Inpainting Model...")
163
+ inpaint_pipe = StableDiffusionInpaintPipeline.from_pretrained("runwayml/stable-diffusion-inpainting", torch_dtype=torch.float32)
164
+ inpaint_pipe = inpaint_pipe.to(device)
165
+ inpaint_pipe.enable_attention_slicing()
166
+
167
  # --- 3. Core Engine Logic ---
168
 
169
  def get_recommendations_from_vector(user_vector):
 
218
 
219
  return generated_image, rec1, score1, rec2, score2, rec3, score3
220
 
221
+ def process_magic_edit(edit_dict, prompt):
222
+ if not edit_dict or not prompt:
223
+ return None, None, "", None, "", None, ""
224
+
225
+ try:
226
+ # Extract the background and mask drawn by the user
227
+ bg = edit_dict["background"].convert("RGB")
228
+ if len(edit_dict["layers"]) > 0:
229
+ mask = edit_dict["layers"][0].split()[-1] # Extract the alpha channel as the mask
230
+ else:
231
+ mask = Image.new("L", bg.size, 0) # Blank mask fallback
232
+
233
+ bg = bg.resize((512, 512))
234
+ mask = mask.resize((512, 512))
235
+
236
+ # Apply Inpainting
237
+ edited_image = inpaint_pipe(prompt=prompt, image=bg, mask_image=mask, num_inference_steps=20).images[0]
238
+
239
+ # Find new recommendations based on the edited image
240
+ inputs = processor(images=edited_image, return_tensors="pt").to(device)
241
+ with torch.no_grad():
242
+ features = clip_model.get_image_features(**inputs)
243
+ if not isinstance(features, torch.Tensor):
244
+ features = features.pooler_output if hasattr(features, 'pooler_output') else features[0]
245
+
246
+ user_vector = features.cpu().numpy().flatten().reshape(1, -1)
247
+ rec1, score1, rec2, score2, rec3, score3 = get_recommendations_from_vector(user_vector)
248
+
249
+ return edited_image, rec1, score1, rec2, score2, rec3, score3
250
+ except Exception as e:
251
+ print(f"Error during Magic Edit: {e}")
252
+ return None, None, "", None, "", None, ""
253
+
254
+ def send_to_magic_edit(img):
255
+ """Helper function to transfer an image to the Magic Edit tab and switch focus to it."""
256
+ return img, gr.update(selected="tab_magic")
257
+
258
  # --- 4. Gradio User Interface (Premium UI) ---
259
 
260
  custom_theme = gr.themes.Monochrome(
 
263
  font=[gr.themes.GoogleFont("Montserrat"), "ui-sans-serif", "system-ui", "sans-serif"]
264
  )
265
 
266
+ with gr.Blocks(title="Visionary | AI Interior Design", css=custom_css, theme=custom_theme) as demo:
267
  gr.HTML("""
268
  <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; margin-top: 20px;">
269
  <img src="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/viss1.jpeg"
 
274
  </div>
275
  """)
276
 
277
+ with gr.Tabs() as main_tabs:
278
 
279
  # --- TAB 1: Classic Search by Image ---
280
+ with gr.TabItem("πŸ–ΌοΈ Search by Image", id="tab1"):
281
  gr.Markdown("Upload an inspiration photo to instantly discover visually and stylistically similar rooms from our curated catalog.")
282
  with gr.Row():
283
  with gr.Column(scale=1):
 
289
  with gr.Column():
290
  img_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
291
  img_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
292
+ img_edit_btn1 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
293
  with gr.Column():
294
  img_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
295
  img_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
296
+ img_edit_btn2 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
297
  with gr.Column():
298
  img_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
299
  img_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
300
+ img_edit_btn3 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
301
 
302
  img_submit_btn.click(
303
  fn=search_by_image, inputs=[image_input],
 
305
  )
306
 
307
  # --- TAB 2: Fast Text Search (CLIP Multi-modal) ---
308
+ with gr.TabItem("πŸ” Fast Text Search", id="tab2"):
309
  gr.Markdown("Describe a room in text. Our multi-modal vision engine will instantly search the catalog for matching designs.")
310
  with gr.Row():
311
  with gr.Column(scale=1):
 
326
  with gr.Column():
327
  ft_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
328
  ft_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
329
+ ft_edit_btn1 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
330
  with gr.Column():
331
  ft_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
332
  ft_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
333
+ ft_edit_btn2 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
334
  with gr.Column():
335
  ft_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
336
  ft_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
337
+ ft_edit_btn3 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
338
 
339
  fast_txt_submit_btn.click(
340
  fn=search_by_text_only, inputs=[fast_text_input],
 
342
  )
343
 
344
  # --- TAB 3: Advanced GenAI Search ---
345
+ with gr.TabItem("✨ AI Design Studio", id="tab3"):
346
  gr.Markdown("Describe your ideal space. Our Generative AI will draft a concept from scratch, and then find the closest real-world equivalents.")
347
  with gr.Row():
348
  with gr.Column(scale=1):
 
355
  with gr.Column():
356
  txt_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
357
  txt_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
358
+ txt_edit_btn1 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
359
  with gr.Column():
360
  txt_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
361
  txt_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
362
+ txt_edit_btn2 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
363
  with gr.Column():
364
  txt_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
365
  txt_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
366
+ txt_edit_btn3 = gr.Button("πŸͺ„ Edit Match", elem_classes="edit-btn")
367
 
368
  txt_submit_btn.click(
369
  fn=generate_and_recommend, inputs=[text_input],
370
  outputs=[gen_output, txt_rec1, txt_score1, txt_rec2, txt_score2, txt_rec3, txt_score3]
371
  )
372
+
373
+ # --- TAB 4: Magic Edit (Inpainting) ---
374
+ with gr.TabItem("🎨 Magic Edit", id="tab_magic"):
375
+ gr.Markdown("Send a match here, paint over an object you want to change, and describe what you want instead.")
376
+ with gr.Row():
377
+ with gr.Column(scale=1):
378
+ magic_editor = gr.ImageEditor(label="1. Paint over object", type="pil", elem_classes="custom-card", brush=gr.Brush(colors=["#FFFFFF"]))
379
+ magic_prompt = gr.Textbox(label="2. What do you want instead?", placeholder="e.g., A modern yellow leather sofa", lines=2)
380
+ magic_submit_btn = gr.Button("Apply Magic Edit & Match", variant="primary")
381
+ magic_output = gr.Image(label="Magic Result", type="pil", elem_classes="custom-card")
382
+
383
+ with gr.Column(scale=2):
384
+ with gr.Row():
385
+ with gr.Column():
386
+ magic_rec1 = gr.Image(label="Top Match", elem_classes="custom-card")
387
+ magic_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
388
+ with gr.Column():
389
+ magic_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card")
390
+ magic_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
391
+ with gr.Column():
392
+ magic_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card")
393
+ magic_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score")
394
 
395
+ magic_submit_btn.click(
396
+ fn=process_magic_edit, inputs=[magic_editor, magic_prompt],
397
+ outputs=[magic_output, magic_rec1, magic_score1, magic_rec2, magic_score2, magic_rec3, magic_score3]
398
+ )
399
+
400
+ # --- TAB 5: Presentation Video ---
401
+ with gr.TabItem("πŸŽ₯ Presentation Video", id="tab_video"):
402
  gr.Markdown("### πŸŽ“ Project Presentation & Walkthrough \nWatch the video below to see a full walkthrough of the dataset, EDA, model pipeline, and the live application.")
403
  gr.Video(value="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/A3.presentation.mp4", interactive=False)
404
 
405
+ # --- Routing logic: Connect all "Edit Match" buttons to the Magic Editor ---
406
+ edit_buttons_and_sources = [
407
+ (img_edit_btn1, img_rec1), (img_edit_btn2, img_rec2), (img_edit_btn3, img_rec3),
408
+ (ft_edit_btn1, ft_rec1), (ft_edit_btn2, ft_rec2), (ft_edit_btn3, ft_rec3),
409
+ (txt_edit_btn1, txt_rec1), (txt_edit_btn2, txt_rec2), (txt_edit_btn3, txt_rec3)
410
+ ]
411
+
412
+ for btn, source_img in edit_buttons_and_sources:
413
+ btn.click(fn=send_to_magic_edit, inputs=[source_img], outputs=[magic_editor, main_tabs])
414
+
415
  demo.launch()