Spaces:
Sleeping
Sleeping
Update app.py
Browse files
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 |
-
|
| 307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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()
|