Implementa la imagen en Cloud Run

1. Acerca de este codelab

Última actualización: 11/10/2024

Escrito por: Laurie White

Generación de imágenes

Seamos honestos, la generación de imágenes a través de modelos de lenguaje grandes (LLM) puede ser divertida. Por supuesto, hay muchas aplicaciones comerciales para generar imágenes a partir de una instrucción, que van desde la publicidad personalizada hasta presentaciones atractivas. (El sitio web de Google Cloud tiene muchos usos específicos de empresas que usan agentes de creatividad). Sin embargo, ver los resultados cuando buscas una imagen de "perros verdes felices en un campo" puede ser bastante divertido.

Ya sea que te interese la generación de imágenes por motivos profesionales o recreativos (¡o ambos!), existen algunos desafíos entre usar un programa de generación de imágenes y, luego, implementarlo en una aplicación web. Este lab te ayudará a superar esos desafíos.

Qué compilarás

En este codelab, compilarás una app que tomará una instrucción de texto y mostrará una página web con una imagen generada con esa instrucción.

Qué aprenderás

En este lab, aprenderás lo siguiente:

  • Cómo usar Imagen de Google para crear imágenes a partir de instrucciones de texto en entornos de notebooks
  • Las dificultades para trasladar el código de Imagen de una notebook a una app web
  • Cómo implementar una aplicación de Cloud Run que usa Imagen para generar imágenes
  • Cómo incluir una imagen de Imagen en HTML

Este codelab se enfoca en Imagen y la implementación. Los conceptos y los bloques de código no relevantes se pasan por alto y se proporcionan para que simplemente los copies y pegues.

Requisitos

El código completo de este codelab está disponible en https://github.com/Annie29/imagen-deployment .

2. Habilita las APIs

Selecciona un proyecto para usar en este codelab. Te recomendamos que crees un proyecto nuevo para que sea más fácil quitar todo tu trabajo cuando termines.

Antes de comenzar a usar Imagen, deberás habilitar algunas APIs.

  1. Ve a la consola de Google Cloud:
  2. Navega al panel de Vertex AI.
  3. Selecciona "Habilitar todas las APIs recomendadas".

a8f336f7380a9eab.png

3. Explorar Google Imagen (opcional)

Si ya conoces Imagen, puedes omitir esta sección.

Antes de intentar crear una app web que use Imagen, es útil ver lo que puede hacer. Por suerte, hay varios notebooks que ejecutan código simple de Imagen, así que comencemos con uno de ellos.

  1. Ve al notebook en https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/getting-started/image_generation.ipynb .
  2. Selecciona Abrir en Colab para abrir el notebook en el servidor de notebooks de Google.
  3. Selecciona "Archivo -> Guardar una copia en Drive" o haz clic en "Copiar en Drive" en la parte superior de la página para crear tu propia copia de este notebook.
  4. Cierra la copia original (solo para evitar trabajar en la incorrecta).
  5. Para conectarte a un entorno de ejecución, haz clic en el botón Conectar en la parte superior derecha. 2afdc8fa660a89bd.png
  6. Comienza a trabajar en cada una de las celdas del notebook.
  7. Para ejecutar una celda, puedes hacer clic en [] o en la flecha a la izquierda de la celda, o bien usar la opción Ejecutar selección del menú Entorno de ejecución (o su acceso directo): dfec032ef6c31296.png
  8. Cuando reinicies el entorno de ejecución actual, recibirás un mensaje que indica que el sistema falló. ¡Que no cunda el pánico! Esto es normal.
  9. Deberás autenticar tu entorno de notebook.
  10. Puedes ingresar el ID de tu proyecto (no el nombre) y la ubicación (us-central1 funciona si no configuraste una ubicación) en los cuadros a la derecha del código y hacer que Colab los inserte en el código por ti.
  11. Cuando llegues a "Generar una imagen", tendrás la oportunidad de ver lo que puede hacer Imagen. No dudes en cambiar la instrucción y volver a ejecutar la celda para ver la variedad de imágenes que puedes obtener.
  12. En este punto, deberías tener una buena idea de cómo Imagen puede crear imágenes a partir de un notebook. No dudes en completar este notebook para obtener más información sobre los parámetros de imagen ahora o en un momento conveniente.

4. Comienza a compilar una aplicación web para mostrar una imagen

Usaremos Python con el framework de Flask en Cloud Run para compilar nuestra app.

Las apps de Flask de Python se configuran en una carpeta de la siguiente manera:

app-folder
    templates
        template.html
        (etc.)
        anothertemplate.html
    main.py
    requirements.txt

Las plantillas son archivos que contienen HTML, por lo general, con marcadores de posición nombrados en los que el programa insertará el texto generado. main.py es la app del servidor web en sí, y requirements.txt es una lista de todas las bibliotecas no estándar que usa main.py.

La aplicación tendrá dos páginas: la primera para obtener una instrucción y la segunda para mostrar la imagen y permitir que el usuario ingrese otra instrucción.

Primero, crea el framework del proyecto.

Cómo crear la estructura de archivos

En este codelab, se supone que tu proyecto está en la carpeta imageapp. Si usas un nombre diferente, asegúrate de actualizar los comandos según corresponda.

Para ingresar a Cloud Shell, selecciona el ícono de instrucción en la parte superior derecha de la pantalla.

28135f700c5b12b0.png

Puedes obtener más espacio para trabajar si mueves la shell a una pestaña nueva con la flecha que se encuentra en la parte superior de la ventana de la shell:

310422ac131813e1.png

Desde tu directorio principal en Cloud Shell, crea la carpeta imageapp, cambia a ella y crea las carpetas templates. Puedes hacerlo desde la línea de comandos o el editor de Cloud Shell.

Crea las plantillas

La aplicación tendrá dos páginas: la primera (que llamaremos home.html) para obtener una instrucción y la segunda (que llamaremos display.html) para mostrar la imagen y permitir que el usuario ingrese otra instrucción.

Crea dos plantillas con el editor de Cloud Shell o el editor de Linux que prefieras. En la carpeta imageapp/templates, crea la página inicial que verá el usuario, home.html. Usa la variable prompt para mostrar la descripción que ingresa el usuario.

templates/home.html

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>
       <form  action="/" method="post" >
           <input type="text" id="prompt" name="prompt">
           <input type="submit" value="Send">
       </form>
   </body>
</html>

Luego, crea display.html, que mostrará la imagen. Observa que la ubicación de la imagen estará en image_url.

templates/display.html

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>

       <div>
           <form  action="/" method="post" >
               <input type="text" id="prompt" name="prompt">
               <input type="submit" value="Send">
           </form>

           <p></p>
       </div>

       <div id="picture">
           <img id="pict" name="pict" alt="The created image" src="{{image_uri}}" style="width:100%;">
       </div>

   </body>
</html>

5. Cómo iniciar el código

Deberás crear el archivo requirements.txt para asegurarte de que todas las bibliotecas que necesita tu programa estén disponibles. Por ahora, solo incluye flask en el archivo requirements.txt.

El archivo main.py contiene el código que publicará las solicitudes web. Solo tenemos que controlar dos solicitudes: una solicitud GET para la página principal y una solicitud POST que envía el formulario que describe la imagen que queremos generar.

Con el editor de Cloud Shell o el editor de Linux que elijas, crea el archivo main.py en la carpeta imageapp. Comenzaremos con el siguiente esqueleto:

main.py

import flask

app = flask.Flask(__name__)

@app.route("/", methods=["GET"])
def home_page():
    return flask.render_template("home.html")

@app.route("/", methods=["POST"])
def display_image():
    # Code to get the prompt (called prompt) from the submitted form
    # Code to generate the image
    # Code to create a URL for the image (called image_url)

    return flask.render_template("display.html", prompt=prompt, image_url=image_url)

# Initialize the web server app when the code locally (Cloud Run handles it in that environment)
if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=8080)

En realidad, eso es casi toda la app. Hay tres comentarios en display_image que deben completarse con código de Python, y eso sería todo.

Comencemos a completar las partes que faltan. Flask facilita la recuperación de la instrucción. Agrega una línea después del comentario, como se muestra a continuación:

# Code to get the prompt (called prompt) from the submitted form
prompt = flask.request.form["prompt"]

Si quieres probar la app ahora, puedes agregar una línea antes de la sentencia return en display_image para asignar un valor a image_url (una URL válida que apunte a una imagen).

Por ejemplo: image_url="<your url here>"

Puedes ejecutar el programa de forma local desde Cloud Shell (con el comando python main.py) y obtener una vista previa con la opción Vista previa en el puerto 8080, que se encuentra en la parte superior derecha de la pantalla.

a80b4abd28cb7eed.png

Tal como está el programa ahora, siempre verás la imagen en la URL que proporcionaste. Sigamos adelante y veamos cómo obtener ese valor de la app. Asegúrate de quitar la línea que le asigna un valor estático a image_url.

6. Crea la imagen

Google Cloud tiene una API de Python para la IA generativa en Vertex AI. Para usarlo, debemos agregar una línea que lo importe con las otras importaciones cerca de la parte superior de nuestro programa:

from vertexai.vision_models import ImageGenerationModel

y, luego, incluye vertexai en el archivo requirements.txt.

En la documentación de ImageGenerationModel, se muestra cómo usarlo. Crearemos un modelo y, luego, generaremos una imagen a partir de él, según una instrucción. Agrega código a main.py para el segundo paso, crea la imagen y almacénala en response:

# Code to generate the image
model = ImageGenerationModel.from_pretrained("imagegeneration@006")
response = model.generate_images(prompt=prompt)[0]

Se pueden crear hasta 4 imágenes a la vez, según los parámetros que se envíen a generate_images, por lo que el valor que se muestra será una lista de GeneratedImage, incluso si solo se muestra una imagen, como en este caso.

Ahora debemos mostrar la imagen en una página WWW. GeneratedImage tiene un método para show la imagen, pero solo funciona en un entorno de notebook. Sin embargo, hay un método para guardar la imagen. Guardaremos la imagen y enviaremos la URL de la imagen guardada cuando rendericemos la plantilla.

Esto es un poco complicado y hay muchas formas de hacerlo. Veamos uno de los enfoques más simples, paso a paso. (y hay una imagen de los pasos a continuación si aprendes mejor con estímulos visuales).

Primero, debemos guardar la imagen. Pero, ¿cómo se llamará? Puede haber problemas con el uso de un nombre estático, ya que muchas personas pueden usar el programa al mismo tiempo. Si bien podríamos crear nombres de imagen independientes para cada usuario (con algo como UUID), una forma más sencilla es usar la biblioteca tempfile de Python, que creará un archivo temporal con un nombre único. El siguiente código creará un archivo temporal, obtendrá su nombre y escribirá la respuesta del paso de generación de imágenes en el archivo temporal. Aún no lo ingresaremos en nuestro código, ya que primero debemos obtener una URL.

with tempfile.NamedTemporaryFile("wb") as f:
    filename = f.name
    response.save(filename, include_generation_parameters=False)
    # process the saved file here, before it goes away

Existen varias formas de procesar el archivo guardado, pero una de las más simples y seguras es usar una URL de datos.

Las URLs de datos permiten que los datos reales se envíen en la URL, no solo una ruta de acceso a ellos. La sintaxis de una URL de datos es la siguiente:

data:[image/png][;base64],<data>

Para obtener la codificación base64 de la imagen, necesitaremos abrir el archivo que tempfile guardó y leerlo en una variable. Sí, esta será una cadena grande, pero no debería haber problemas con los navegadores y servidores modernos. Luego, usaremos la biblioteca base64 para codificarlo en una cadena que podamos enviar en la URL de datos.

Nuestro código final para realizar el tercer paso (crear la URL) será el siguiente:

# Code to create a URL for the image (called image_url)
with tempfile.NamedTemporaryFile("wb") as f:
    filename = f.name
    response.save(filename, include_generation_parameters=False)
    # process the saved file here, before it goes away
    with open(filename, "rb") as image_file:
        binary_image = image_file.read()
        base64_image = base64.b64encode(binary_image).decode("utf-8")
        image_url = f"data:image/png;base64,{base64_image}"

Puedes ver todos estos pasos en la siguiente imagen:

268876579dc02376.png

Deberás importar tempfile y base64 al comienzo de tu programa.

import tempfile
import base64

Intenta ejecutar tu programa desde Cloud Shell. Para ello, asegúrate de estar en la carpeta con main.py y ejecuta el siguiente comando:

python main.py

Luego, puedes obtener una vista previa con la opción Vista previa en el puerto 8080 en la parte superior derecha de la pantalla.

a80b4abd28cb7eed.png

7. Un error común

En algún momento, es posible que notes que, cuando ejecutas el programa (ya sea durante la prueba o después de implementarlo), recibes un mensaje como el siguiente:

2366c3bba6273517.png

Es probable que esto se deba a una instrucción que incumple las prácticas de IA responsable de Google . Una instrucción tan simple como "gatitos jugando con pelotas de colores" puede causar este problema. (Pero no te preocupes, puedes obtener imágenes de "gatitos jugando con juguetes coloridos").

Para solucionar este error, agregaremos código para capturar la excepción que se genera cuando intentamos generar la imagen. Si hay uno, volveremos a renderizar la plantilla home.html con un mensaje.

Primero, agreguemos un div en la plantilla home.html después del primer formulario que se mostrará si hay un error:

<!DOCTYPE html>
<html>
   <head>
       <title>Let's draw a picture</title>
   </head>
   <body>
       <h1>Let's draw a picture</h1>
       <form  action="/" method="post" >
           <input type="text" id="prompt" name="prompt">
           <input type="submit" value="Send">
       </form>
       {% if mistake %}
       <div id="warning">
       The prompt contains sensitive words that violate
       <a href=\"https://ai.google/responsibility/responsible-ai-practices\">
           Google's Responsible AI practices</a>.
       Try rephrasing the prompt."</div>

       {% endif %}

   </body>
</html>

Luego, agrega código en main.py para detectar una posible excepción cuando llames al código generate_images en display_image. Si hay una excepción, el código renderizará la plantilla home.html con un mensaje.

# Code to generate the image
   model = ImageGenerationModel.from_pretrained("imagegeneration@006")
   try:
       response = model.generate_images(prompt=prompt)[0]   
   except:
       #  This is probably due to a questionable prompt
       return flask.render_template("home.html", warning=True)

Esta no es la única función de IA responsable de Imagen. Hay varias funciones que protegen la generación de personas y niños, y los filtros generales en las imágenes. Puedes obtener más información sobre estos aquí.

8. Implementa la app en la Web

Puedes implementar la app en la Web con el comando de la carpeta imageapp en Cloud Shell. Asegúrate de usar el ID de tu proyecto real en el comando.

gcloud run deploy imageapp \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --project your-project-id

Deberías ver una respuesta como la siguiente, en la que se te indica dónde encontrar tu solicitud:

Service [imageapp] revision [imageapp-00001-t48] has been deployed and is serving 100 percent of traffic.
Service URL: https://imageapp-708208532564.us-central1.run.app```

9. Limpieza

Si bien Cloud Run no cobra cuando el servicio no se usa, es posible que se te cobre por el almacenamiento de la imagen del contenedor en Artifact Registry. Puedes borrar tu repositorio o borrar tu proyecto de Cloud para evitar que se apliquen cargos. Si borras tu proyecto de Cloud, se detendrá la facturación de todos los recursos que usaste en ese proyecto.

Para borrar el repositorio de imágenes de contenedor, sigue estos pasos:

gcloud artifacts repositories delete cloud-run-source-deploy \
  --location $REGION

Para borrar tu servicio de Cloud Run, sigue estos pasos:

gcloud run services delete imageapp \
  --platform managed \
  --region $REGION

Para borrar tu proyecto de Google Cloud, sigue estos pasos:

  1. Recupera el ID de tu proyecto actual:
PROJECT_ID=$(gcloud config get-value core/project)
  1. Asegúrate de que este sea el proyecto que quieres borrar:
echo $PROJECT_ID
  1. Borra el proyecto:
gcloud projects delete $PROJECT_ID

10. Felicitaciones

¡Felicitaciones! Compilaste correctamente una aplicación web que mostrará imágenes creadas por Imagen. ¿Cómo puedes usar esto en tu aplicación?

¿Qué sigue?

Consulta algunos codelabs sobre los siguientes temas:

Lecturas adicionales