Code icon

The App is Under a Quick Maintenance

We apologize for the inconvenience. Please come back later

Menu iconMenu iconOpenAI API Bible Volume 2
OpenAI API Bible Volume 2

Chapter 5: Image and Audio Integration Projects

5.2 Interactive Image Generation with Flask

Let's take our previous project to the next level by incorporating advanced interactive elements and dynamic features. This enhancement will transform the basic image generation tool into a sophisticated application that provides users with granular control over every aspect of the creation process. Here's what we'll add:

First, we'll implement real-time validation and feedback systems that guide users through crafting effective prompts. Next, we'll introduce dynamic parameter controls that allow users to fine-tune their image generation settings on the fly. Finally, we'll create an intuitive interface that makes these powerful features accessible to users of all skill levels.

5.2.1 What You’ll Build

This expanded version focuses on three key aspects: user control, immediate feedback, and reliability. Users will have precise control over the generation parameters while receiving instant visual feedback on their choices. All of this is built on a robust foundation that ensures consistent performance and error handling, creating a more engaging and flexible user experience.

You will expand the Flask web application to include these powerful advanced features, each designed to enhance user experience and functionality:

  • A meticulously designed web interface with an intuitive form for submitting prompts, featuring:
    • Real-time input validation that checks prompt length and content
    • Smart suggestion system that recommends improvements to prompt effectiveness
    • Interactive tooltips and examples to guide users in crafting better descriptions
  • Comprehensive dropdown menus offering full control over generation parameters:
    • DALL-E model selection (DALL-E 2 or 3) for different quality levels and capabilities - DALL-E 3 offers higher quality and better prompt understanding, while DALL-E 2 provides faster generation
    • Multiple image size options (1024x1024, 1024x1792, 1792x1024) for various use cases - portrait, landscape, or square formats to suit different creative needs
    • Response format selection (URL or Base64) for different integration needs - URLs for quick viewing, Base64 for direct embedding and offline storage
  • Dynamic image display functionality that shows generated images in real-time on the webpage, including:
    • Interactive preview window with zoom capabilities
    • One-click download options in multiple formats
    • Image history tracking for comparing iterations
  • Robust error handling system that:
    • Provides clear, user-friendly error messages with specific troubleshooting steps
    • Implements automatic retry mechanisms for transient failures, with configurable retry attempts and intervals
    • Ensures graceful degradation during API issues or rate limiting through fallback options and queue management

Technologies Used:

  • Flask: A Python web framework.
  • OpenAI API: To access DALL-E for image generation.
  • HTML: To structure the web page.
  • CSS: To style the web page.

Structure:

The project will have the following file structure:

  • app.py: The Python file containing the Flask application code.
  • templates/index.html: The HTML template.
  • .env: A file to store the OpenAI API key.

5.2.2 Step 1: Install Required Packages

Ensure you have the necessary Python libraries installed.

pip install flask openai python-dotenv

5.2.3 Step 2: Set up Environment Variables

Create a .env file in your project directory and add your OpenAI API key:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Step 3: Create the Flask Application (app.py)

Create a Python file named app.py with the following code:

from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def generate_image(prompt: str, model: str = "dall-e-3", size: str = "1024x1024", response_format: str = "url") -> Optional[str]:
    """
    Generates an image using OpenAI's DALL·E API.

    Args:
        prompt (str): The text prompt to generate the image from.
        model (str, optional): The DALL·E model to use. Defaults to "dall-e-3".
        size (str, optional): The size of the generated image. Defaults to "1024x1024".
        response_format (str, optional): The format of the response. Defaults to "url".

    Returns:
        Optional[str]: The URL of the generated image, or None on error.
    """
    try:
        logger.info(f"Generating image with prompt: {prompt}, model: {model}, size: {size}, format: {response_format}")
        response = openai.Image.create(
            prompt=prompt,
            model=model,
            size=size,
            response_format=response_format,
        )
        image_url = response.data[0].url
        logger.info(f"Image URL: {image_url}")
        return image_url
    except openai.error.OpenAIError as e:
        logger.error(f"OpenAI API Error: {e}")
        return None
    except Exception as e:
        logger.error(f"Error generating image: {e}")
        return None

@app.route("/", methods=["GET", "POST"])
def index():
    """
    Handles the main route for the web application.
    Generates an image based on user input and displays it.
    """
    image_url = None
    error_message = None

    if request.method == "POST":
        prompt = request.form.get("prompt")
        if not prompt:
            error_message = "Please provide a prompt to generate an image."
            logger.warning(error_message)
            return render_template("index.html", error=error_message)

        model = request.form.get("model", "dall-e-3")  # Get model from form
        size = request.form.get("size", "1024x1024")    # Get size from form
        response_format = request.form.get("format", "url")

        image_url = generate_image(prompt, model, size, response_format)

        if not image_url:
            error_message = "Failed to generate image. Please try again."  # generic error
            return render_template("index.html", error=error_message)

    return render_template("index.html", image_url=image_url, error=error_message)

@app.errorhandler(500)
def internal_server_error(e):
    """Handles internal server errors."""
    logger.error(f"Internal Server Error: {e}")
    return render_template("error.html", error="Internal Server Error"), 500


if __name__ == "__main__":
    app.run(debug=True)

Code Breakdown:

  • Import Statements:
    • from flask import Flask, request, render_template, jsonify, make_response: Imports the necessary components from the Flask framework.
    • import openai: Imports the OpenAI Python library, which allows you to interact with the OpenAI API.
    • import os: Imports the os module, which provides a way to interact with the operating system (e.g., to access environment variables).
    • from dotenv import load_dotenv: Imports the load_dotenv function from the python-dotenv library.
    • import logging: Imports the logging module for application logging.
    • from typing import Optional, Dict: Imports Optional and Dict from the typing module for type hinting.
  • Environment Variables:
    • load_dotenv(): Loads the variables from the .env file into the environment.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Retrieves the OpenAI API key from the environment variable OPENAI_API_KEY and sets it for the OpenAI library.
  • Flask Application:
    • app = Flask(__name__): Creates a Flask application instance. The __name__ argument helps Flask locate the application's resources.
  • Logging Configuration:
    • logging.basicConfig(level=logging.INFO): Configures the logging module to record events at the INFO level and higher. This means that informational messages, warnings, and errors will be logged.
    • logger = logging.getLogger(__name__): Creates a logger object specific to this module (app.py).
  • generate_image Function:
    • def generate_image(...): Defines a function that encapsulates the logic for generating an image using the OpenAI API.
    • Args:
      • prompt (str): The text description of the desired image.
      • model (str, optional): The DALL·E model to use (defaults to "dall-e-3").
      • size (str, optional): The dimensions of the generated image (defaults to "1024x1024").
      • response_format (str, optional): The format in which the image should be returned. It defaults to "url".
    • Returns:
      • Optional[str]: The URL of the generated image if the API call is successful, or None if an error occurs.
    • The function uses a try...except block to handle potential errors during the API call:
      • It logs an informational message using logger.info() before making the API call.
      • It calls the OpenAI API's openai.Image.create() method to generate the image.
      • If the API call is successful, it extracts the image URL from the response and returns it.
      • If an openai.error.OpenAIError occurs (e.g., invalid API key, API server error), it logs an error message using logger.error() and returns None.
      • If any other exception occurs, it also logs an error message and returns None.
  • index Route:
    • @app.route("/", methods=["GET", "POST"]): This decorator defines a route for the web application's main page ("/"). The index() function will handle both GET and POST requests to this URL.
    • def index():: This function handles requests to the root URL ("/").
    • image_url = None: Initializes a variable to store the image URL.
    • error_message = None: Initializes a variable to store any error message.
    • if request.method == "POST":: This block of code is executed when the user submits the form on the webpage (i.e., when the user clicks the "Generate Image" button).
      • prompt = request.form.get("prompt"): Gets the user's input from the form.
      • if not prompt:: Checks if the prompt is empty. If it is, sets an error message and returns the template.
      • model = request.form.get("model", "dall-e-3"): Gets the selected model, size, and format from the form, defaulting to "dall-e-3", "1024x1024", and "url" if not provided.
      • image_url = generate_image(prompt, model, size, response_format): Calls the generate_image() function to generate the image.
      • if not image_url:: Checks if generate_image() returned None (indicating an error). If so, sets an error message.
      • return render_template("index.html", image_url=image_url, error=error_message): Renders the index.html template, passing the image_url and error_message variables.
    • return render_template("index.html", image_url=image_url, error=error_message): This line is executed when the user first loads the page (i.e., when the browser sends a GET request to "/"). It renders the index.html template, initially with image_url and error_message set to None.
  • @app.errorhandler(500): This decorator registers a function to handle HTTP 500 errors (Internal Server Error).
    • def internal_server_error(e):: This function is called when a 500 error occurs.
      • logger.error(f"Internal Server Error: {e}"): Logs the error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renders an error page (error.html) with a generic error message and returns the HTTP status code 500.
  • if __name__ == "__main__":: This ensures that the Flask development server is started only when the script is executed directly (not when imported as a module).
    • app.run(debug=True): Starts the Flask development server in debug mode. Debug mode provides helpful error messages and automatic reloading when you make changes to the code.

5.2.5 Step 3: Create the HTML Template (templates/index.html)

Create a folder named templates in the same directory as app.py. Inside the templates folder, create a file named index.html with the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DALL·E 3 Image Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <style>
        /* --- General Styles --- */
        body {
            font-family: 'Inter', sans-serif;
            padding: 40px;
            background-color: #f9fafb; /* Tailwind's gray-50 */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            color: #374151; /* Tailwind's gray-700 */
        }
        .container {
            max-width: 800px; /* Increased max-width */
            width: 95%; /* Take up most of the viewport */
            background-color: #fff;
            padding: 2rem;
            border-radius: 0.75rem; /* Tailwind's rounded-lg */
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
            text-align: center;
        }
        h2 {
            font-size: 2.25rem; /* Tailwind's text-3xl */
            font-weight: 600;  /* Tailwind's font-semibold */
            margin-bottom: 1.5rem; /* Tailwind's mb-6 */
            color: #1e293b; /* Tailwind's gray-900 */
        }
        p{
            color: #6b7280; /* Tailwind's gray-500 */
            margin-bottom: 1rem;
        }

        /* --- Form Styles --- */
        form {
            margin-top: 1rem; /* Tailwind's mt-4 */
            margin-bottom: 1.5rem;
            display: flex;
            flex-direction: column;
            align-items: center; /* Center form elements */
            gap: 0.5rem; /* Tailwind's gap-2 */
        }
        textarea {
            width: 100%;
            max-width: 400px; /* Added max-width for text area */
            padding: 0.75rem; /* Tailwind's p-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
            resize: vertical;
            font-size: 1rem; /* Tailwind's text-base */
            line-height: 1.5rem; /* Tailwind's leading-relaxed */
            margin-bottom: 0.25rem; /* Tailwind's mb-1 */
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
        }
        textarea:focus {
            outline: none;
            border-color: #3b82f6; /* Tailwind's border-blue-500 */
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
        }
        input[type="submit"] {
            padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
            color: #fff;
            font-size: 1rem; /* Tailwind's text-base */
            font-weight: 600; /* Tailwind's font-semibold */
            cursor: pointer;
            transition: background-color 0.3s ease;
            border: none;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
        }
        input[type="submit"]:hover {
            background-color: #4338ca; /* Tailwind's bg-indigo-700 */
        }
        input[type="submit"]:focus {
            outline: none;
            box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
        }

        /* --- Image Styles --- */
        img {
            max-width: 100%;
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            margin-top: 1.5rem; /* Tailwind's mt-6 */
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* Tailwind's shadow-md */
        }

        /* --- Error Styles --- */
        .error-message {
            color: #dc2626; /* Tailwind's text-red-600 */
            margin-top: 1rem; /* Tailwind's mt-4 */
            padding: 0.75rem;
            background-color: #fee2e2;
            border-radius: 0.375rem;
            border: 1px solid #fecaca;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>🎨 Generate an Image with DALL·E</h2>
        <p> Enter a detailed prompt to generate an image. </p>
        <form method="post">
            <textarea name="prompt" rows="3" placeholder="Describe an image..."></textarea><br>
             <div style="display: flex; gap: 1rem; justify-content: center; margin-top: 0.5rem;">
                <select name="model">
                    <option value="dall-e-3">DALL·E 3</option>
                    <option value="dall-e-2">DALL·E 2</option>
                </select>
                <select name="size">
                    <option value="1024x1024">1024x1024</option>
                    <option value="1024x1792">1024x1792</option>
                    <option value="1792x1024">1792x1024</option>
                 </select>
                 <select name="format">
                    <option value="url">URL</option>
                    <option value="b64_json">Base64</option>
                </select>
            </div>
            <input type="submit" value="Generate Image">
        </form>

        {% if image_url %}
            <h3>🖼️ Result:</h3>
            <img src="{{ image_url }}" alt="Generated Image">
        {% elif error %}
            <div class="error-message">{{ error }}</div>
        {% endif %}
    </div>
</body>
</html>

The HTML template provides the structure and styling for the web page.  Key elements include:

  • HTML Structure:
    • The <head> section defines the title, links a CSS stylesheet, and sets the viewport for responsiveness.
    • The <body> contains the visible content of the page, including a container for the form and the image display area.
  • CSS Styling:
    • Modern Design: The CSS is updated to use a modern design, similar to Tailwind CSS.
    • Responsive Layout: The layout is more responsive.
    • User Experience: Improved form styling.
    • Configuration Options: The template now includes dropdowns to select the DALL·E model, image size, and response format.
    • Error Display: Displays error messages from the backend in a user-friendly way.
  • Form:
    • <form> element allows the user to input a prompt to generate an image. The <textarea> element provides a multi-line input field for the prompt, and the <input type="submit"> element is a button to submit the form. Additionally, dropdowns are added to select the model, size, and format.
  • Image Display:
    • An <img> element is used to display the generated image. The src attribute is dynamically set to the image_url passed from the Flask application.
  • Error Handling:
    • <div class="error-message"> is used to display any error messages generated by the application.

Try It Out

  1. Save the files as app.py and templates/index.html.
  2. Run the server:
    python app.py
  3. Open http://localhost:5000 in your browser.
  4. Type a prompt (e.g., "A cyberpunk city at sunset with glowing neon signs") and select the desired options.

5.2 Interactive Image Generation with Flask

Let's take our previous project to the next level by incorporating advanced interactive elements and dynamic features. This enhancement will transform the basic image generation tool into a sophisticated application that provides users with granular control over every aspect of the creation process. Here's what we'll add:

First, we'll implement real-time validation and feedback systems that guide users through crafting effective prompts. Next, we'll introduce dynamic parameter controls that allow users to fine-tune their image generation settings on the fly. Finally, we'll create an intuitive interface that makes these powerful features accessible to users of all skill levels.

5.2.1 What You’ll Build

This expanded version focuses on three key aspects: user control, immediate feedback, and reliability. Users will have precise control over the generation parameters while receiving instant visual feedback on their choices. All of this is built on a robust foundation that ensures consistent performance and error handling, creating a more engaging and flexible user experience.

You will expand the Flask web application to include these powerful advanced features, each designed to enhance user experience and functionality:

  • A meticulously designed web interface with an intuitive form for submitting prompts, featuring:
    • Real-time input validation that checks prompt length and content
    • Smart suggestion system that recommends improvements to prompt effectiveness
    • Interactive tooltips and examples to guide users in crafting better descriptions
  • Comprehensive dropdown menus offering full control over generation parameters:
    • DALL-E model selection (DALL-E 2 or 3) for different quality levels and capabilities - DALL-E 3 offers higher quality and better prompt understanding, while DALL-E 2 provides faster generation
    • Multiple image size options (1024x1024, 1024x1792, 1792x1024) for various use cases - portrait, landscape, or square formats to suit different creative needs
    • Response format selection (URL or Base64) for different integration needs - URLs for quick viewing, Base64 for direct embedding and offline storage
  • Dynamic image display functionality that shows generated images in real-time on the webpage, including:
    • Interactive preview window with zoom capabilities
    • One-click download options in multiple formats
    • Image history tracking for comparing iterations
  • Robust error handling system that:
    • Provides clear, user-friendly error messages with specific troubleshooting steps
    • Implements automatic retry mechanisms for transient failures, with configurable retry attempts and intervals
    • Ensures graceful degradation during API issues or rate limiting through fallback options and queue management

Technologies Used:

  • Flask: A Python web framework.
  • OpenAI API: To access DALL-E for image generation.
  • HTML: To structure the web page.
  • CSS: To style the web page.

Structure:

The project will have the following file structure:

  • app.py: The Python file containing the Flask application code.
  • templates/index.html: The HTML template.
  • .env: A file to store the OpenAI API key.

5.2.2 Step 1: Install Required Packages

Ensure you have the necessary Python libraries installed.

pip install flask openai python-dotenv

5.2.3 Step 2: Set up Environment Variables

Create a .env file in your project directory and add your OpenAI API key:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Step 3: Create the Flask Application (app.py)

Create a Python file named app.py with the following code:

from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def generate_image(prompt: str, model: str = "dall-e-3", size: str = "1024x1024", response_format: str = "url") -> Optional[str]:
    """
    Generates an image using OpenAI's DALL·E API.

    Args:
        prompt (str): The text prompt to generate the image from.
        model (str, optional): The DALL·E model to use. Defaults to "dall-e-3".
        size (str, optional): The size of the generated image. Defaults to "1024x1024".
        response_format (str, optional): The format of the response. Defaults to "url".

    Returns:
        Optional[str]: The URL of the generated image, or None on error.
    """
    try:
        logger.info(f"Generating image with prompt: {prompt}, model: {model}, size: {size}, format: {response_format}")
        response = openai.Image.create(
            prompt=prompt,
            model=model,
            size=size,
            response_format=response_format,
        )
        image_url = response.data[0].url
        logger.info(f"Image URL: {image_url}")
        return image_url
    except openai.error.OpenAIError as e:
        logger.error(f"OpenAI API Error: {e}")
        return None
    except Exception as e:
        logger.error(f"Error generating image: {e}")
        return None

@app.route("/", methods=["GET", "POST"])
def index():
    """
    Handles the main route for the web application.
    Generates an image based on user input and displays it.
    """
    image_url = None
    error_message = None

    if request.method == "POST":
        prompt = request.form.get("prompt")
        if not prompt:
            error_message = "Please provide a prompt to generate an image."
            logger.warning(error_message)
            return render_template("index.html", error=error_message)

        model = request.form.get("model", "dall-e-3")  # Get model from form
        size = request.form.get("size", "1024x1024")    # Get size from form
        response_format = request.form.get("format", "url")

        image_url = generate_image(prompt, model, size, response_format)

        if not image_url:
            error_message = "Failed to generate image. Please try again."  # generic error
            return render_template("index.html", error=error_message)

    return render_template("index.html", image_url=image_url, error=error_message)

@app.errorhandler(500)
def internal_server_error(e):
    """Handles internal server errors."""
    logger.error(f"Internal Server Error: {e}")
    return render_template("error.html", error="Internal Server Error"), 500


if __name__ == "__main__":
    app.run(debug=True)

Code Breakdown:

  • Import Statements:
    • from flask import Flask, request, render_template, jsonify, make_response: Imports the necessary components from the Flask framework.
    • import openai: Imports the OpenAI Python library, which allows you to interact with the OpenAI API.
    • import os: Imports the os module, which provides a way to interact with the operating system (e.g., to access environment variables).
    • from dotenv import load_dotenv: Imports the load_dotenv function from the python-dotenv library.
    • import logging: Imports the logging module for application logging.
    • from typing import Optional, Dict: Imports Optional and Dict from the typing module for type hinting.
  • Environment Variables:
    • load_dotenv(): Loads the variables from the .env file into the environment.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Retrieves the OpenAI API key from the environment variable OPENAI_API_KEY and sets it for the OpenAI library.
  • Flask Application:
    • app = Flask(__name__): Creates a Flask application instance. The __name__ argument helps Flask locate the application's resources.
  • Logging Configuration:
    • logging.basicConfig(level=logging.INFO): Configures the logging module to record events at the INFO level and higher. This means that informational messages, warnings, and errors will be logged.
    • logger = logging.getLogger(__name__): Creates a logger object specific to this module (app.py).
  • generate_image Function:
    • def generate_image(...): Defines a function that encapsulates the logic for generating an image using the OpenAI API.
    • Args:
      • prompt (str): The text description of the desired image.
      • model (str, optional): The DALL·E model to use (defaults to "dall-e-3").
      • size (str, optional): The dimensions of the generated image (defaults to "1024x1024").
      • response_format (str, optional): The format in which the image should be returned. It defaults to "url".
    • Returns:
      • Optional[str]: The URL of the generated image if the API call is successful, or None if an error occurs.
    • The function uses a try...except block to handle potential errors during the API call:
      • It logs an informational message using logger.info() before making the API call.
      • It calls the OpenAI API's openai.Image.create() method to generate the image.
      • If the API call is successful, it extracts the image URL from the response and returns it.
      • If an openai.error.OpenAIError occurs (e.g., invalid API key, API server error), it logs an error message using logger.error() and returns None.
      • If any other exception occurs, it also logs an error message and returns None.
  • index Route:
    • @app.route("/", methods=["GET", "POST"]): This decorator defines a route for the web application's main page ("/"). The index() function will handle both GET and POST requests to this URL.
    • def index():: This function handles requests to the root URL ("/").
    • image_url = None: Initializes a variable to store the image URL.
    • error_message = None: Initializes a variable to store any error message.
    • if request.method == "POST":: This block of code is executed when the user submits the form on the webpage (i.e., when the user clicks the "Generate Image" button).
      • prompt = request.form.get("prompt"): Gets the user's input from the form.
      • if not prompt:: Checks if the prompt is empty. If it is, sets an error message and returns the template.
      • model = request.form.get("model", "dall-e-3"): Gets the selected model, size, and format from the form, defaulting to "dall-e-3", "1024x1024", and "url" if not provided.
      • image_url = generate_image(prompt, model, size, response_format): Calls the generate_image() function to generate the image.
      • if not image_url:: Checks if generate_image() returned None (indicating an error). If so, sets an error message.
      • return render_template("index.html", image_url=image_url, error=error_message): Renders the index.html template, passing the image_url and error_message variables.
    • return render_template("index.html", image_url=image_url, error=error_message): This line is executed when the user first loads the page (i.e., when the browser sends a GET request to "/"). It renders the index.html template, initially with image_url and error_message set to None.
  • @app.errorhandler(500): This decorator registers a function to handle HTTP 500 errors (Internal Server Error).
    • def internal_server_error(e):: This function is called when a 500 error occurs.
      • logger.error(f"Internal Server Error: {e}"): Logs the error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renders an error page (error.html) with a generic error message and returns the HTTP status code 500.
  • if __name__ == "__main__":: This ensures that the Flask development server is started only when the script is executed directly (not when imported as a module).
    • app.run(debug=True): Starts the Flask development server in debug mode. Debug mode provides helpful error messages and automatic reloading when you make changes to the code.

5.2.5 Step 3: Create the HTML Template (templates/index.html)

Create a folder named templates in the same directory as app.py. Inside the templates folder, create a file named index.html with the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DALL·E 3 Image Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <style>
        /* --- General Styles --- */
        body {
            font-family: 'Inter', sans-serif;
            padding: 40px;
            background-color: #f9fafb; /* Tailwind's gray-50 */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            color: #374151; /* Tailwind's gray-700 */
        }
        .container {
            max-width: 800px; /* Increased max-width */
            width: 95%; /* Take up most of the viewport */
            background-color: #fff;
            padding: 2rem;
            border-radius: 0.75rem; /* Tailwind's rounded-lg */
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
            text-align: center;
        }
        h2 {
            font-size: 2.25rem; /* Tailwind's text-3xl */
            font-weight: 600;  /* Tailwind's font-semibold */
            margin-bottom: 1.5rem; /* Tailwind's mb-6 */
            color: #1e293b; /* Tailwind's gray-900 */
        }
        p{
            color: #6b7280; /* Tailwind's gray-500 */
            margin-bottom: 1rem;
        }

        /* --- Form Styles --- */
        form {
            margin-top: 1rem; /* Tailwind's mt-4 */
            margin-bottom: 1.5rem;
            display: flex;
            flex-direction: column;
            align-items: center; /* Center form elements */
            gap: 0.5rem; /* Tailwind's gap-2 */
        }
        textarea {
            width: 100%;
            max-width: 400px; /* Added max-width for text area */
            padding: 0.75rem; /* Tailwind's p-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
            resize: vertical;
            font-size: 1rem; /* Tailwind's text-base */
            line-height: 1.5rem; /* Tailwind's leading-relaxed */
            margin-bottom: 0.25rem; /* Tailwind's mb-1 */
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
        }
        textarea:focus {
            outline: none;
            border-color: #3b82f6; /* Tailwind's border-blue-500 */
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
        }
        input[type="submit"] {
            padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
            color: #fff;
            font-size: 1rem; /* Tailwind's text-base */
            font-weight: 600; /* Tailwind's font-semibold */
            cursor: pointer;
            transition: background-color 0.3s ease;
            border: none;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
        }
        input[type="submit"]:hover {
            background-color: #4338ca; /* Tailwind's bg-indigo-700 */
        }
        input[type="submit"]:focus {
            outline: none;
            box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
        }

        /* --- Image Styles --- */
        img {
            max-width: 100%;
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            margin-top: 1.5rem; /* Tailwind's mt-6 */
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* Tailwind's shadow-md */
        }

        /* --- Error Styles --- */
        .error-message {
            color: #dc2626; /* Tailwind's text-red-600 */
            margin-top: 1rem; /* Tailwind's mt-4 */
            padding: 0.75rem;
            background-color: #fee2e2;
            border-radius: 0.375rem;
            border: 1px solid #fecaca;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>🎨 Generate an Image with DALL·E</h2>
        <p> Enter a detailed prompt to generate an image. </p>
        <form method="post">
            <textarea name="prompt" rows="3" placeholder="Describe an image..."></textarea><br>
             <div style="display: flex; gap: 1rem; justify-content: center; margin-top: 0.5rem;">
                <select name="model">
                    <option value="dall-e-3">DALL·E 3</option>
                    <option value="dall-e-2">DALL·E 2</option>
                </select>
                <select name="size">
                    <option value="1024x1024">1024x1024</option>
                    <option value="1024x1792">1024x1792</option>
                    <option value="1792x1024">1792x1024</option>
                 </select>
                 <select name="format">
                    <option value="url">URL</option>
                    <option value="b64_json">Base64</option>
                </select>
            </div>
            <input type="submit" value="Generate Image">
        </form>

        {% if image_url %}
            <h3>🖼️ Result:</h3>
            <img src="{{ image_url }}" alt="Generated Image">
        {% elif error %}
            <div class="error-message">{{ error }}</div>
        {% endif %}
    </div>
</body>
</html>

The HTML template provides the structure and styling for the web page.  Key elements include:

  • HTML Structure:
    • The <head> section defines the title, links a CSS stylesheet, and sets the viewport for responsiveness.
    • The <body> contains the visible content of the page, including a container for the form and the image display area.
  • CSS Styling:
    • Modern Design: The CSS is updated to use a modern design, similar to Tailwind CSS.
    • Responsive Layout: The layout is more responsive.
    • User Experience: Improved form styling.
    • Configuration Options: The template now includes dropdowns to select the DALL·E model, image size, and response format.
    • Error Display: Displays error messages from the backend in a user-friendly way.
  • Form:
    • <form> element allows the user to input a prompt to generate an image. The <textarea> element provides a multi-line input field for the prompt, and the <input type="submit"> element is a button to submit the form. Additionally, dropdowns are added to select the model, size, and format.
  • Image Display:
    • An <img> element is used to display the generated image. The src attribute is dynamically set to the image_url passed from the Flask application.
  • Error Handling:
    • <div class="error-message"> is used to display any error messages generated by the application.

Try It Out

  1. Save the files as app.py and templates/index.html.
  2. Run the server:
    python app.py
  3. Open http://localhost:5000 in your browser.
  4. Type a prompt (e.g., "A cyberpunk city at sunset with glowing neon signs") and select the desired options.

5.2 Interactive Image Generation with Flask

Let's take our previous project to the next level by incorporating advanced interactive elements and dynamic features. This enhancement will transform the basic image generation tool into a sophisticated application that provides users with granular control over every aspect of the creation process. Here's what we'll add:

First, we'll implement real-time validation and feedback systems that guide users through crafting effective prompts. Next, we'll introduce dynamic parameter controls that allow users to fine-tune their image generation settings on the fly. Finally, we'll create an intuitive interface that makes these powerful features accessible to users of all skill levels.

5.2.1 What You’ll Build

This expanded version focuses on three key aspects: user control, immediate feedback, and reliability. Users will have precise control over the generation parameters while receiving instant visual feedback on their choices. All of this is built on a robust foundation that ensures consistent performance and error handling, creating a more engaging and flexible user experience.

You will expand the Flask web application to include these powerful advanced features, each designed to enhance user experience and functionality:

  • A meticulously designed web interface with an intuitive form for submitting prompts, featuring:
    • Real-time input validation that checks prompt length and content
    • Smart suggestion system that recommends improvements to prompt effectiveness
    • Interactive tooltips and examples to guide users in crafting better descriptions
  • Comprehensive dropdown menus offering full control over generation parameters:
    • DALL-E model selection (DALL-E 2 or 3) for different quality levels and capabilities - DALL-E 3 offers higher quality and better prompt understanding, while DALL-E 2 provides faster generation
    • Multiple image size options (1024x1024, 1024x1792, 1792x1024) for various use cases - portrait, landscape, or square formats to suit different creative needs
    • Response format selection (URL or Base64) for different integration needs - URLs for quick viewing, Base64 for direct embedding and offline storage
  • Dynamic image display functionality that shows generated images in real-time on the webpage, including:
    • Interactive preview window with zoom capabilities
    • One-click download options in multiple formats
    • Image history tracking for comparing iterations
  • Robust error handling system that:
    • Provides clear, user-friendly error messages with specific troubleshooting steps
    • Implements automatic retry mechanisms for transient failures, with configurable retry attempts and intervals
    • Ensures graceful degradation during API issues or rate limiting through fallback options and queue management

Technologies Used:

  • Flask: A Python web framework.
  • OpenAI API: To access DALL-E for image generation.
  • HTML: To structure the web page.
  • CSS: To style the web page.

Structure:

The project will have the following file structure:

  • app.py: The Python file containing the Flask application code.
  • templates/index.html: The HTML template.
  • .env: A file to store the OpenAI API key.

5.2.2 Step 1: Install Required Packages

Ensure you have the necessary Python libraries installed.

pip install flask openai python-dotenv

5.2.3 Step 2: Set up Environment Variables

Create a .env file in your project directory and add your OpenAI API key:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Step 3: Create the Flask Application (app.py)

Create a Python file named app.py with the following code:

from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def generate_image(prompt: str, model: str = "dall-e-3", size: str = "1024x1024", response_format: str = "url") -> Optional[str]:
    """
    Generates an image using OpenAI's DALL·E API.

    Args:
        prompt (str): The text prompt to generate the image from.
        model (str, optional): The DALL·E model to use. Defaults to "dall-e-3".
        size (str, optional): The size of the generated image. Defaults to "1024x1024".
        response_format (str, optional): The format of the response. Defaults to "url".

    Returns:
        Optional[str]: The URL of the generated image, or None on error.
    """
    try:
        logger.info(f"Generating image with prompt: {prompt}, model: {model}, size: {size}, format: {response_format}")
        response = openai.Image.create(
            prompt=prompt,
            model=model,
            size=size,
            response_format=response_format,
        )
        image_url = response.data[0].url
        logger.info(f"Image URL: {image_url}")
        return image_url
    except openai.error.OpenAIError as e:
        logger.error(f"OpenAI API Error: {e}")
        return None
    except Exception as e:
        logger.error(f"Error generating image: {e}")
        return None

@app.route("/", methods=["GET", "POST"])
def index():
    """
    Handles the main route for the web application.
    Generates an image based on user input and displays it.
    """
    image_url = None
    error_message = None

    if request.method == "POST":
        prompt = request.form.get("prompt")
        if not prompt:
            error_message = "Please provide a prompt to generate an image."
            logger.warning(error_message)
            return render_template("index.html", error=error_message)

        model = request.form.get("model", "dall-e-3")  # Get model from form
        size = request.form.get("size", "1024x1024")    # Get size from form
        response_format = request.form.get("format", "url")

        image_url = generate_image(prompt, model, size, response_format)

        if not image_url:
            error_message = "Failed to generate image. Please try again."  # generic error
            return render_template("index.html", error=error_message)

    return render_template("index.html", image_url=image_url, error=error_message)

@app.errorhandler(500)
def internal_server_error(e):
    """Handles internal server errors."""
    logger.error(f"Internal Server Error: {e}")
    return render_template("error.html", error="Internal Server Error"), 500


if __name__ == "__main__":
    app.run(debug=True)

Code Breakdown:

  • Import Statements:
    • from flask import Flask, request, render_template, jsonify, make_response: Imports the necessary components from the Flask framework.
    • import openai: Imports the OpenAI Python library, which allows you to interact with the OpenAI API.
    • import os: Imports the os module, which provides a way to interact with the operating system (e.g., to access environment variables).
    • from dotenv import load_dotenv: Imports the load_dotenv function from the python-dotenv library.
    • import logging: Imports the logging module for application logging.
    • from typing import Optional, Dict: Imports Optional and Dict from the typing module for type hinting.
  • Environment Variables:
    • load_dotenv(): Loads the variables from the .env file into the environment.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Retrieves the OpenAI API key from the environment variable OPENAI_API_KEY and sets it for the OpenAI library.
  • Flask Application:
    • app = Flask(__name__): Creates a Flask application instance. The __name__ argument helps Flask locate the application's resources.
  • Logging Configuration:
    • logging.basicConfig(level=logging.INFO): Configures the logging module to record events at the INFO level and higher. This means that informational messages, warnings, and errors will be logged.
    • logger = logging.getLogger(__name__): Creates a logger object specific to this module (app.py).
  • generate_image Function:
    • def generate_image(...): Defines a function that encapsulates the logic for generating an image using the OpenAI API.
    • Args:
      • prompt (str): The text description of the desired image.
      • model (str, optional): The DALL·E model to use (defaults to "dall-e-3").
      • size (str, optional): The dimensions of the generated image (defaults to "1024x1024").
      • response_format (str, optional): The format in which the image should be returned. It defaults to "url".
    • Returns:
      • Optional[str]: The URL of the generated image if the API call is successful, or None if an error occurs.
    • The function uses a try...except block to handle potential errors during the API call:
      • It logs an informational message using logger.info() before making the API call.
      • It calls the OpenAI API's openai.Image.create() method to generate the image.
      • If the API call is successful, it extracts the image URL from the response and returns it.
      • If an openai.error.OpenAIError occurs (e.g., invalid API key, API server error), it logs an error message using logger.error() and returns None.
      • If any other exception occurs, it also logs an error message and returns None.
  • index Route:
    • @app.route("/", methods=["GET", "POST"]): This decorator defines a route for the web application's main page ("/"). The index() function will handle both GET and POST requests to this URL.
    • def index():: This function handles requests to the root URL ("/").
    • image_url = None: Initializes a variable to store the image URL.
    • error_message = None: Initializes a variable to store any error message.
    • if request.method == "POST":: This block of code is executed when the user submits the form on the webpage (i.e., when the user clicks the "Generate Image" button).
      • prompt = request.form.get("prompt"): Gets the user's input from the form.
      • if not prompt:: Checks if the prompt is empty. If it is, sets an error message and returns the template.
      • model = request.form.get("model", "dall-e-3"): Gets the selected model, size, and format from the form, defaulting to "dall-e-3", "1024x1024", and "url" if not provided.
      • image_url = generate_image(prompt, model, size, response_format): Calls the generate_image() function to generate the image.
      • if not image_url:: Checks if generate_image() returned None (indicating an error). If so, sets an error message.
      • return render_template("index.html", image_url=image_url, error=error_message): Renders the index.html template, passing the image_url and error_message variables.
    • return render_template("index.html", image_url=image_url, error=error_message): This line is executed when the user first loads the page (i.e., when the browser sends a GET request to "/"). It renders the index.html template, initially with image_url and error_message set to None.
  • @app.errorhandler(500): This decorator registers a function to handle HTTP 500 errors (Internal Server Error).
    • def internal_server_error(e):: This function is called when a 500 error occurs.
      • logger.error(f"Internal Server Error: {e}"): Logs the error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renders an error page (error.html) with a generic error message and returns the HTTP status code 500.
  • if __name__ == "__main__":: This ensures that the Flask development server is started only when the script is executed directly (not when imported as a module).
    • app.run(debug=True): Starts the Flask development server in debug mode. Debug mode provides helpful error messages and automatic reloading when you make changes to the code.

5.2.5 Step 3: Create the HTML Template (templates/index.html)

Create a folder named templates in the same directory as app.py. Inside the templates folder, create a file named index.html with the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DALL·E 3 Image Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <style>
        /* --- General Styles --- */
        body {
            font-family: 'Inter', sans-serif;
            padding: 40px;
            background-color: #f9fafb; /* Tailwind's gray-50 */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            color: #374151; /* Tailwind's gray-700 */
        }
        .container {
            max-width: 800px; /* Increased max-width */
            width: 95%; /* Take up most of the viewport */
            background-color: #fff;
            padding: 2rem;
            border-radius: 0.75rem; /* Tailwind's rounded-lg */
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
            text-align: center;
        }
        h2 {
            font-size: 2.25rem; /* Tailwind's text-3xl */
            font-weight: 600;  /* Tailwind's font-semibold */
            margin-bottom: 1.5rem; /* Tailwind's mb-6 */
            color: #1e293b; /* Tailwind's gray-900 */
        }
        p{
            color: #6b7280; /* Tailwind's gray-500 */
            margin-bottom: 1rem;
        }

        /* --- Form Styles --- */
        form {
            margin-top: 1rem; /* Tailwind's mt-4 */
            margin-bottom: 1.5rem;
            display: flex;
            flex-direction: column;
            align-items: center; /* Center form elements */
            gap: 0.5rem; /* Tailwind's gap-2 */
        }
        textarea {
            width: 100%;
            max-width: 400px; /* Added max-width for text area */
            padding: 0.75rem; /* Tailwind's p-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
            resize: vertical;
            font-size: 1rem; /* Tailwind's text-base */
            line-height: 1.5rem; /* Tailwind's leading-relaxed */
            margin-bottom: 0.25rem; /* Tailwind's mb-1 */
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
        }
        textarea:focus {
            outline: none;
            border-color: #3b82f6; /* Tailwind's border-blue-500 */
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
        }
        input[type="submit"] {
            padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
            color: #fff;
            font-size: 1rem; /* Tailwind's text-base */
            font-weight: 600; /* Tailwind's font-semibold */
            cursor: pointer;
            transition: background-color 0.3s ease;
            border: none;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
        }
        input[type="submit"]:hover {
            background-color: #4338ca; /* Tailwind's bg-indigo-700 */
        }
        input[type="submit"]:focus {
            outline: none;
            box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
        }

        /* --- Image Styles --- */
        img {
            max-width: 100%;
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            margin-top: 1.5rem; /* Tailwind's mt-6 */
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* Tailwind's shadow-md */
        }

        /* --- Error Styles --- */
        .error-message {
            color: #dc2626; /* Tailwind's text-red-600 */
            margin-top: 1rem; /* Tailwind's mt-4 */
            padding: 0.75rem;
            background-color: #fee2e2;
            border-radius: 0.375rem;
            border: 1px solid #fecaca;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>🎨 Generate an Image with DALL·E</h2>
        <p> Enter a detailed prompt to generate an image. </p>
        <form method="post">
            <textarea name="prompt" rows="3" placeholder="Describe an image..."></textarea><br>
             <div style="display: flex; gap: 1rem; justify-content: center; margin-top: 0.5rem;">
                <select name="model">
                    <option value="dall-e-3">DALL·E 3</option>
                    <option value="dall-e-2">DALL·E 2</option>
                </select>
                <select name="size">
                    <option value="1024x1024">1024x1024</option>
                    <option value="1024x1792">1024x1792</option>
                    <option value="1792x1024">1792x1024</option>
                 </select>
                 <select name="format">
                    <option value="url">URL</option>
                    <option value="b64_json">Base64</option>
                </select>
            </div>
            <input type="submit" value="Generate Image">
        </form>

        {% if image_url %}
            <h3>🖼️ Result:</h3>
            <img src="{{ image_url }}" alt="Generated Image">
        {% elif error %}
            <div class="error-message">{{ error }}</div>
        {% endif %}
    </div>
</body>
</html>

The HTML template provides the structure and styling for the web page.  Key elements include:

  • HTML Structure:
    • The <head> section defines the title, links a CSS stylesheet, and sets the viewport for responsiveness.
    • The <body> contains the visible content of the page, including a container for the form and the image display area.
  • CSS Styling:
    • Modern Design: The CSS is updated to use a modern design, similar to Tailwind CSS.
    • Responsive Layout: The layout is more responsive.
    • User Experience: Improved form styling.
    • Configuration Options: The template now includes dropdowns to select the DALL·E model, image size, and response format.
    • Error Display: Displays error messages from the backend in a user-friendly way.
  • Form:
    • <form> element allows the user to input a prompt to generate an image. The <textarea> element provides a multi-line input field for the prompt, and the <input type="submit"> element is a button to submit the form. Additionally, dropdowns are added to select the model, size, and format.
  • Image Display:
    • An <img> element is used to display the generated image. The src attribute is dynamically set to the image_url passed from the Flask application.
  • Error Handling:
    • <div class="error-message"> is used to display any error messages generated by the application.

Try It Out

  1. Save the files as app.py and templates/index.html.
  2. Run the server:
    python app.py
  3. Open http://localhost:5000 in your browser.
  4. Type a prompt (e.g., "A cyberpunk city at sunset with glowing neon signs") and select the desired options.

5.2 Interactive Image Generation with Flask

Let's take our previous project to the next level by incorporating advanced interactive elements and dynamic features. This enhancement will transform the basic image generation tool into a sophisticated application that provides users with granular control over every aspect of the creation process. Here's what we'll add:

First, we'll implement real-time validation and feedback systems that guide users through crafting effective prompts. Next, we'll introduce dynamic parameter controls that allow users to fine-tune their image generation settings on the fly. Finally, we'll create an intuitive interface that makes these powerful features accessible to users of all skill levels.

5.2.1 What You’ll Build

This expanded version focuses on three key aspects: user control, immediate feedback, and reliability. Users will have precise control over the generation parameters while receiving instant visual feedback on their choices. All of this is built on a robust foundation that ensures consistent performance and error handling, creating a more engaging and flexible user experience.

You will expand the Flask web application to include these powerful advanced features, each designed to enhance user experience and functionality:

  • A meticulously designed web interface with an intuitive form for submitting prompts, featuring:
    • Real-time input validation that checks prompt length and content
    • Smart suggestion system that recommends improvements to prompt effectiveness
    • Interactive tooltips and examples to guide users in crafting better descriptions
  • Comprehensive dropdown menus offering full control over generation parameters:
    • DALL-E model selection (DALL-E 2 or 3) for different quality levels and capabilities - DALL-E 3 offers higher quality and better prompt understanding, while DALL-E 2 provides faster generation
    • Multiple image size options (1024x1024, 1024x1792, 1792x1024) for various use cases - portrait, landscape, or square formats to suit different creative needs
    • Response format selection (URL or Base64) for different integration needs - URLs for quick viewing, Base64 for direct embedding and offline storage
  • Dynamic image display functionality that shows generated images in real-time on the webpage, including:
    • Interactive preview window with zoom capabilities
    • One-click download options in multiple formats
    • Image history tracking for comparing iterations
  • Robust error handling system that:
    • Provides clear, user-friendly error messages with specific troubleshooting steps
    • Implements automatic retry mechanisms for transient failures, with configurable retry attempts and intervals
    • Ensures graceful degradation during API issues or rate limiting through fallback options and queue management

Technologies Used:

  • Flask: A Python web framework.
  • OpenAI API: To access DALL-E for image generation.
  • HTML: To structure the web page.
  • CSS: To style the web page.

Structure:

The project will have the following file structure:

  • app.py: The Python file containing the Flask application code.
  • templates/index.html: The HTML template.
  • .env: A file to store the OpenAI API key.

5.2.2 Step 1: Install Required Packages

Ensure you have the necessary Python libraries installed.

pip install flask openai python-dotenv

5.2.3 Step 2: Set up Environment Variables

Create a .env file in your project directory and add your OpenAI API key:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Step 3: Create the Flask Application (app.py)

Create a Python file named app.py with the following code:

from flask import Flask, request, render_template, jsonify, make_response
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def generate_image(prompt: str, model: str = "dall-e-3", size: str = "1024x1024", response_format: str = "url") -> Optional[str]:
    """
    Generates an image using OpenAI's DALL·E API.

    Args:
        prompt (str): The text prompt to generate the image from.
        model (str, optional): The DALL·E model to use. Defaults to "dall-e-3".
        size (str, optional): The size of the generated image. Defaults to "1024x1024".
        response_format (str, optional): The format of the response. Defaults to "url".

    Returns:
        Optional[str]: The URL of the generated image, or None on error.
    """
    try:
        logger.info(f"Generating image with prompt: {prompt}, model: {model}, size: {size}, format: {response_format}")
        response = openai.Image.create(
            prompt=prompt,
            model=model,
            size=size,
            response_format=response_format,
        )
        image_url = response.data[0].url
        logger.info(f"Image URL: {image_url}")
        return image_url
    except openai.error.OpenAIError as e:
        logger.error(f"OpenAI API Error: {e}")
        return None
    except Exception as e:
        logger.error(f"Error generating image: {e}")
        return None

@app.route("/", methods=["GET", "POST"])
def index():
    """
    Handles the main route for the web application.
    Generates an image based on user input and displays it.
    """
    image_url = None
    error_message = None

    if request.method == "POST":
        prompt = request.form.get("prompt")
        if not prompt:
            error_message = "Please provide a prompt to generate an image."
            logger.warning(error_message)
            return render_template("index.html", error=error_message)

        model = request.form.get("model", "dall-e-3")  # Get model from form
        size = request.form.get("size", "1024x1024")    # Get size from form
        response_format = request.form.get("format", "url")

        image_url = generate_image(prompt, model, size, response_format)

        if not image_url:
            error_message = "Failed to generate image. Please try again."  # generic error
            return render_template("index.html", error=error_message)

    return render_template("index.html", image_url=image_url, error=error_message)

@app.errorhandler(500)
def internal_server_error(e):
    """Handles internal server errors."""
    logger.error(f"Internal Server Error: {e}")
    return render_template("error.html", error="Internal Server Error"), 500


if __name__ == "__main__":
    app.run(debug=True)

Code Breakdown:

  • Import Statements:
    • from flask import Flask, request, render_template, jsonify, make_response: Imports the necessary components from the Flask framework.
    • import openai: Imports the OpenAI Python library, which allows you to interact with the OpenAI API.
    • import os: Imports the os module, which provides a way to interact with the operating system (e.g., to access environment variables).
    • from dotenv import load_dotenv: Imports the load_dotenv function from the python-dotenv library.
    • import logging: Imports the logging module for application logging.
    • from typing import Optional, Dict: Imports Optional and Dict from the typing module for type hinting.
  • Environment Variables:
    • load_dotenv(): Loads the variables from the .env file into the environment.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Retrieves the OpenAI API key from the environment variable OPENAI_API_KEY and sets it for the OpenAI library.
  • Flask Application:
    • app = Flask(__name__): Creates a Flask application instance. The __name__ argument helps Flask locate the application's resources.
  • Logging Configuration:
    • logging.basicConfig(level=logging.INFO): Configures the logging module to record events at the INFO level and higher. This means that informational messages, warnings, and errors will be logged.
    • logger = logging.getLogger(__name__): Creates a logger object specific to this module (app.py).
  • generate_image Function:
    • def generate_image(...): Defines a function that encapsulates the logic for generating an image using the OpenAI API.
    • Args:
      • prompt (str): The text description of the desired image.
      • model (str, optional): The DALL·E model to use (defaults to "dall-e-3").
      • size (str, optional): The dimensions of the generated image (defaults to "1024x1024").
      • response_format (str, optional): The format in which the image should be returned. It defaults to "url".
    • Returns:
      • Optional[str]: The URL of the generated image if the API call is successful, or None if an error occurs.
    • The function uses a try...except block to handle potential errors during the API call:
      • It logs an informational message using logger.info() before making the API call.
      • It calls the OpenAI API's openai.Image.create() method to generate the image.
      • If the API call is successful, it extracts the image URL from the response and returns it.
      • If an openai.error.OpenAIError occurs (e.g., invalid API key, API server error), it logs an error message using logger.error() and returns None.
      • If any other exception occurs, it also logs an error message and returns None.
  • index Route:
    • @app.route("/", methods=["GET", "POST"]): This decorator defines a route for the web application's main page ("/"). The index() function will handle both GET and POST requests to this URL.
    • def index():: This function handles requests to the root URL ("/").
    • image_url = None: Initializes a variable to store the image URL.
    • error_message = None: Initializes a variable to store any error message.
    • if request.method == "POST":: This block of code is executed when the user submits the form on the webpage (i.e., when the user clicks the "Generate Image" button).
      • prompt = request.form.get("prompt"): Gets the user's input from the form.
      • if not prompt:: Checks if the prompt is empty. If it is, sets an error message and returns the template.
      • model = request.form.get("model", "dall-e-3"): Gets the selected model, size, and format from the form, defaulting to "dall-e-3", "1024x1024", and "url" if not provided.
      • image_url = generate_image(prompt, model, size, response_format): Calls the generate_image() function to generate the image.
      • if not image_url:: Checks if generate_image() returned None (indicating an error). If so, sets an error message.
      • return render_template("index.html", image_url=image_url, error=error_message): Renders the index.html template, passing the image_url and error_message variables.
    • return render_template("index.html", image_url=image_url, error=error_message): This line is executed when the user first loads the page (i.e., when the browser sends a GET request to "/"). It renders the index.html template, initially with image_url and error_message set to None.
  • @app.errorhandler(500): This decorator registers a function to handle HTTP 500 errors (Internal Server Error).
    • def internal_server_error(e):: This function is called when a 500 error occurs.
      • logger.error(f"Internal Server Error: {e}"): Logs the error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renders an error page (error.html) with a generic error message and returns the HTTP status code 500.
  • if __name__ == "__main__":: This ensures that the Flask development server is started only when the script is executed directly (not when imported as a module).
    • app.run(debug=True): Starts the Flask development server in debug mode. Debug mode provides helpful error messages and automatic reloading when you make changes to the code.

5.2.5 Step 3: Create the HTML Template (templates/index.html)

Create a folder named templates in the same directory as app.py. Inside the templates folder, create a file named index.html with the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DALL·E 3 Image Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
    <style>
        /* --- General Styles --- */
        body {
            font-family: 'Inter', sans-serif;
            padding: 40px;
            background-color: #f9fafb; /* Tailwind's gray-50 */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            color: #374151; /* Tailwind's gray-700 */
        }
        .container {
            max-width: 800px; /* Increased max-width */
            width: 95%; /* Take up most of the viewport */
            background-color: #fff;
            padding: 2rem;
            border-radius: 0.75rem; /* Tailwind's rounded-lg */
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05); /* Tailwind's shadow-xl */
            text-align: center;
        }
        h2 {
            font-size: 2.25rem; /* Tailwind's text-3xl */
            font-weight: 600;  /* Tailwind's font-semibold */
            margin-bottom: 1.5rem; /* Tailwind's mb-6 */
            color: #1e293b; /* Tailwind's gray-900 */
        }
        p{
            color: #6b7280; /* Tailwind's gray-500 */
            margin-bottom: 1rem;
        }

        /* --- Form Styles --- */
        form {
            margin-top: 1rem; /* Tailwind's mt-4 */
            margin-bottom: 1.5rem;
            display: flex;
            flex-direction: column;
            align-items: center; /* Center form elements */
            gap: 0.5rem; /* Tailwind's gap-2 */
        }
        textarea {
            width: 100%;
            max-width: 400px; /* Added max-width for text area */
            padding: 0.75rem; /* Tailwind's p-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            border: 1px solid #d1d5db; /* Tailwind's border-gray-300 */
            resize: vertical;
            font-size: 1rem; /* Tailwind's text-base */
            line-height: 1.5rem; /* Tailwind's leading-relaxed */
            margin-bottom: 0.25rem; /* Tailwind's mb-1 */
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow */
        }
        textarea:focus {
            outline: none;
            border-color: #3b82f6; /* Tailwind's border-blue-500 */
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); /* Tailwind's ring-blue-500 */
        }
        input[type="submit"] {
            padding: 0.75rem 1.5rem; /* Tailwind's px-6 py-3 */
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            background-color: #4f46e5; /* Tailwind's bg-indigo-500 */
            color: #fff;
            font-size: 1rem; /* Tailwind's text-base */
            font-weight: 600; /* Tailwind's font-semibold */
            cursor: pointer;
            transition: background-color 0.3s ease;
            border: none;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */
        }
        input[type="submit"]:hover {
            background-color: #4338ca; /* Tailwind's bg-indigo-700 */
        }
        input[type="submit"]:focus {
            outline: none;
            box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3); /* Tailwind's ring-indigo-500 */
        }

        /* --- Image Styles --- */
        img {
            max-width: 100%;
            border-radius: 0.5rem; /* Tailwind's rounded-md */
            margin-top: 1.5rem; /* Tailwind's mt-6 */
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); /* Tailwind's shadow-md */
        }

        /* --- Error Styles --- */
        .error-message {
            color: #dc2626; /* Tailwind's text-red-600 */
            margin-top: 1rem; /* Tailwind's mt-4 */
            padding: 0.75rem;
            background-color: #fee2e2;
            border-radius: 0.375rem;
            border: 1px solid #fecaca;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>🎨 Generate an Image with DALL·E</h2>
        <p> Enter a detailed prompt to generate an image. </p>
        <form method="post">
            <textarea name="prompt" rows="3" placeholder="Describe an image..."></textarea><br>
             <div style="display: flex; gap: 1rem; justify-content: center; margin-top: 0.5rem;">
                <select name="model">
                    <option value="dall-e-3">DALL·E 3</option>
                    <option value="dall-e-2">DALL·E 2</option>
                </select>
                <select name="size">
                    <option value="1024x1024">1024x1024</option>
                    <option value="1024x1792">1024x1792</option>
                    <option value="1792x1024">1792x1024</option>
                 </select>
                 <select name="format">
                    <option value="url">URL</option>
                    <option value="b64_json">Base64</option>
                </select>
            </div>
            <input type="submit" value="Generate Image">
        </form>

        {% if image_url %}
            <h3>🖼️ Result:</h3>
            <img src="{{ image_url }}" alt="Generated Image">
        {% elif error %}
            <div class="error-message">{{ error }}</div>
        {% endif %}
    </div>
</body>
</html>

The HTML template provides the structure and styling for the web page.  Key elements include:

  • HTML Structure:
    • The <head> section defines the title, links a CSS stylesheet, and sets the viewport for responsiveness.
    • The <body> contains the visible content of the page, including a container for the form and the image display area.
  • CSS Styling:
    • Modern Design: The CSS is updated to use a modern design, similar to Tailwind CSS.
    • Responsive Layout: The layout is more responsive.
    • User Experience: Improved form styling.
    • Configuration Options: The template now includes dropdowns to select the DALL·E model, image size, and response format.
    • Error Display: Displays error messages from the backend in a user-friendly way.
  • Form:
    • <form> element allows the user to input a prompt to generate an image. The <textarea> element provides a multi-line input field for the prompt, and the <input type="submit"> element is a button to submit the form. Additionally, dropdowns are added to select the model, size, and format.
  • Image Display:
    • An <img> element is used to display the generated image. The src attribute is dynamically set to the image_url passed from the Flask application.
  • Error Handling:
    • <div class="error-message"> is used to display any error messages generated by the application.

Try It Out

  1. Save the files as app.py and templates/index.html.
  2. Run the server:
    python app.py
  3. Open http://localhost:5000 in your browser.
  4. Type a prompt (e.g., "A cyberpunk city at sunset with glowing neon signs") and select the desired options.