# app.py import gradio as gr import torch from diffusers import AutoPipelineForInpainting from PIL import Image import time # --- Model Loading (CPU Version) --- print("Loading model on CPU... This may take several minutes.") pipe = AutoPipelineForInpainting.from_pretrained( "runwayml/stable-diffusion-inpainting" # Using the slightly smaller 1.5 model for better CPU performance ) print("Model loaded successfully.") # --- Default "Magic" Prompts --- # These will be used if the user doesn't provide their own prompt. DEFAULT_PROMPT = "photorealistic, 4k, ultra high quality, sharp focus, masterpiece, high detail, professional photo" DEFAULT_NEGATIVE_PROMPT = "blurry, pixelated, distorted, deformed, ugly, disfigured, cartoon, anime, low quality, watermark, text" # --- The Inpainting Function --- # It now handles the logic for an optional user prompt. def inpaint_image(input_dict, user_prompt, guidance_scale, num_steps, progress=gr.Progress()): """ Performs inpainting. Uses a default prompt if the user_prompt is empty. """ image = input_dict["image"].convert("RGB") mask_image = input_dict["mask"].convert("RGB") # --- This is the core logic for the hybrid approach --- if user_prompt and user_prompt.strip(): # If the user provided a prompt, use it. prompt = user_prompt # For custom prompts, a general negative prompt is still useful. negative_prompt = DEFAULT_NEGATIVE_PROMPT print(f"Using custom prompt: '{prompt}'") else: # If the user left the prompt box empty, use our high-quality defaults. prompt = DEFAULT_PROMPT negative_prompt = DEFAULT_NEGATIVE_PROMPT print(f"User prompt is empty. Using default 'General Fix' prompt.") print(f"Starting inpainting on CPU...") start_time = time.time() # Callback to update the progress bar in the UI def progress_callback(step, timestep, latents): progress(step / int(num_steps), desc=f"Running step {step}/{int(num_steps)}") # Run the pipeline result_image = pipe( prompt=prompt, image=image, mask_image=mask_image, negative_prompt=negative_prompt, guidance_scale=guidance_scale, num_inference_steps=int(num_steps), callback_steps=1, callback=progress_callback, ).images[0] end_time = time.time() print(f"Inpainting finished in {end_time - start_time:.2f} seconds.") return result_image # --- Gradio User Interface --- with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown( """ # 🎨 AI Image Fixer **How to use:** 1. Upload an image. 2. Use the brush to **paint over the area you want to fix**. 3. **(Optional)** For precise control, write a custom prompt describing the fix. 4. **(Easy Mode)** Or, just leave the prompt box empty for a general quality improvement. 5. Click "Fix It!" """ ) gr.Warning( "⚠️ This Space is running on a free CPU. " "Image generation will be VERY SLOW (expect 5-15 minutes). " "A progress bar will show the status below the button. Please be patient!" ) with gr.Row(): # Input Column with gr.Column(scale=2): input_image = gr.Image( label="1. Upload & Mask Image", source="upload", tool="brush", type="pil" ) # The prompt textbox is back, but now it's optional! prompt_textbox = gr.Textbox( label="2. Describe Your Fix (Optional)", placeholder="Leave empty for a general fix, or type e.g., 'a perfect human hand'" ) with gr.Accordion("Advanced Settings", open=False): guidance_scale = gr.Slider(minimum=0, maximum=20, value=8.0, label="Guidance Scale") num_steps = gr.Slider(minimum=10, maximum=50, step=1, value=25, label="Inference Steps") # Output Column with gr.Column(scale=1): output_image = gr.Image(label="Result", type="pil") submit_button = gr.Button("Fix It!", variant="primary") submit_button.click( fn=inpaint_image, inputs=[input_image, prompt_textbox, guidance_scale, num_steps], outputs=output_image ) if __name__ == "__main__": demo.launch()