Menu iconMenu icon
OpenAI API Biblia Volumen 2

Capítulo 5: Proyectos de Integración de Imagen y Audio

5.2 Generación Interactiva de Imágenes con Flask

Vamos a llevar nuestro proyecto anterior al siguiente nivel incorporando elementos interactivos avanzados y características dinámicas. Esta mejora transformará la herramienta básica de generación de imágenes en una aplicación sofisticada que proporciona a los usuarios un control preciso sobre cada aspecto del proceso de creación. Esto es lo que añadiremos:

Primero, implementaremos sistemas de validación y retroalimentación en tiempo real que guían a los usuarios en la elaboración de prompts efectivos. Luego, introduciremos controles dinámicos de parámetros que permiten a los usuarios ajustar la configuración de generación de imágenes sobre la marcha. Finalmente, crearemos una interfaz intuitiva que hace que estas potentes características sean accesibles para usuarios de todos los niveles de habilidad.

5.1.1 Lo que Construirás

Esta versión expandida se centra en tres aspectos clave: control del usuario, retroalimentación inmediata y fiabilidad. Los usuarios tendrán control preciso sobre los parámetros de generación mientras reciben retroalimentación visual instantánea sobre sus elecciones. Todo esto está construido sobre una base robusta que garantiza un rendimiento consistente y manejo de errores, creando una experiencia de usuario más atractiva y flexible.

Expandirás la aplicación web Flask para incluir estas potentes características avanzadas, cada una diseñada para mejorar la experiencia y funcionalidad del usuario:

  • Una interfaz web meticulosamente diseñada con un formulario intuitivo para enviar prompts, que incluye:
    • Validación de entrada en tiempo real que verifica la longitud y contenido del prompt
    • Sistema inteligente de sugerencias que recomienda mejoras para la efectividad del prompt
    • Tooltips interactivos y ejemplos para guiar a los usuarios en la elaboración de mejores descripciones
  • Menús desplegables completos que ofrecen control total sobre los parámetros de generación:
    • Selección de modelo DALL-E (DALL-E 2 o 3) para diferentes niveles de calidad y capacidades - DALL-E 3 ofrece mayor calidad y mejor comprensión de prompts, mientras que DALL-E 2 proporciona generación más rápida
    • Múltiples opciones de tamaño de imagen (1024x1024, 1024x1792, 1792x1024) para varios casos de uso - formatos de retrato, paisaje o cuadrado para adaptarse a diferentes necesidades creativas
    • Selección de formato de respuesta (URL o Base64) para diferentes necesidades de integración - URLs para visualización rápida, Base64 para incrustación directa y almacenamiento sin conexión
  • Funcionalidad de visualización dinámica de imágenes que muestra las imágenes generadas en tiempo real en la página web, incluyendo:
    • Ventana de vista previa interactiva con capacidades de zoom
    • Opciones de descarga con un solo clic en múltiples formatos
    • Seguimiento del historial de imágenes para comparar iteraciones
  • Sistema robusto de manejo de errores que:
    • Proporciona mensajes de error claros y amigables con pasos específicos de solución de problemas
    • Implementa mecanismos automáticos de reintento para fallos transitorios, con intentos y intervalos de reintento configurables
    • Asegura una degradación elegante durante problemas de API o limitación de velocidad mediante opciones de respaldo y gestión de colas

Tecnologías Utilizadas:

  • Flask: Un framework web de Python.
  • OpenAI API: Para acceder a DALL-E para la generación de imágenes.
  • HTML: Para estructurar la página web.
  • CSS: Para estilizar la página web.

Estructura:

El proyecto tendrá la siguiente estructura de archivos:

  • app.py: El archivo Python que contiene el código de la aplicación Flask.
  • templates/index.html: La plantilla HTML.
  • .env: Un archivo para almacenar la clave API de OpenAI.

5.2.2 Paso 1: Instalar Paquetes Requeridos

Asegúrate de tener las bibliotecas Python necesarias instaladas.

pip install flask openai python-dotenv

5.2.3 Paso 2: Configurar Variables de Entorno

Crea un archivo .env en el directorio de tu proyecto y añade tu clave API de OpenAI:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Paso 3: Crear la Aplicación Flask (app.py)

Crea un archivo Python llamado app.py con el siguiente código:

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)

Desglose del Código:

  • Declaraciones de Importación:
    • from flask import Flask, request, render_template, jsonify, make_response: Importa los componentes necesarios del framework Flask.
    • import openai: Importa la biblioteca Python de OpenAI, que permite interactuar con la API de OpenAI.
    • import os: Importa el módulo os, que proporciona una forma de interactuar con el sistema operativo (por ejemplo, para acceder a variables de entorno).
    • from dotenv import load_dotenv: Importa la función load_dotenv de la biblioteca python-dotenv.
    • import logging: Importa el módulo de registro para el registro de la aplicación.
    • from typing import Optional, Dict: Importa Optional y Dict del módulo typing para sugerencias de tipo.
  • Variables de Entorno:
    • load_dotenv(): Carga las variables del archivo .env en el entorno.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Obtiene la clave API de OpenAI de la variable de entorno OPENAI_API_KEY y la establece para la biblioteca OpenAI.
  • Aplicación Flask:
    • app = Flask(__name__): Crea una instancia de la aplicación Flask. El argumento __name__ ayuda a Flask a localizar los recursos de la aplicación.
  • Configuración de Registro:
    • logging.basicConfig(level=logging.INFO): Configura el módulo de registro para registrar eventos en el nivel INFO y superior. Esto significa que se registrarán mensajes informativos, advertencias y errores.
    • logger = logging.getLogger(__name__): Crea un objeto logger específico para este módulo (app.py).
  • Función generate_image:
    • def generate_image(...): Define una función que encapsula la lógica para generar una imagen usando la API de OpenAI.
    • Args:
      • prompt (str): La descripción textual de la imagen deseada.
      • model (str, opcional): El modelo DALL·E a utilizar (por defecto "dall-e-3").
      • size (str, opcional): Las dimensiones de la imagen generada (por defecto "1024x1024").
      • response_format (str, opcional): El formato en el que se debe devolver la imagen. Por defecto es "url".
    • Returns:
      • Optional[str]: La URL de la imagen generada si la llamada a la API es exitosa, o None si ocurre un error.
    • La función utiliza un bloque try...except para manejar posibles errores durante la llamada a la API:
      • Registra un mensaje informativo usando logger.info() antes de realizar la llamada a la API.
      • Llama al método openai.Image.create() de la API de OpenAI para generar la imagen.
      • Si la llamada a la API es exitosa, extrae la URL de la imagen de la respuesta y la devuelve.
      • Si ocurre un openai.error.OpenAIError (por ejemplo, clave API inválida, error del servidor API), registra un mensaje de error usando logger.error() y devuelve None.
      • Si ocurre cualquier otra excepción, también registra un mensaje de error y devuelve None.
  • Ruta index:
    • @app.route("/", methods=["GET", "POST"]): Este decorador define una ruta para la página principal de la aplicación web ("/"). La función index() manejará tanto las solicitudes GET como POST a esta URL.
    • def index():: Esta función maneja las solicitudes a la URL raíz ("/").
    • image_url = None: Inicializa una variable para almacenar la URL de la imagen.
    • error_message = None: Inicializa una variable para almacenar cualquier mensaje de error.
    • if request.method == "POST":: Este bloque de código se ejecuta cuando el usuario envía el formulario en la página web (es decir, cuando el usuario hace clic en el botón "Generar Imagen").
      • prompt = request.form.get("prompt"): Obtiene la entrada del usuario del formulario.
      • if not prompt:: Verifica si el prompt está vacío. Si lo está, establece un mensaje de error y devuelve la plantilla.
      • model = request.form.get("model", "dall-e-3"): Obtiene el modelo, tamaño y formato seleccionados del formulario, con valores predeterminados "dall-e-3", "1024x1024" y "url" si no se proporcionan.
      • image_url = generate_image(prompt, model, size, response_format): Llama a la función generate_image() para generar la imagen.
      • if not image_url:: Verifica si generate_image() devolvió None (indicando un error). Si es así, establece un mensaje de error.
      • return render_template("index.html", image_url=image_url, error=error_message): Renderiza la plantilla index.html, pasando las variables image_url y error_message.
    • return render_template("index.html", image_url=image_url, error=error_message): Esta línea se ejecuta cuando el usuario carga la página por primera vez (es decir, cuando el navegador envía una solicitud GET a "/"). Renderiza la plantilla index.html, inicialmente con image_url y error_message establecidos en None.
  • @app.errorhandler(500): Este decorador registra una función para manejar errores HTTP 500 (Error Interno del Servidor).
    • def internal_server_error(e):: Esta función se llama cuando ocurre un error 500.
      • logger.error(f"Internal Server Error: {e}"): Registra el error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renderiza una página de error (error.html) con un mensaje de error genérico y devuelve el código de estado HTTP 500.
  • if __name__ == "__main__":: Esto asegura que el servidor de desarrollo Flask se inicie solo cuando el script se ejecuta directamente (no cuando se importa como módulo).
    • app.run(debug=True): Inicia el servidor de desarrollo Flask en modo debug. El modo debug proporciona mensajes de error útiles y recarga automática cuando se realizan cambios en el código.

5.2.5 Paso 3: Crear la Plantilla HTML (templates/index.html)

Crea una carpeta llamada templates en el mismo directorio que app.py. Dentro de la carpeta templates, crea un archivo llamado index.html con el siguiente código:

<!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>

La plantilla HTML proporciona la estructura y el estilo para la página web. Los elementos clave incluyen:

  • Estructura HTML:
    • La sección &lt;head&gt; define el título, enlaza una hoja de estilo CSS y establece el viewport para la capacidad de respuesta.
    • El &lt;body&gt; contiene el contenido visible de la página, incluyendo un contenedor para el formulario y el área de visualización de imágenes.
  • Estilo CSS:
    • Diseño Moderno: El CSS está actualizado para usar un diseño moderno, similar a Tailwind CSS.
    • Diseño Responsivo: El diseño es más adaptable.
    • Experiencia de Usuario: Mejora en el estilo del formulario.
    • Opciones de Configuración: La plantilla ahora incluye menús desplegables para seleccionar el modelo DALL·E, el tamaño de imagen y el formato de respuesta.
    • Visualización de Errores: Muestra los mensajes de error del backend de manera amigable para el usuario.
  • Formulario:
    • Un elemento &lt;form&gt; permite al usuario introducir un prompt para generar una imagen. El elemento &lt;textarea&gt; proporciona un campo de entrada multilínea para el prompt, y el elemento &lt;input type="submit"&gt; es un botón para enviar el formulario. Además, se añaden menús desplegables para seleccionar el modelo, tamaño y formato.
  • Visualización de Imagen:
    • Se utiliza un elemento &lt;img&gt; para mostrar la imagen generada. El atributo src se establece dinámicamente con el image_url pasado desde la aplicación Flask.
  • Manejo de Errores:
    • Se utiliza un &lt;div class="error-message"&gt; para mostrar cualquier mensaje de error generado por la aplicación.

Pruébalo

  1. Guarda los archivos como app.py y templates/index.html.
  2. Ejecuta el servidor:
    python app.py
  3. Abre http://localhost:5000 en tu navegador.
  4. Escribe un prompt (por ejemplo, "Una ciudad cyberpunk al atardecer con letreros de neón brillantes") y selecciona las opciones deseadas.

5.2 Generación Interactiva de Imágenes con Flask

Vamos a llevar nuestro proyecto anterior al siguiente nivel incorporando elementos interactivos avanzados y características dinámicas. Esta mejora transformará la herramienta básica de generación de imágenes en una aplicación sofisticada que proporciona a los usuarios un control preciso sobre cada aspecto del proceso de creación. Esto es lo que añadiremos:

Primero, implementaremos sistemas de validación y retroalimentación en tiempo real que guían a los usuarios en la elaboración de prompts efectivos. Luego, introduciremos controles dinámicos de parámetros que permiten a los usuarios ajustar la configuración de generación de imágenes sobre la marcha. Finalmente, crearemos una interfaz intuitiva que hace que estas potentes características sean accesibles para usuarios de todos los niveles de habilidad.

5.1.1 Lo que Construirás

Esta versión expandida se centra en tres aspectos clave: control del usuario, retroalimentación inmediata y fiabilidad. Los usuarios tendrán control preciso sobre los parámetros de generación mientras reciben retroalimentación visual instantánea sobre sus elecciones. Todo esto está construido sobre una base robusta que garantiza un rendimiento consistente y manejo de errores, creando una experiencia de usuario más atractiva y flexible.

Expandirás la aplicación web Flask para incluir estas potentes características avanzadas, cada una diseñada para mejorar la experiencia y funcionalidad del usuario:

  • Una interfaz web meticulosamente diseñada con un formulario intuitivo para enviar prompts, que incluye:
    • Validación de entrada en tiempo real que verifica la longitud y contenido del prompt
    • Sistema inteligente de sugerencias que recomienda mejoras para la efectividad del prompt
    • Tooltips interactivos y ejemplos para guiar a los usuarios en la elaboración de mejores descripciones
  • Menús desplegables completos que ofrecen control total sobre los parámetros de generación:
    • Selección de modelo DALL-E (DALL-E 2 o 3) para diferentes niveles de calidad y capacidades - DALL-E 3 ofrece mayor calidad y mejor comprensión de prompts, mientras que DALL-E 2 proporciona generación más rápida
    • Múltiples opciones de tamaño de imagen (1024x1024, 1024x1792, 1792x1024) para varios casos de uso - formatos de retrato, paisaje o cuadrado para adaptarse a diferentes necesidades creativas
    • Selección de formato de respuesta (URL o Base64) para diferentes necesidades de integración - URLs para visualización rápida, Base64 para incrustación directa y almacenamiento sin conexión
  • Funcionalidad de visualización dinámica de imágenes que muestra las imágenes generadas en tiempo real en la página web, incluyendo:
    • Ventana de vista previa interactiva con capacidades de zoom
    • Opciones de descarga con un solo clic en múltiples formatos
    • Seguimiento del historial de imágenes para comparar iteraciones
  • Sistema robusto de manejo de errores que:
    • Proporciona mensajes de error claros y amigables con pasos específicos de solución de problemas
    • Implementa mecanismos automáticos de reintento para fallos transitorios, con intentos y intervalos de reintento configurables
    • Asegura una degradación elegante durante problemas de API o limitación de velocidad mediante opciones de respaldo y gestión de colas

Tecnologías Utilizadas:

  • Flask: Un framework web de Python.
  • OpenAI API: Para acceder a DALL-E para la generación de imágenes.
  • HTML: Para estructurar la página web.
  • CSS: Para estilizar la página web.

Estructura:

El proyecto tendrá la siguiente estructura de archivos:

  • app.py: El archivo Python que contiene el código de la aplicación Flask.
  • templates/index.html: La plantilla HTML.
  • .env: Un archivo para almacenar la clave API de OpenAI.

5.2.2 Paso 1: Instalar Paquetes Requeridos

Asegúrate de tener las bibliotecas Python necesarias instaladas.

pip install flask openai python-dotenv

5.2.3 Paso 2: Configurar Variables de Entorno

Crea un archivo .env en el directorio de tu proyecto y añade tu clave API de OpenAI:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Paso 3: Crear la Aplicación Flask (app.py)

Crea un archivo Python llamado app.py con el siguiente código:

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)

Desglose del Código:

  • Declaraciones de Importación:
    • from flask import Flask, request, render_template, jsonify, make_response: Importa los componentes necesarios del framework Flask.
    • import openai: Importa la biblioteca Python de OpenAI, que permite interactuar con la API de OpenAI.
    • import os: Importa el módulo os, que proporciona una forma de interactuar con el sistema operativo (por ejemplo, para acceder a variables de entorno).
    • from dotenv import load_dotenv: Importa la función load_dotenv de la biblioteca python-dotenv.
    • import logging: Importa el módulo de registro para el registro de la aplicación.
    • from typing import Optional, Dict: Importa Optional y Dict del módulo typing para sugerencias de tipo.
  • Variables de Entorno:
    • load_dotenv(): Carga las variables del archivo .env en el entorno.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Obtiene la clave API de OpenAI de la variable de entorno OPENAI_API_KEY y la establece para la biblioteca OpenAI.
  • Aplicación Flask:
    • app = Flask(__name__): Crea una instancia de la aplicación Flask. El argumento __name__ ayuda a Flask a localizar los recursos de la aplicación.
  • Configuración de Registro:
    • logging.basicConfig(level=logging.INFO): Configura el módulo de registro para registrar eventos en el nivel INFO y superior. Esto significa que se registrarán mensajes informativos, advertencias y errores.
    • logger = logging.getLogger(__name__): Crea un objeto logger específico para este módulo (app.py).
  • Función generate_image:
    • def generate_image(...): Define una función que encapsula la lógica para generar una imagen usando la API de OpenAI.
    • Args:
      • prompt (str): La descripción textual de la imagen deseada.
      • model (str, opcional): El modelo DALL·E a utilizar (por defecto "dall-e-3").
      • size (str, opcional): Las dimensiones de la imagen generada (por defecto "1024x1024").
      • response_format (str, opcional): El formato en el que se debe devolver la imagen. Por defecto es "url".
    • Returns:
      • Optional[str]: La URL de la imagen generada si la llamada a la API es exitosa, o None si ocurre un error.
    • La función utiliza un bloque try...except para manejar posibles errores durante la llamada a la API:
      • Registra un mensaje informativo usando logger.info() antes de realizar la llamada a la API.
      • Llama al método openai.Image.create() de la API de OpenAI para generar la imagen.
      • Si la llamada a la API es exitosa, extrae la URL de la imagen de la respuesta y la devuelve.
      • Si ocurre un openai.error.OpenAIError (por ejemplo, clave API inválida, error del servidor API), registra un mensaje de error usando logger.error() y devuelve None.
      • Si ocurre cualquier otra excepción, también registra un mensaje de error y devuelve None.
  • Ruta index:
    • @app.route("/", methods=["GET", "POST"]): Este decorador define una ruta para la página principal de la aplicación web ("/"). La función index() manejará tanto las solicitudes GET como POST a esta URL.
    • def index():: Esta función maneja las solicitudes a la URL raíz ("/").
    • image_url = None: Inicializa una variable para almacenar la URL de la imagen.
    • error_message = None: Inicializa una variable para almacenar cualquier mensaje de error.
    • if request.method == "POST":: Este bloque de código se ejecuta cuando el usuario envía el formulario en la página web (es decir, cuando el usuario hace clic en el botón "Generar Imagen").
      • prompt = request.form.get("prompt"): Obtiene la entrada del usuario del formulario.
      • if not prompt:: Verifica si el prompt está vacío. Si lo está, establece un mensaje de error y devuelve la plantilla.
      • model = request.form.get("model", "dall-e-3"): Obtiene el modelo, tamaño y formato seleccionados del formulario, con valores predeterminados "dall-e-3", "1024x1024" y "url" si no se proporcionan.
      • image_url = generate_image(prompt, model, size, response_format): Llama a la función generate_image() para generar la imagen.
      • if not image_url:: Verifica si generate_image() devolvió None (indicando un error). Si es así, establece un mensaje de error.
      • return render_template("index.html", image_url=image_url, error=error_message): Renderiza la plantilla index.html, pasando las variables image_url y error_message.
    • return render_template("index.html", image_url=image_url, error=error_message): Esta línea se ejecuta cuando el usuario carga la página por primera vez (es decir, cuando el navegador envía una solicitud GET a "/"). Renderiza la plantilla index.html, inicialmente con image_url y error_message establecidos en None.
  • @app.errorhandler(500): Este decorador registra una función para manejar errores HTTP 500 (Error Interno del Servidor).
    • def internal_server_error(e):: Esta función se llama cuando ocurre un error 500.
      • logger.error(f"Internal Server Error: {e}"): Registra el error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renderiza una página de error (error.html) con un mensaje de error genérico y devuelve el código de estado HTTP 500.
  • if __name__ == "__main__":: Esto asegura que el servidor de desarrollo Flask se inicie solo cuando el script se ejecuta directamente (no cuando se importa como módulo).
    • app.run(debug=True): Inicia el servidor de desarrollo Flask en modo debug. El modo debug proporciona mensajes de error útiles y recarga automática cuando se realizan cambios en el código.

5.2.5 Paso 3: Crear la Plantilla HTML (templates/index.html)

Crea una carpeta llamada templates en el mismo directorio que app.py. Dentro de la carpeta templates, crea un archivo llamado index.html con el siguiente código:

<!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>

La plantilla HTML proporciona la estructura y el estilo para la página web. Los elementos clave incluyen:

  • Estructura HTML:
    • La sección &lt;head&gt; define el título, enlaza una hoja de estilo CSS y establece el viewport para la capacidad de respuesta.
    • El &lt;body&gt; contiene el contenido visible de la página, incluyendo un contenedor para el formulario y el área de visualización de imágenes.
  • Estilo CSS:
    • Diseño Moderno: El CSS está actualizado para usar un diseño moderno, similar a Tailwind CSS.
    • Diseño Responsivo: El diseño es más adaptable.
    • Experiencia de Usuario: Mejora en el estilo del formulario.
    • Opciones de Configuración: La plantilla ahora incluye menús desplegables para seleccionar el modelo DALL·E, el tamaño de imagen y el formato de respuesta.
    • Visualización de Errores: Muestra los mensajes de error del backend de manera amigable para el usuario.
  • Formulario:
    • Un elemento &lt;form&gt; permite al usuario introducir un prompt para generar una imagen. El elemento &lt;textarea&gt; proporciona un campo de entrada multilínea para el prompt, y el elemento &lt;input type="submit"&gt; es un botón para enviar el formulario. Además, se añaden menús desplegables para seleccionar el modelo, tamaño y formato.
  • Visualización de Imagen:
    • Se utiliza un elemento &lt;img&gt; para mostrar la imagen generada. El atributo src se establece dinámicamente con el image_url pasado desde la aplicación Flask.
  • Manejo de Errores:
    • Se utiliza un &lt;div class="error-message"&gt; para mostrar cualquier mensaje de error generado por la aplicación.

Pruébalo

  1. Guarda los archivos como app.py y templates/index.html.
  2. Ejecuta el servidor:
    python app.py
  3. Abre http://localhost:5000 en tu navegador.
  4. Escribe un prompt (por ejemplo, "Una ciudad cyberpunk al atardecer con letreros de neón brillantes") y selecciona las opciones deseadas.

5.2 Generación Interactiva de Imágenes con Flask

Vamos a llevar nuestro proyecto anterior al siguiente nivel incorporando elementos interactivos avanzados y características dinámicas. Esta mejora transformará la herramienta básica de generación de imágenes en una aplicación sofisticada que proporciona a los usuarios un control preciso sobre cada aspecto del proceso de creación. Esto es lo que añadiremos:

Primero, implementaremos sistemas de validación y retroalimentación en tiempo real que guían a los usuarios en la elaboración de prompts efectivos. Luego, introduciremos controles dinámicos de parámetros que permiten a los usuarios ajustar la configuración de generación de imágenes sobre la marcha. Finalmente, crearemos una interfaz intuitiva que hace que estas potentes características sean accesibles para usuarios de todos los niveles de habilidad.

5.1.1 Lo que Construirás

Esta versión expandida se centra en tres aspectos clave: control del usuario, retroalimentación inmediata y fiabilidad. Los usuarios tendrán control preciso sobre los parámetros de generación mientras reciben retroalimentación visual instantánea sobre sus elecciones. Todo esto está construido sobre una base robusta que garantiza un rendimiento consistente y manejo de errores, creando una experiencia de usuario más atractiva y flexible.

Expandirás la aplicación web Flask para incluir estas potentes características avanzadas, cada una diseñada para mejorar la experiencia y funcionalidad del usuario:

  • Una interfaz web meticulosamente diseñada con un formulario intuitivo para enviar prompts, que incluye:
    • Validación de entrada en tiempo real que verifica la longitud y contenido del prompt
    • Sistema inteligente de sugerencias que recomienda mejoras para la efectividad del prompt
    • Tooltips interactivos y ejemplos para guiar a los usuarios en la elaboración de mejores descripciones
  • Menús desplegables completos que ofrecen control total sobre los parámetros de generación:
    • Selección de modelo DALL-E (DALL-E 2 o 3) para diferentes niveles de calidad y capacidades - DALL-E 3 ofrece mayor calidad y mejor comprensión de prompts, mientras que DALL-E 2 proporciona generación más rápida
    • Múltiples opciones de tamaño de imagen (1024x1024, 1024x1792, 1792x1024) para varios casos de uso - formatos de retrato, paisaje o cuadrado para adaptarse a diferentes necesidades creativas
    • Selección de formato de respuesta (URL o Base64) para diferentes necesidades de integración - URLs para visualización rápida, Base64 para incrustación directa y almacenamiento sin conexión
  • Funcionalidad de visualización dinámica de imágenes que muestra las imágenes generadas en tiempo real en la página web, incluyendo:
    • Ventana de vista previa interactiva con capacidades de zoom
    • Opciones de descarga con un solo clic en múltiples formatos
    • Seguimiento del historial de imágenes para comparar iteraciones
  • Sistema robusto de manejo de errores que:
    • Proporciona mensajes de error claros y amigables con pasos específicos de solución de problemas
    • Implementa mecanismos automáticos de reintento para fallos transitorios, con intentos y intervalos de reintento configurables
    • Asegura una degradación elegante durante problemas de API o limitación de velocidad mediante opciones de respaldo y gestión de colas

Tecnologías Utilizadas:

  • Flask: Un framework web de Python.
  • OpenAI API: Para acceder a DALL-E para la generación de imágenes.
  • HTML: Para estructurar la página web.
  • CSS: Para estilizar la página web.

Estructura:

El proyecto tendrá la siguiente estructura de archivos:

  • app.py: El archivo Python que contiene el código de la aplicación Flask.
  • templates/index.html: La plantilla HTML.
  • .env: Un archivo para almacenar la clave API de OpenAI.

5.2.2 Paso 1: Instalar Paquetes Requeridos

Asegúrate de tener las bibliotecas Python necesarias instaladas.

pip install flask openai python-dotenv

5.2.3 Paso 2: Configurar Variables de Entorno

Crea un archivo .env en el directorio de tu proyecto y añade tu clave API de OpenAI:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Paso 3: Crear la Aplicación Flask (app.py)

Crea un archivo Python llamado app.py con el siguiente código:

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)

Desglose del Código:

  • Declaraciones de Importación:
    • from flask import Flask, request, render_template, jsonify, make_response: Importa los componentes necesarios del framework Flask.
    • import openai: Importa la biblioteca Python de OpenAI, que permite interactuar con la API de OpenAI.
    • import os: Importa el módulo os, que proporciona una forma de interactuar con el sistema operativo (por ejemplo, para acceder a variables de entorno).
    • from dotenv import load_dotenv: Importa la función load_dotenv de la biblioteca python-dotenv.
    • import logging: Importa el módulo de registro para el registro de la aplicación.
    • from typing import Optional, Dict: Importa Optional y Dict del módulo typing para sugerencias de tipo.
  • Variables de Entorno:
    • load_dotenv(): Carga las variables del archivo .env en el entorno.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Obtiene la clave API de OpenAI de la variable de entorno OPENAI_API_KEY y la establece para la biblioteca OpenAI.
  • Aplicación Flask:
    • app = Flask(__name__): Crea una instancia de la aplicación Flask. El argumento __name__ ayuda a Flask a localizar los recursos de la aplicación.
  • Configuración de Registro:
    • logging.basicConfig(level=logging.INFO): Configura el módulo de registro para registrar eventos en el nivel INFO y superior. Esto significa que se registrarán mensajes informativos, advertencias y errores.
    • logger = logging.getLogger(__name__): Crea un objeto logger específico para este módulo (app.py).
  • Función generate_image:
    • def generate_image(...): Define una función que encapsula la lógica para generar una imagen usando la API de OpenAI.
    • Args:
      • prompt (str): La descripción textual de la imagen deseada.
      • model (str, opcional): El modelo DALL·E a utilizar (por defecto "dall-e-3").
      • size (str, opcional): Las dimensiones de la imagen generada (por defecto "1024x1024").
      • response_format (str, opcional): El formato en el que se debe devolver la imagen. Por defecto es "url".
    • Returns:
      • Optional[str]: La URL de la imagen generada si la llamada a la API es exitosa, o None si ocurre un error.
    • La función utiliza un bloque try...except para manejar posibles errores durante la llamada a la API:
      • Registra un mensaje informativo usando logger.info() antes de realizar la llamada a la API.
      • Llama al método openai.Image.create() de la API de OpenAI para generar la imagen.
      • Si la llamada a la API es exitosa, extrae la URL de la imagen de la respuesta y la devuelve.
      • Si ocurre un openai.error.OpenAIError (por ejemplo, clave API inválida, error del servidor API), registra un mensaje de error usando logger.error() y devuelve None.
      • Si ocurre cualquier otra excepción, también registra un mensaje de error y devuelve None.
  • Ruta index:
    • @app.route("/", methods=["GET", "POST"]): Este decorador define una ruta para la página principal de la aplicación web ("/"). La función index() manejará tanto las solicitudes GET como POST a esta URL.
    • def index():: Esta función maneja las solicitudes a la URL raíz ("/").
    • image_url = None: Inicializa una variable para almacenar la URL de la imagen.
    • error_message = None: Inicializa una variable para almacenar cualquier mensaje de error.
    • if request.method == "POST":: Este bloque de código se ejecuta cuando el usuario envía el formulario en la página web (es decir, cuando el usuario hace clic en el botón "Generar Imagen").
      • prompt = request.form.get("prompt"): Obtiene la entrada del usuario del formulario.
      • if not prompt:: Verifica si el prompt está vacío. Si lo está, establece un mensaje de error y devuelve la plantilla.
      • model = request.form.get("model", "dall-e-3"): Obtiene el modelo, tamaño y formato seleccionados del formulario, con valores predeterminados "dall-e-3", "1024x1024" y "url" si no se proporcionan.
      • image_url = generate_image(prompt, model, size, response_format): Llama a la función generate_image() para generar la imagen.
      • if not image_url:: Verifica si generate_image() devolvió None (indicando un error). Si es así, establece un mensaje de error.
      • return render_template("index.html", image_url=image_url, error=error_message): Renderiza la plantilla index.html, pasando las variables image_url y error_message.
    • return render_template("index.html", image_url=image_url, error=error_message): Esta línea se ejecuta cuando el usuario carga la página por primera vez (es decir, cuando el navegador envía una solicitud GET a "/"). Renderiza la plantilla index.html, inicialmente con image_url y error_message establecidos en None.
  • @app.errorhandler(500): Este decorador registra una función para manejar errores HTTP 500 (Error Interno del Servidor).
    • def internal_server_error(e):: Esta función se llama cuando ocurre un error 500.
      • logger.error(f"Internal Server Error: {e}"): Registra el error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renderiza una página de error (error.html) con un mensaje de error genérico y devuelve el código de estado HTTP 500.
  • if __name__ == "__main__":: Esto asegura que el servidor de desarrollo Flask se inicie solo cuando el script se ejecuta directamente (no cuando se importa como módulo).
    • app.run(debug=True): Inicia el servidor de desarrollo Flask en modo debug. El modo debug proporciona mensajes de error útiles y recarga automática cuando se realizan cambios en el código.

5.2.5 Paso 3: Crear la Plantilla HTML (templates/index.html)

Crea una carpeta llamada templates en el mismo directorio que app.py. Dentro de la carpeta templates, crea un archivo llamado index.html con el siguiente código:

<!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>

La plantilla HTML proporciona la estructura y el estilo para la página web. Los elementos clave incluyen:

  • Estructura HTML:
    • La sección &lt;head&gt; define el título, enlaza una hoja de estilo CSS y establece el viewport para la capacidad de respuesta.
    • El &lt;body&gt; contiene el contenido visible de la página, incluyendo un contenedor para el formulario y el área de visualización de imágenes.
  • Estilo CSS:
    • Diseño Moderno: El CSS está actualizado para usar un diseño moderno, similar a Tailwind CSS.
    • Diseño Responsivo: El diseño es más adaptable.
    • Experiencia de Usuario: Mejora en el estilo del formulario.
    • Opciones de Configuración: La plantilla ahora incluye menús desplegables para seleccionar el modelo DALL·E, el tamaño de imagen y el formato de respuesta.
    • Visualización de Errores: Muestra los mensajes de error del backend de manera amigable para el usuario.
  • Formulario:
    • Un elemento &lt;form&gt; permite al usuario introducir un prompt para generar una imagen. El elemento &lt;textarea&gt; proporciona un campo de entrada multilínea para el prompt, y el elemento &lt;input type="submit"&gt; es un botón para enviar el formulario. Además, se añaden menús desplegables para seleccionar el modelo, tamaño y formato.
  • Visualización de Imagen:
    • Se utiliza un elemento &lt;img&gt; para mostrar la imagen generada. El atributo src se establece dinámicamente con el image_url pasado desde la aplicación Flask.
  • Manejo de Errores:
    • Se utiliza un &lt;div class="error-message"&gt; para mostrar cualquier mensaje de error generado por la aplicación.

Pruébalo

  1. Guarda los archivos como app.py y templates/index.html.
  2. Ejecuta el servidor:
    python app.py
  3. Abre http://localhost:5000 en tu navegador.
  4. Escribe un prompt (por ejemplo, "Una ciudad cyberpunk al atardecer con letreros de neón brillantes") y selecciona las opciones deseadas.

5.2 Generación Interactiva de Imágenes con Flask

Vamos a llevar nuestro proyecto anterior al siguiente nivel incorporando elementos interactivos avanzados y características dinámicas. Esta mejora transformará la herramienta básica de generación de imágenes en una aplicación sofisticada que proporciona a los usuarios un control preciso sobre cada aspecto del proceso de creación. Esto es lo que añadiremos:

Primero, implementaremos sistemas de validación y retroalimentación en tiempo real que guían a los usuarios en la elaboración de prompts efectivos. Luego, introduciremos controles dinámicos de parámetros que permiten a los usuarios ajustar la configuración de generación de imágenes sobre la marcha. Finalmente, crearemos una interfaz intuitiva que hace que estas potentes características sean accesibles para usuarios de todos los niveles de habilidad.

5.1.1 Lo que Construirás

Esta versión expandida se centra en tres aspectos clave: control del usuario, retroalimentación inmediata y fiabilidad. Los usuarios tendrán control preciso sobre los parámetros de generación mientras reciben retroalimentación visual instantánea sobre sus elecciones. Todo esto está construido sobre una base robusta que garantiza un rendimiento consistente y manejo de errores, creando una experiencia de usuario más atractiva y flexible.

Expandirás la aplicación web Flask para incluir estas potentes características avanzadas, cada una diseñada para mejorar la experiencia y funcionalidad del usuario:

  • Una interfaz web meticulosamente diseñada con un formulario intuitivo para enviar prompts, que incluye:
    • Validación de entrada en tiempo real que verifica la longitud y contenido del prompt
    • Sistema inteligente de sugerencias que recomienda mejoras para la efectividad del prompt
    • Tooltips interactivos y ejemplos para guiar a los usuarios en la elaboración de mejores descripciones
  • Menús desplegables completos que ofrecen control total sobre los parámetros de generación:
    • Selección de modelo DALL-E (DALL-E 2 o 3) para diferentes niveles de calidad y capacidades - DALL-E 3 ofrece mayor calidad y mejor comprensión de prompts, mientras que DALL-E 2 proporciona generación más rápida
    • Múltiples opciones de tamaño de imagen (1024x1024, 1024x1792, 1792x1024) para varios casos de uso - formatos de retrato, paisaje o cuadrado para adaptarse a diferentes necesidades creativas
    • Selección de formato de respuesta (URL o Base64) para diferentes necesidades de integración - URLs para visualización rápida, Base64 para incrustación directa y almacenamiento sin conexión
  • Funcionalidad de visualización dinámica de imágenes que muestra las imágenes generadas en tiempo real en la página web, incluyendo:
    • Ventana de vista previa interactiva con capacidades de zoom
    • Opciones de descarga con un solo clic en múltiples formatos
    • Seguimiento del historial de imágenes para comparar iteraciones
  • Sistema robusto de manejo de errores que:
    • Proporciona mensajes de error claros y amigables con pasos específicos de solución de problemas
    • Implementa mecanismos automáticos de reintento para fallos transitorios, con intentos y intervalos de reintento configurables
    • Asegura una degradación elegante durante problemas de API o limitación de velocidad mediante opciones de respaldo y gestión de colas

Tecnologías Utilizadas:

  • Flask: Un framework web de Python.
  • OpenAI API: Para acceder a DALL-E para la generación de imágenes.
  • HTML: Para estructurar la página web.
  • CSS: Para estilizar la página web.

Estructura:

El proyecto tendrá la siguiente estructura de archivos:

  • app.py: El archivo Python que contiene el código de la aplicación Flask.
  • templates/index.html: La plantilla HTML.
  • .env: Un archivo para almacenar la clave API de OpenAI.

5.2.2 Paso 1: Instalar Paquetes Requeridos

Asegúrate de tener las bibliotecas Python necesarias instaladas.

pip install flask openai python-dotenv

5.2.3 Paso 2: Configurar Variables de Entorno

Crea un archivo .env en el directorio de tu proyecto y añade tu clave API de OpenAI:

OPENAI_API_KEY=YOUR_OPENAI_API_KEY

5.2.4 Paso 3: Crear la Aplicación Flask (app.py)

Crea un archivo Python llamado app.py con el siguiente código:

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)

Desglose del Código:

  • Declaraciones de Importación:
    • from flask import Flask, request, render_template, jsonify, make_response: Importa los componentes necesarios del framework Flask.
    • import openai: Importa la biblioteca Python de OpenAI, que permite interactuar con la API de OpenAI.
    • import os: Importa el módulo os, que proporciona una forma de interactuar con el sistema operativo (por ejemplo, para acceder a variables de entorno).
    • from dotenv import load_dotenv: Importa la función load_dotenv de la biblioteca python-dotenv.
    • import logging: Importa el módulo de registro para el registro de la aplicación.
    • from typing import Optional, Dict: Importa Optional y Dict del módulo typing para sugerencias de tipo.
  • Variables de Entorno:
    • load_dotenv(): Carga las variables del archivo .env en el entorno.
    • openai.api_key = os.getenv("OPENAI_API_KEY"): Obtiene la clave API de OpenAI de la variable de entorno OPENAI_API_KEY y la establece para la biblioteca OpenAI.
  • Aplicación Flask:
    • app = Flask(__name__): Crea una instancia de la aplicación Flask. El argumento __name__ ayuda a Flask a localizar los recursos de la aplicación.
  • Configuración de Registro:
    • logging.basicConfig(level=logging.INFO): Configura el módulo de registro para registrar eventos en el nivel INFO y superior. Esto significa que se registrarán mensajes informativos, advertencias y errores.
    • logger = logging.getLogger(__name__): Crea un objeto logger específico para este módulo (app.py).
  • Función generate_image:
    • def generate_image(...): Define una función que encapsula la lógica para generar una imagen usando la API de OpenAI.
    • Args:
      • prompt (str): La descripción textual de la imagen deseada.
      • model (str, opcional): El modelo DALL·E a utilizar (por defecto "dall-e-3").
      • size (str, opcional): Las dimensiones de la imagen generada (por defecto "1024x1024").
      • response_format (str, opcional): El formato en el que se debe devolver la imagen. Por defecto es "url".
    • Returns:
      • Optional[str]: La URL de la imagen generada si la llamada a la API es exitosa, o None si ocurre un error.
    • La función utiliza un bloque try...except para manejar posibles errores durante la llamada a la API:
      • Registra un mensaje informativo usando logger.info() antes de realizar la llamada a la API.
      • Llama al método openai.Image.create() de la API de OpenAI para generar la imagen.
      • Si la llamada a la API es exitosa, extrae la URL de la imagen de la respuesta y la devuelve.
      • Si ocurre un openai.error.OpenAIError (por ejemplo, clave API inválida, error del servidor API), registra un mensaje de error usando logger.error() y devuelve None.
      • Si ocurre cualquier otra excepción, también registra un mensaje de error y devuelve None.
  • Ruta index:
    • @app.route("/", methods=["GET", "POST"]): Este decorador define una ruta para la página principal de la aplicación web ("/"). La función index() manejará tanto las solicitudes GET como POST a esta URL.
    • def index():: Esta función maneja las solicitudes a la URL raíz ("/").
    • image_url = None: Inicializa una variable para almacenar la URL de la imagen.
    • error_message = None: Inicializa una variable para almacenar cualquier mensaje de error.
    • if request.method == "POST":: Este bloque de código se ejecuta cuando el usuario envía el formulario en la página web (es decir, cuando el usuario hace clic en el botón "Generar Imagen").
      • prompt = request.form.get("prompt"): Obtiene la entrada del usuario del formulario.
      • if not prompt:: Verifica si el prompt está vacío. Si lo está, establece un mensaje de error y devuelve la plantilla.
      • model = request.form.get("model", "dall-e-3"): Obtiene el modelo, tamaño y formato seleccionados del formulario, con valores predeterminados "dall-e-3", "1024x1024" y "url" si no se proporcionan.
      • image_url = generate_image(prompt, model, size, response_format): Llama a la función generate_image() para generar la imagen.
      • if not image_url:: Verifica si generate_image() devolvió None (indicando un error). Si es así, establece un mensaje de error.
      • return render_template("index.html", image_url=image_url, error=error_message): Renderiza la plantilla index.html, pasando las variables image_url y error_message.
    • return render_template("index.html", image_url=image_url, error=error_message): Esta línea se ejecuta cuando el usuario carga la página por primera vez (es decir, cuando el navegador envía una solicitud GET a "/"). Renderiza la plantilla index.html, inicialmente con image_url y error_message establecidos en None.
  • @app.errorhandler(500): Este decorador registra una función para manejar errores HTTP 500 (Error Interno del Servidor).
    • def internal_server_error(e):: Esta función se llama cuando ocurre un error 500.
      • logger.error(f"Internal Server Error: {e}"): Registra el error.
      • return render_template("error.html", error="Internal Server Error"), 500: Renderiza una página de error (error.html) con un mensaje de error genérico y devuelve el código de estado HTTP 500.
  • if __name__ == "__main__":: Esto asegura que el servidor de desarrollo Flask se inicie solo cuando el script se ejecuta directamente (no cuando se importa como módulo).
    • app.run(debug=True): Inicia el servidor de desarrollo Flask en modo debug. El modo debug proporciona mensajes de error útiles y recarga automática cuando se realizan cambios en el código.

5.2.5 Paso 3: Crear la Plantilla HTML (templates/index.html)

Crea una carpeta llamada templates en el mismo directorio que app.py. Dentro de la carpeta templates, crea un archivo llamado index.html con el siguiente código:

<!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>

La plantilla HTML proporciona la estructura y el estilo para la página web. Los elementos clave incluyen:

  • Estructura HTML:
    • La sección &lt;head&gt; define el título, enlaza una hoja de estilo CSS y establece el viewport para la capacidad de respuesta.
    • El &lt;body&gt; contiene el contenido visible de la página, incluyendo un contenedor para el formulario y el área de visualización de imágenes.
  • Estilo CSS:
    • Diseño Moderno: El CSS está actualizado para usar un diseño moderno, similar a Tailwind CSS.
    • Diseño Responsivo: El diseño es más adaptable.
    • Experiencia de Usuario: Mejora en el estilo del formulario.
    • Opciones de Configuración: La plantilla ahora incluye menús desplegables para seleccionar el modelo DALL·E, el tamaño de imagen y el formato de respuesta.
    • Visualización de Errores: Muestra los mensajes de error del backend de manera amigable para el usuario.
  • Formulario:
    • Un elemento &lt;form&gt; permite al usuario introducir un prompt para generar una imagen. El elemento &lt;textarea&gt; proporciona un campo de entrada multilínea para el prompt, y el elemento &lt;input type="submit"&gt; es un botón para enviar el formulario. Además, se añaden menús desplegables para seleccionar el modelo, tamaño y formato.
  • Visualización de Imagen:
    • Se utiliza un elemento &lt;img&gt; para mostrar la imagen generada. El atributo src se establece dinámicamente con el image_url pasado desde la aplicación Flask.
  • Manejo de Errores:
    • Se utiliza un &lt;div class="error-message"&gt; para mostrar cualquier mensaje de error generado por la aplicación.

Pruébalo

  1. Guarda los archivos como app.py y templates/index.html.
  2. Ejecuta el servidor:
    python app.py
  3. Abre http://localhost:5000 en tu navegador.
  4. Escribe un prompt (por ejemplo, "Una ciudad cyberpunk al atardecer con letreros de neón brillantes") y selecciona las opciones deseadas.