Download app.py from Revrse/SaltedAI: direct link, hf CLI and curl.
- Browser
- Download file 8.45 kB
-
https://huggingface.co/spaces/Revrse/SaltedAI/resolve/main/app.py
- Command line
-
hf download hf://spaces/Revrse/SaltedAI/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Revrse/SaltedAI/resolve/main/app.py
8.45 kB
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image, ImageDraw | |
| import requests | |
| import io | |
| import os | |
| import spaces | |
| import json | |
| import re | |
| import torch | |
| from diffusers import FluxKontextPipeline | |
| # Initialize FLUX model for advanced inpainting | |
| def load_flux_model(): | |
| """Load FLUX.1 Kontext model for high-quality object removal""" | |
| try: | |
| pipe = FluxKontextPipeline.from_pretrained( | |
| "black-forest-labs/FLUX.1-Kontext-dev", | |
| torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| return pipe | |
| except Exception as e: | |
| print(f"Failed to load FLUX model: {e}") | |
| return None | |
| # Global variable to store the model (loaded once) | |
| flux_pipe = None | |
| # Initialize object detection using proven working models | |
| def fuzzy_match_object(user_input, detected_labels): | |
| """ | |
| Advanced matching function that handles synonyms, plurals, and fuzzy matching | |
| """ | |
| user_input = user_input.lower().strip() | |
| matches = [] | |
| # Direct matching | |
| for detection in detected_labels: | |
| label = detection.get('label', '').lower() | |
| # Exact match | |
| if label == user_input: | |
| matches.append(detection) | |
| continue | |
| # Handle plurals | |
| if user_input.endswith('s') and label == user_input[:-1]: | |
| matches.append(detection) | |
| continue | |
| if label.endswith('s') and user_input == label[:-1]: | |
| matches.append(detection) | |
| continue | |
| # Substring matching | |
| if user_input in label or label in user_input: | |
| matches.append(detection) | |
| continue | |
| # Handle common synonyms | |
| synonyms = { | |
| 'person': ['human', 'people', 'man', 'woman', 'individual'], | |
| 'car': ['vehicle', 'automobile', 'auto'], | |
| 'bike': ['bicycle', 'cycle'], | |
| 'phone': ['mobile', 'cellphone', 'smartphone'], | |
| 'tv': ['television', 'telly'], | |
| 'couch': ['sofa', 'settee'], | |
| 'bag': ['purse', 'handbag', 'backpack'], | |
| 'glasses': ['spectacles', 'eyeglasses'], | |
| 'plane': ['airplane', 'aircraft'], | |
| 'boat': ['ship', 'vessel'], | |
| 'dog': ['puppy', 'canine'], | |
| 'cat': ['kitten', 'feline'] | |
| } | |
| # Check if user input matches any synonym | |
| for main_word, synonym_list in synonyms.items(): | |
| if (user_input == main_word and label in synonym_list) or \ | |
| (user_input in synonym_list and label == main_word): | |
| matches.append(detection) | |
| break | |
| return matches | |
| def flux_inpainting(image, object_name, guidance_scale=2.5, steps=28): | |
| """ | |
| Use FLUX.1 Kontext for intelligent object removal | |
| """ | |
| global flux_pipe | |
| try: | |
| # Load FLUX model if not already loaded | |
| if flux_pipe is None: | |
| print("Loading FLUX.1 Kontext model...") | |
| flux_pipe = load_flux_model() | |
| if flux_pipe is None: | |
| raise Exception("Failed to load FLUX model") | |
| # Create intelligent removal prompt | |
| removal_prompt = f"Remove the {object_name} from this image, fill with background that matches the surrounding environment, photorealistic, seamless, high quality" | |
| # Use FLUX for contextual editing | |
| result = flux_pipe( | |
| image=image.convert("RGB"), | |
| prompt=removal_prompt, | |
| guidance_scale=guidance_scale, | |
| width=image.size[0], | |
| height=image.size[1], | |
| num_inference_steps=steps, | |
| generator=torch.Generator().manual_seed(42), | |
| ).images[0] | |
| return result, True | |
| except Exception as e: | |
| print(f"FLUX inpainting error: {str(e)}") | |
| return None, False | |
| def remove_objects(image, object_name, guidance_scale, steps): | |
| """ | |
| Main function to remove any specified object using advanced detection + FLUX inpainting | |
| """ | |
| try: | |
| if image is None: | |
| raise gr.Error("Please upload an image") | |
| if not object_name or not object_name.strip(): | |
| raise gr.Error("Please enter the name of the object you want to remove") | |
| # Try to get token from multiple sources | |
| token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_HUB_TOKEN") | |
| if not token: | |
| raise gr.Error("Please provide your Hugging Face token or set HF_TOKEN in Space secrets") | |
| # Step 3: Use FLUX.1 Kontext for intelligent object removal | |
| print("Using FLUX.1 Kontext for advanced object removal...") | |
| result_image, flux_success = flux_inpainting(image, object_name, guidance_scale, steps) | |
| if flux_success and result_image: | |
| status_msg = f"✅ Successfully removed '{object_name}' object(s)\n" | |
| status_msg += f"⚙️ Settings: Guidance={guidance_scale}, Steps={steps}" | |
| return result_image, status_msg | |
| else: | |
| # Fallback: show detection areas | |
| status_msg = f"⚠️ Inpainting failed, but detection was successful\n" | |
| status_msg += f"💡 Try adjusting guidance scale or steps, or check GPU availability" | |
| return result_image, status_msg | |
| except Exception as e: | |
| return image, None, f"❌ Error: {str(e)}" | |
| # Create Gradio interface | |
| with gr.Blocks( | |
| fill_height=True, | |
| title="Professional Object Removal", | |
| theme=gr.themes.Soft() | |
| ) as demo: | |
| gr.Markdown(""" | |
| # 🚀 Professional Object Removal using Advanced AI | |
| Upload an image and specify **ANY object** you want to remove with professional results! | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| # Input section | |
| gr.Markdown("## 📤 Input") | |
| input_image = gr.Image( | |
| label="Upload Image", | |
| type="pil", | |
| height=300 | |
| ) | |
| object_name = gr.Textbox( | |
| label="🎯 Object to Remove", | |
| placeholder="Enter any object name (e.g., person, car, dog, bottle, tree, sign...)", | |
| value="person", | |
| info="Type ANY object name - supports synonyms and variations!" | |
| ) | |
| # Add suggestions | |
| with gr.Row(): | |
| gr.Examples( | |
| examples=[ | |
| ["person"], ["car"], ["dog"], ["cat"], ["bottle"], | |
| ["chair"], ["tree"], ["sign"], ["bag"], ["phone"] | |
| ], | |
| inputs=[object_name], | |
| label="💡 Quick Examples" | |
| ) | |
| with gr.Accordion("⚙️ Advanced Settings", open=False): | |
| guidance_scale = gr.Slider( | |
| minimum=1.0, | |
| maximum=10.0, | |
| value=2.5, | |
| step=0.1, | |
| label="🎯 Guidance Scale", | |
| info="Higher = more faithful to prompt, lower = more creative" | |
| ) | |
| steps = gr.Slider( | |
| minimum=10, | |
| maximum=50, | |
| value=28, | |
| step=2, | |
| label="🔄 Steps", | |
| info="More steps = higher quality but slower processing" | |
| ) | |
| remove_btn = gr.Button("🚀 Remove Objects", variant="primary", size="lg") | |
| with gr.Column(scale=2): | |
| # Output section | |
| gr.Markdown("## 📋 Results") | |
| with gr.Row(): | |
| output_image = gr.Image( | |
| label="🖼️ Result", | |
| type="pil", | |
| height=300 | |
| ) | |
| status_text = gr.Textbox( | |
| label="📊 Status & Detection Info", | |
| interactive=False, | |
| max_lines=5 | |
| ) | |
| # Event handlers | |
| remove_btn.click( | |
| fn=remove_objects, | |
| inputs=[ | |
| input_image, | |
| object_name, | |
| guidance_scale, | |
| steps, | |
| ], | |
| outputs=[output_image, status_text] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |