Eugene Mazarakis
17 November 2024

Creating a Standalone Tkinter App with python for Image Generation with DALL·E 2 model

by Eugene Mazarakis

Introduction

In today’s world, generative AI models like DALL·E 2 have become indispensable for creating high-quality, custom images from text prompts. Leveraging OpenAI’s API, you can seamlessly integrate this powerful model into your Python projects to generate images based on your ideas.

This article showcases a Python script that utilizes the OpenAI API to interact with the DALL·E 2 model. Moreover, the script includes a simple yet functional graphical user interface (GUI) built using Tkinter. This GUI allows you to input various parameters for the API call, making the process more intuitive and user-friendly.

Key Features of the Script:

  1. Prompt Input: Specify the text prompt to guide the image generation.
  2. Image Size Selection: Choose from three supported sizes: 1024x1024, 512x512, or 256x256.
  3. Number of Images: Generate between 1 and 10 images in a single API call.
  4. Save Directory: Select the directory where the generated images will be saved.

With this setup, you can easily create a standalone application for generating and saving images, bypassing the need to work directly in the command line. This approach is perfect for those seeking a user-friendly solution to experiment with generative AI capabilities.

NOTE Two modifications are required in the Python script for proper execution:

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "paste_the_API_key_that_you_obtained_from_the_OpenAI_website"))
default_image_dir = "specify_the_directory_path_where_the_generated_images_will_be_stored"

Graphical User Interface (GUI) of Python Application

You need to provide input to the program through the GUI as follows:

  1. Prompt: Enter the text description that will be used to generate a relevant image.
  2. Image Size: Choose from three supported sizes: 1024x1024, 512x512, or 256x256.
  3. Number of Images: Select the number of images to generate, ranging from 1 to 10, in a single API call.
  4. Choose Save Directory: Select the directory where you would like to save the generated images.
  5. Generate Images: Click the button to begin generating the images

Photo 0

You can see a video tutorial here

Video

Make Python script executable

After you create your python script you can make it executable following the step-by-step guide. First, you need to install PyInstaller.

pip install pyinstaller

Then you have to run the following command in the cmd:

pyinstaller --noconsole --onefile  path_to_your_script_name.py
  1. noconsole: Suppresses the command prompt window.
  2. onefile: Packages everything into a single executable file.

The Python code provided below is as follows

import tkinter as tk
from tkinter import filedialog, messagebox
from openai import OpenAI, OpenAIError  # OpenAI Python library to make API calls
import requests                         # used to download images
import os                               # used to access filepaths
import datetime                         # used to name the filename of the image
from PIL import Image                   # used to print and edit images

# Initialize OpenAI client
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "paste_the_API_key_that_you_obtained_from_the_OpenAI_website"))

# Set a default directory to save DALL·E images
default_image_dir = "specify_the_directory_path_where_the_generated_images_will_be_stored"
os.makedirs(default_image_dir, exist_ok=True) #Ensures the directory exists; if not, it is created

# Type of saved image
suffix = '.png'
MODEL = "dall-e-2"  # Supported sizes for 256x256, 512x512, or 1024x1024

# Custom exception class for OpenAI image errors
class OpenAIImageError(Exception):
    pass


# Function to generate image using OpenAI API
def generate_image(prompt, num_images, size, format, m):
    
    # Parameters Explanation
    # prompt: Text description for the image.
    # num_images: Number of images to generate.
    # size: Size of the image (1024x1024, 512x512, or 256x256).
    # format: Response format (set to "url" for the API to return image URLs).
    # m: Model name (dall-e-2).
    
    try:
        generation_response = client.images.generate(
            model=m,
            prompt=prompt,
            n=num_images,
            size=size,
            response_format=format,
        )
        return generation_response  # Returns the response from the OpenAI API, which includes image URLs.
    except OpenAIError as e:
        raise OpenAIImageError("OpenAI API Error: " + str(e))
    except Exception as e:
        raise OpenAIImageError("An unexpected error occurred: " + str(e))


# Function to save image data to files
def save_image(res, size, prefix, suffix):
    
    # Parameters Explanation
    # res: Response object from the API containing image URLs.
    # size: Size of the image.
    # prefix: Directory path to save images.
    # suffix: File format extension (e.g., .png).

    timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    
    for i, image in enumerate(res.data):
        generated_image_name = f'image_{size}_{timestamp}_{i}{suffix}'  # Generate Unique Filename: Combines size, timestamp, and an index to name each image.
        generated_image_filepath = os.path.join(prefix, generated_image_name)
        generated_image_url = image.url
        generated_image = requests.get(generated_image_url).content     # Download Images: Fetches image data using the requests library.
        
        with open(generated_image_filepath, "wb") as image_file:
            image_file.write(generated_image)                           # Save Images: Writes the image content to a file on disk.
        print('Saved:', generated_image_filepath)

# GUI Application
class ImageGeneratorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("DALL-E Image Generator")
        self.root.geometry("500x400")
        
        # Variables
        self.prompt_var = tk.StringVar()                # Stores the user’s image description.
        self.size_var = tk.StringVar(value="1024x1024") # Tracks the selected image size.
        self.num_images_var = tk.IntVar(value=1)        # Tracks the number of images to generate.
        self.save_dir = default_image_dir               # Holds the directory where images will be saved.
        
        # Layout: Adds a label and a text box for the user to input their prompt.
        tk.Label(root, text="Prompt:", font=("Arial", 12)).pack(pady=10)
        self.prompt_entry = tk.Entry(root, textvariable=self.prompt_var, width=50)
        self.prompt_entry.pack(pady=5)
        
        # Image Size Dropdown: Adds a dropdown menu for the user to select image size.
        tk.Label(root, text="Image Size:", font=("Arial", 12)).pack(pady=10)
        tk.OptionMenu(root, self.size_var, "1024x1024", "512x512", "256x256").pack(pady=5)
        
        # Number of Images: Adds a spinbox to select the number of images (between 1 and 10).
        tk.Label(root, text="Number of Images:", font=("Arial", 12)).pack(pady=10)
        tk.Spinbox(root, from_=1, to=10, textvariable=self.num_images_var, width=10).pack(pady=5)
        
        #Save Directory Button: Adds a button to open a file dialog for selecting the directory to save images.
        tk.Button(root, text="Choose Save Directory", command=self.choose_save_directory).pack(pady=10)
        
        # Generate Images Button: Adds a button to trigger image generation.
        tk.Button(root, text="Generate Images", command=self.generate_images).pack(pady=10)
    
    # Choose Save Directory: Opens a dialog for the user to select a directory.
    def choose_save_directory(self):
        directory = filedialog.askdirectory(initialdir=default_image_dir, title="Select Save Directory")
        if directory:
            self.save_dir = directory
    
    #Generate Images: Fetches user input from the GUI (prompt, size, num_images).
    def generate_images(self):
        prompt = self.prompt_var.get()
        size = self.size_var.get()
        num_images = self.num_images_var.get()
        
        # Validates the prompt.
        if not prompt:
            messagebox.showerror("Error", "Prompt cannot be empty!")
            return
        
        try:
            response = generate_image(prompt, num_images, size, "url", MODEL)   #Calls generate_image to create images and save_image to save them.
            save_image(response, size, self.save_dir, suffix)
            messagebox.showinfo("Success", f"Images saved to {self.save_dir}")  # Displays success or error messages using messagebox.
        except OpenAIImageError as e:
            messagebox.showerror("Error", str(e))

# Main Function
def main():
    root = tk.Tk()                  # Initializes the Tkinter root window.
    app = ImageGeneratorApp(root)   # Instantiates the ImageGeneratorApp to populate the window with GUI components.
    root.mainloop()                 # Starts the Tkinter event loop to keep the window responsive. 
    
# Entry point of the script
if __name__ == "__main__":
    main()
tags: Python - OpenAI Api - DALL-E 2