Spaces:
Running
Running
| import gradio as gr | |
| import pandas as pd | |
| import numpy as np | |
| import torch | |
| from transformers import CLIPProcessor, CLIPModel | |
| from datasets import load_dataset | |
| from diffusers import StableDiffusionPipeline | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| custom_css = """ | |
| body { | |
| background-image: url('https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/viss.jpeg'); | |
| background-size: 130% 130%; | |
| background-position: 0% 0%; | |
| background-attachment: fixed; | |
| animation: panBackground 40s ease-in-out infinite alternate; | |
| } | |
| @keyframes panBackground { | |
| 0% { background-position: 0% 0%; } | |
| 100% { background-position: 100% 100%; } | |
| } | |
| .gradio-container { | |
| background: rgba(20, 20, 20, 0.75) !important; | |
| border-radius: 20px; | |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5); | |
| backdrop-filter: blur(5px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .visionary-title { | |
| font-size: 3.5rem; | |
| font-weight: 900; | |
| text-align: center; | |
| letter-spacing: 4px; | |
| margin-bottom: 5px; | |
| margin-top: 15px; | |
| background: linear-gradient(270deg, #b8860b, #ffd700, #fff8dc, #b8860b); | |
| background-size: 200% 200%; | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| animation: goldShine 4s ease infinite; | |
| transition: transform 0.3s ease, text-shadow 0.3s ease; | |
| cursor: pointer; | |
| } | |
| .visionary-title:hover { | |
| transform: scale(1.03); | |
| text-shadow: 0px 0px 20px rgba(255, 215, 0, 0.4); | |
| } | |
| @keyframes goldShine { | |
| 0% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| .visionary-subtitle { | |
| text-align: center; | |
| color: rgba(255, 255, 255, 0.7); | |
| font-size: 1.2rem; | |
| letter-spacing: 2px; | |
| margin-bottom: 30px; | |
| } | |
| .custom-card { | |
| background: rgba(15, 15, 15, 0.6) !important; | |
| border-radius: 20px !important; | |
| border: 1px solid rgba(255, 215, 0, 0.15) !important; | |
| transition: all 0.3s ease-in-out !important; | |
| overflow: hidden !important; | |
| box-shadow: 0 4px 15px rgba(0,0,0,0.4) !important; | |
| } | |
| .custom-card:hover { | |
| transform: translateY(-5px) scale(1.01) !important; | |
| border: 1px solid rgba(255, 215, 0, 0.6) !important; | |
| box-shadow: 0 10px 30px rgba(255, 215, 0, 0.15) !important; | |
| } | |
| .custom-card img { | |
| transition: transform 0.4s ease !important; | |
| } | |
| .custom-card:hover img { | |
| transform: scale(1.05) !important; | |
| } | |
| .custom-score { | |
| background: rgba(10, 10, 10, 0.8) !important; | |
| border-radius: 12px !important; | |
| border: 1px solid rgba(255, 215, 0, 0.1) !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| .custom-score:hover { | |
| border: 1px solid rgba(255, 215, 0, 0.4) !important; | |
| box-shadow: 0 0 15px rgba(255, 215, 0, 0.1) !important; | |
| } | |
| .custom-score:hover textarea { | |
| color: #ffd700 !important; | |
| } | |
| button.primary { | |
| background: linear-gradient(90deg, #151515, #252525) !important; | |
| border: 1px solid rgba(255, 215, 0, 0.4) !important; | |
| color: #ffd700 !important; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| font-weight: bold !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| button.primary:hover { | |
| background: linear-gradient(90deg, #252525, #353535) !important; | |
| border: 1px solid rgba(255, 215, 0, 0.8) !important; | |
| box-shadow: 0 0 15px rgba(255, 215, 0, 0.2) !important; | |
| transform: translateY(-2px) !important; | |
| } | |
| """ | |
| # --- 1. Load Dataset & Embeddings --- | |
| print("Loading Dataset and Embeddings...") | |
| full_ds = load_dataset("tonijhanel/my_interior_design_dataset", split="train") | |
| sample_dataset = full_ds.shuffle(seed=42).select(range(5000)) | |
| df_saved = pd.read_parquet("interior_embeddings.parquet") | |
| dataset_matrix = np.array(df_saved['embedding'].tolist()) | |
| # --- 2. Load Deep Learning Models --- | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| print("Loading CLIP Model...") | |
| clip_id = "openai/clip-vit-base-patch32" | |
| processor = CLIPProcessor.from_pretrained(clip_id) | |
| clip_model = CLIPModel.from_pretrained(clip_id).to(device) | |
| print("Loading Stable Diffusion Model...") | |
| pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", torch_dtype=torch.float32) | |
| pipe = pipe.to(device) | |
| pipe.enable_attention_slicing() | |
| # --- 3. Core Engine Logic --- | |
| def get_recommendations_from_vector(user_vector): | |
| similarities = cosine_similarity(user_vector, dataset_matrix)[0] | |
| top_indices = np.argsort(similarities)[-3:][::-1] | |
| top_scores = similarities[top_indices] | |
| recs = [sample_dataset[int(i)]['image'] for i in top_indices] | |
| scores = [f"Match: {score*100:.1f}%" for score in top_scores] | |
| return recs[0], scores[0], recs[1], scores[1], recs[2], scores[2] | |
| def search_by_image(user_image): | |
| if user_image is None: | |
| return None, "", None, "", None, "" | |
| inputs = processor(images=user_image, return_tensors="pt").to(device) | |
| with torch.no_grad(): | |
| features = clip_model.get_image_features(**inputs) | |
| if not isinstance(features, torch.Tensor): | |
| features = features.pooler_output if hasattr(features, 'pooler_output') else features[0] | |
| user_vector = features.cpu().numpy().flatten().reshape(1, -1) | |
| return get_recommendations_from_vector(user_vector) | |
| def search_by_text_only(prompt): | |
| if not prompt: | |
| return None, "", None, "", None, "" | |
| inputs = processor(text=[prompt], return_tensors="pt", padding=True).to(device) | |
| with torch.no_grad(): | |
| features = clip_model.get_text_features(**inputs) | |
| if not isinstance(features, torch.Tensor): | |
| features = features.pooler_output if hasattr(features, 'pooler_output') else features[0] | |
| user_vector = features.cpu().numpy().flatten().reshape(1, -1) | |
| return get_recommendations_from_vector(user_vector) | |
| def generate_and_recommend(prompt): | |
| if not prompt: | |
| return None, None, "", None, "", None, "" | |
| generated_image = pipe(prompt, num_inference_steps=15).images[0] | |
| inputs = processor(images=generated_image, return_tensors="pt").to(device) | |
| with torch.no_grad(): | |
| features = clip_model.get_image_features(**inputs) | |
| if not isinstance(features, torch.Tensor): | |
| features = features.pooler_output if hasattr(features, 'pooler_output') else features[0] | |
| user_vector = features.cpu().numpy().flatten().reshape(1, -1) | |
| rec1, score1, rec2, score2, rec3, score3 = get_recommendations_from_vector(user_vector) | |
| return generated_image, rec1, score1, rec2, score2, rec3, score3 | |
| # --- 4. Gradio User Interface (Premium UI) --- | |
| custom_theme = gr.themes.Monochrome( | |
| primary_hue="neutral", | |
| secondary_hue="neutral", | |
| font=[gr.themes.GoogleFont("Montserrat"), "ui-sans-serif", "system-ui", "sans-serif"] | |
| ) | |
| with gr.Blocks(title="Visionary | AI Interior Design", css=custom_css, theme=custom_theme) as demo: | |
| gr.HTML(""" | |
| <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; margin-top: 20px;"> | |
| <img src="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/viss1.jpeg" | |
| style="height: 110px; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.8); margin-bottom: 10px;"> | |
| <h1 class="visionary-title">VISIONARY</h1> | |
| <div class="visionary-subtitle">AI-Powered Interior Design Engine</div> | |
| </div> | |
| """) | |
| with gr.Tabs(): | |
| # --- TAB 1: Classic Search by Image --- | |
| with gr.TabItem("๐ผ๏ธ Search by Image"): | |
| gr.Markdown("Upload an inspiration photo to instantly discover visually and stylistically similar rooms from our curated catalog.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| image_input = gr.Image(label="Upload Inspiration", type="pil", elem_classes="custom-card") | |
| img_submit_btn = gr.Button("Find Matches (Instant)", variant="primary") | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| with gr.Column(): | |
| img_rec1 = gr.Image(label="Top Match", elem_classes="custom-card") | |
| img_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| img_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card") | |
| img_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| img_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card") | |
| img_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| img_submit_btn.click( | |
| fn=search_by_image, inputs=[image_input], | |
| outputs=[img_rec1, img_score1, img_rec2, img_score2, img_rec3, img_score3] | |
| ) | |
| # --- TAB 2: Fast Text Search (CLIP Multi-modal) --- | |
| with gr.TabItem("๐ Fast Text Search"): | |
| gr.Markdown("Describe a room in text. Our multi-modal vision engine will instantly search the catalog for matching designs.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| fast_text_input = gr.Textbox(label="Search Query", placeholder="e.g., A minimalist industrial bedroom...", lines=3) | |
| fast_txt_submit_btn = gr.Button("Search Catalog (Instant)", variant="primary") | |
| gr.Examples( | |
| examples=[ | |
| "A minimalist industrial bedroom with concrete walls", | |
| "Luxury modern bathroom with marble and warm lights", | |
| "Bohemian living room with lots of plants and wood" | |
| ], | |
| inputs=fast_text_input | |
| ) | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| with gr.Column(): | |
| ft_rec1 = gr.Image(label="Top Match", elem_classes="custom-card") | |
| ft_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| ft_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card") | |
| ft_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| ft_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card") | |
| ft_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| fast_txt_submit_btn.click( | |
| fn=search_by_text_only, inputs=[fast_text_input], | |
| outputs=[ft_rec1, ft_score1, ft_rec2, ft_score2, ft_rec3, ft_score3] | |
| ) | |
| # --- TAB 3: Advanced GenAI Search --- | |
| with gr.TabItem("โจ AI Design Studio"): | |
| gr.Markdown("Describe your ideal space. Our Generative AI will draft a concept from scratch, and then find the closest real-world equivalents.") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| text_input = gr.Textbox(label="Concept Description", placeholder="e.g., A cozy modern living room...", lines=3) | |
| txt_submit_btn = gr.Button("Generate Concept & Match", variant="primary") | |
| gen_output = gr.Image(label="AI Drafted Concept", type="pil", elem_classes="custom-card") | |
| with gr.Column(scale=2): | |
| with gr.Row(): | |
| with gr.Column(): | |
| txt_rec1 = gr.Image(label="Top Match", elem_classes="custom-card") | |
| txt_score1 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| txt_rec2 = gr.Image(label="2nd Match", elem_classes="custom-card") | |
| txt_score2 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| with gr.Column(): | |
| txt_rec3 = gr.Image(label="3rd Match", elem_classes="custom-card") | |
| txt_score3 = gr.Textbox(label="Confidence", interactive=False, elem_classes="custom-score") | |
| txt_submit_btn.click( | |
| fn=generate_and_recommend, inputs=[text_input], | |
| outputs=[gen_output, txt_rec1, txt_score1, txt_rec2, txt_score2, txt_rec3, txt_score3] | |
| ) | |
| # --- TAB 4: Presentation Video --- | |
| with gr.TabItem("๐ฅ Presentation Video"): | |
| gr.Markdown("### ๐ Project Presentation & Walkthrough \nWatch the video below to see a full walkthrough of the dataset, EDA, model pipeline, and the live application.") | |
| gr.Video(value="https://huggingface.co/spaces/matanzig/Interior-Design-GenAI/resolve/main/A3.presentation.mp4", interactive=False) | |
| demo.launch() |