Inference Providers documentation

Building an AI Image Editor with Gradio and Inference Providers

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Building an AI Image Editor with Gradio and Inference Providers

In this guide, we’ll build an AI-powered image editor that lets users upload images and edit them using natural language prompts. This project demonstrates how to combine Inference Providers with image-to-image models like Qwen’s Image Edit and Black Forest Labs’ Flux Kontext.

Our app will:

  1. Accept image uploads through a web interface
  2. Process natural language prompts editing instructions like “Turn the cat into a tiger”
  3. Transform images using Qwen Image Edit or FLUX.1 Kontext
  4. Display results in a Gradio interface

TL;DR - this guide will show you how to build an AI image editor with Gradio and Inference Providers, just like this one.

Step 1: Set Up Authentication

Before we start coding, authenticate with Hugging Face using your token:

# Get your token from https://huggingface.co/settings/tokens
export HF_TOKEN="your_token_here"

This guide assumes you have a Hugging Face account. If you don’t have one, you can create one for free at huggingface.co.

When you set this environment variable, it handles authentication automatically for all your inference calls. You can generate a token from your settings page.

Step 2: Project Setup

Create a new project directory and initialize it with uv:

mkdir image-editor-app
cd image-editor-app
uv init

This creates a basic project structure with a pyproject.toml file. Now add the required dependencies:

uv add huggingface-hub>=0.34.4 gradio>=5.0.0 pillow>=11.3.0

The dependencies are now installed and ready to use! Also, uv will maintain the pyproject.toml file for you as you add dependencies.

We’re using uv because it’s a fast Python package manager that handles dependency resolution and virtual environment management automatically. It’s much faster than pip and provides better dependency resolution. If you’re not familiar with uv, check it out here.

Step 3: Build the Core Image Editing Function

Now let’s create the main logic for our application - the image editing function that transforms images using AI.

Create main.py then import the necessary libraries and instantiate the InferenceClient. We’re using the fal-ai provider for fast image processing, but other providers like replicate are also available.

import os
import gradio as gr
from huggingface_hub import InferenceClient
import io

# Initialize the client with fal-ai provider for fast image processing
client = InferenceClient(
    provider="fal-ai",
    api_key=os.environ["HF_TOKEN"],
)

Now let’s create the image editing function. This function takes an input image and a prompt, and returns an edited image. We also want to handle errors gracefully and return the original image if there’s an error, so our UI always shows something.

def edit_image(input_image, prompt):
    """
    Edit an image using the given prompt.
    
    Args:
        input_image: PIL Image object from Gradio
        prompt: String prompt for image editing
    
    Returns:
        PIL Image object (edited image)
    """
    if input_image is None:
        return None
    
    if not prompt or prompt.strip() == "":
        return input_image
    
    try:
        # Convert PIL Image to bytes
        img_bytes = io.BytesIO()
        input_image.save(img_bytes, format="PNG")
        img_bytes = img_bytes.getvalue()
        
        # Use the image_to_image method with Qwen's image editing model
        edited_image = client.image_to_image(
            img_bytes,
            prompt=prompt.strip(),
            model="Qwen/Qwen-Image-Edit",
        )
        
        return edited_image
    
    except Exception as e:
        print(f"Error editing image: {e}")
        return input_image

We’re using the fal-ai provider with the Qwen/Qwen-Image-Edit model. The fal-ai provider offers fast inference times, perfect for interactive applications.

However, you can experiment with different providers for various performance characteristics:

client = InferenceClient(provider="replicate", api_key=os.environ["HF_TOKEN"])
client = InferenceClient(provider="auto", api_key=os.environ["HF_TOKEN"])  # Automatic selection

Step 4: Create the Gradio Interface

Now let’s build a simple user-friendly interface using Gradio.

# Create the Gradio interface
with gr.Blocks(title="Image Editor", theme=gr.themes.Soft()) as interface:
    gr.Markdown(
        """
        # 🎨 AI Image Editor
        Upload an image and describe how you want to edit it using natural language!
        """
    )

    with gr.Row():
        with gr.Column():
            input_image = gr.Image(label="Upload Image", type="pil", height=400)
            prompt = gr.Textbox(
                label="Edit Prompt",
                placeholder="Describe how you want to edit the image...",
                lines=2,
            )
            edit_btn = gr.Button("✨ Edit Image", variant="primary", size="lg")

        with gr.Column():
            output_image = gr.Image(label="Edited Image", type="pil", height=400)

    # Example images and prompts
    with gr.Row():
        gr.Examples(
            examples=[
                ["cat.png", "Turn the cat into a tiger"],
                ["cat.png", "Make it look like a watercolor painting"],
                ["cat.png", "Change the background to a forest"],
            ],
            inputs=[input_image, prompt],
            outputs=output_image,
            fn=edit_image,
            cache_examples=False,
        )

    # Event handlers
    edit_btn.click(fn=edit_image, inputs=[input_image, prompt], outputs=output_image)

    # Allow Enter key to trigger editing
    prompt.submit(fn=edit_image, inputs=[input_image, prompt], outputs=output_image)

In this app we’ll use some practical Gradio features to make a user-friendly app

  • We’ll use blocks to create a two column layout with the image upload and the edited image.
  • We’ll drop some markdown into to explain what the app does.
  • And, we’ll use gr.Examples to show some example inputs to give the user some inspiration.

Finally, add the launch configuration at the end of main.py:

if __name__ == "__main__":
    interface.launch(
        share=True,  # Creates a public link
        server_name="0.0.0.0",  # Allow external access
        server_port=7860,  # Default Gradio port
        show_error=True,  # Show errors in the interface
    )

Now run your application:

python main.py

Your app will launch locally at http://localhost:7860 and Gradio will also provide a public shareable link!

Complete Working Code

📋 Click to view the complete main.py file
import os
import gradio as gr
from huggingface_hub import InferenceClient
from PIL import Image
import io

# Initialize the client
client = InferenceClient(
    provider="fal-ai",
    api_key=os.environ["HF_TOKEN"],
)

def edit_image(input_image, prompt):
    """
    Edit an image using the given prompt.
    
    Args:
        input_image: PIL Image object from Gradio
        prompt: String prompt for image editing
    
    Returns:
        PIL Image object (edited image)
    """
    if input_image is None:
        return None
    
    if not prompt or prompt.strip() == "":
        return input_image
    
    try:
        # Convert PIL Image to bytes
        img_bytes = io.BytesIO()
        input_image.save(img_bytes, format="PNG")
        img_bytes = img_bytes.getvalue()
        
        # Use the image_to_image method
        edited_image = client.image_to_image(
            img_bytes,
            prompt=prompt.strip(),
            model="Qwen/Qwen-Image-Edit",
        )
        
        return edited_image
    
    except Exception as e:
        print(f"Error editing image: {e}")
        return input_image

# Create Gradio interface
with gr.Blocks(title="Image Editor", theme=gr.themes.Soft()) as interface:
    gr.Markdown(
        """
        # 🎨 AI Image Editor
        Upload an image and describe how you want to edit it using natural language!
        """
    )

    with gr.Row():
        with gr.Column():
            input_image = gr.Image(label="Upload Image", type="pil", height=400)
            prompt = gr.Textbox(
                label="Edit Prompt",
                placeholder="Describe how you want to edit the image...",
                lines=2,
            )
            edit_btn = gr.Button("✨ Edit Image", variant="primary", size="lg")

        with gr.Column():
            output_image = gr.Image(label="Edited Image", type="pil", height=400)

    # Example images and prompts
    with gr.Row():
        gr.Examples(
            examples=[
                ["cat.png", "Turn the cat into a tiger"],
                ["cat.png", "Make it look like a watercolor painting"],
                ["cat.png", "Change the background to a forest"],
            ],
            inputs=[input_image, prompt],
            outputs=output_image,
            fn=edit_image,
            cache_examples=False,
        )

    # Event handlers
    edit_btn.click(fn=edit_image, inputs=[input_image, prompt], outputs=output_image)

    # Allow Enter key to trigger editing
    prompt.submit(fn=edit_image, inputs=[input_image, prompt], outputs=output_image)

if __name__ == "__main__":
    interface.launch(
        share=True,  # Creates a public link
        server_name="0.0.0.0",  # Allow external access
        server_port=7860,  # Default Gradio port
        show_error=True,  # Show errors in the interface
    )

Deploy on Hugging Face Spaces

Let’s deploy our app to Hugging Face Spaces.

First, we will export our dependencies to a requirements file.

uv export --format requirements-txt --output-file requirements.txt

This creates a requirements.txt file with all your project dependencies and their exact versions from the lockfile.

The uv export command ensures that your Space will use the exact same dependency versions that you tested locally, preventing deployment issues caused by version mismatches.

Now you can deploy to Spaces:

  1. Create a new Space: Go to huggingface.co/new-space
  2. Choose Gradio SDK and make it public
  3. Upload your files: Upload main.py, requirements.txt, and any example images
  4. Add your token: In Space settings, add HF_TOKEN as a secret
  5. Launch: Your app will be live at https://huggingface.co/spaces/your-username/your-space-name

Next Steps

Congratulations! You’ve created a production-ready AI image editor. Now that you have a working image editor, here are some ideas to extend it:

  • Batch processing: Edit multiple images at once
  • Object removal: Remove unwanted objects from images
  • Provider comparison: Benchmark different providers for your use case

Happy building! And remember to share your app with the community on the Hub.

< > Update on GitHub