About this codelab
1. About this codelab
Last Updated: 2024-10-11
Written by: Laurie White
Image generation
Let's be honest, image generation by Large Language Models (LLMs) can be fun. Of course there are lots of business applications for generating images from a prompt, ranging from customized advertising to attractive presentations. (The Google Cloud Web site has many specific uses of companies that use Creative Agents.) Still, seeing what results when you ask for an image of "happy green dogs in a field" can be quite amusing.
Whether you're interested in image generation for professional or recreational reasons (or both!), there's some challenges between using an image generation program and deploying one to a web application. This lab will help you conquer those challenges.
What you'll build
In this codelab, you'll build an app that will take a text prompt and will return a web page with an image generated using that prompt.
What you'll learn
In this lab you'll learn:
- How to use Google Imagen to create images from text prompts in notebook environments
- The difficulties with moving Imagen code from a notebook to a web app
- How to deploy a Cloud Run application that uses Imagen to generate images
- How to include an image from Imagen in HTML
This codelab is focused on Imagen and deployment. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.
What you'll need
- A recent version of the Chrome browser.
- Some knowledge of Cloud Run. You can get this from the fairly short codelab here.
- Familiarity with editing files in either the Cloud Shell or Cloud Shell Editor. You can learn more about the Cloud Shell and Cloud Shell Editor from this Codelab.
- A Google Cloud Project with billing enabled. This guide will show you how to create a project. There are numerous products with free tiers and free trials available.
The complete code for this codelab is available at https://github.com/Annie29/imagen-deployment .
2. Enable APIs
Select a project to use for this Codelab. You may want to create a new project to make removing all your work easier when you're done.
Before you can start with Imagen, you'll need to enable some APIs.
- Go to the Google Cloud Console.
- Navigate to the Vertex AI Dashboard.
- Select "Enable All Recommended APIs"
3. Exploring Google Imagen (optional)
If you're familiar with Imagen, you can skip this section.
Before trying to create a web app that uses Imagen, it's useful to see what Imagen can do. Fortunately, there are a number of notebooks that run simple Imagen code, so let's start with one of those.
- Go to the notebook at https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/getting-started/image_generation.ipynb .
- Select Open in Colab to open the notebook in Google's notebook server.
- Select either "File -> Save a copy in Drive" or click "Copy to Drive"at the top of the page to create your own copy of this notebook.
- Close the original copy (just to avoid working in the wrong one!).
- You'll need to connect to a runtime by clicking the Connect button at the top right.
- Start working through each of the cells in the notebook.
- To run a cell, you can click in the [] or arrow to the left of the cell or use the Run Selection option from the Runtime menu (or its shortcut):
- When you restart the current runtime, you'll get a message your system has crashed. Don't panic. This is normal.
- You will need to authenticate your notebook environment.
- You can enter your project id (not name) and location (us-central1 works if you haven't set a location) in the boxes to the right of the code and have Colab insert them in the code for you.
- When you get to "Generate an image" you'll have an opportunity to see what Imagen can do. Feel free to change the prompt and rerun the cell to see the variety of images you can get.
- At this point you should have a good idea of how Imagen can create images from a notebook. Feel free to complete this notebook to see more about image parameters now or at a convenient time.
4. Start building a web application to show an image
We'll use Python using the Flask framework on Cloud Run to build our app.
Python Flask apps are set up in a folder as follows:
app-folder templates template.html (etc.) anothertemplate.html main.py requirements.txt
Templates are files containing HTML, usually with named placeholders where the program will insert generated text. main.py
is the web server app itself, and requirements.txt
is a list of all the non-standard libraries main.py
uses.
The application will have two pages–the first to get a prompt and the second to display the image and allow the user to enter another prompt.
First create the project framework.
Creating the file structure
This codelab assumes your project is in the folder imageapp
. If you use a different name, be sure to update commands as appropriate.
Enter Cloud Shell by selecting the prompt icon at the top right of the screen.
You can get more room to work if you move the shell to a new tab, using the arrow at the top of the shell window:
From your home directory in Cloud Shell, create the imageapp
folder, change to it, and create the templates
folders. You can do this either from the command line or the Cloud Shell editor.
Create the templates
The application will have two pages–the first (which we'll call home.html
) to get a prompt and the second (which we'll call display.html
) to display the image and allow the user to enter another prompt.
Using the Cloud Shell editor or Linux editor of your choice, create two templates. From the imageapp/templates
folder, create the initial page the user will see, home.html
. It uses the variable prompt
to return the description the user enters.
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>
Then create display.html
, which will display the image. Notice that the location of the image will be in 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. Starting the code
You'll need to create the file requirements.txt
to ensure all libraries your program needs are available. For now, just include flask
in the requirements.txt
file.
The main.py
file contains the code that will serve web requests. There are only two requests we have to handle: a GET
request for the home page, and a POST
request that submits the form describing the image we want generated.
Using the Cloud Shell editor or Linux editor of your choice, create the main.py
file in the imageapp
folder. We'll start with the skeleton below:
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)
Actually, that's almost the entire app. There are three comments in display_image
that need to be fleshed out with Python code, and that would be it.
Let's start filling in those missing parts. Flask makes retrieving the prompt easy. Add a line after the comment as shown below:
# Code to get the prompt (called prompt) from the submitted form
prompt = flask.request.form["prompt"]
If you want to test the app now, you can add a line before the return
statement in display_image
to give a value to image_url
(a valid URL that points to an image).
For example: image_url="<your url here>"
You can run the program locally from the Cloud Shell (using the command python main.py
) and preview it using the Preview on port 8080 at the top right of your screen.
As the program is now, you'll always see the image in the URL you provided. Let's move on and see how to get that value from the app. Be sure to remove the line giving image_url
a static value.
6. Creating the image
Google Cloud has a Python API for Generative AI on Vertex AI. To use it, we have to add a line importing it with the other imports near the top of our program:
from vertexai.vision_models import ImageGenerationModel
and include vertexai
in the requirements.txt
file.
The documentation for ImageGenerationModel shows how to use it. We'll create a model and then generate an image from it, given a prompt. Add code to main.py
for the second step, creating the image and storing it in response
:
# Code to generate the image
model = ImageGenerationModel.from_pretrained("imagegeneration@006")
response = model.generate_images(prompt=prompt)[0]
Up to 4 images can be created at a time, depending on the parameters sent to generate_images
, so the returned value will be a list of GeneratedImage
, even if there's just one image returned, as there is in this case.
Now we need to display the image on a WWW page. The GeneratedImage
does have a method to show
the image, but it only works in a notebook environment. But there is a method to save the image. We'll save the image and send the URL of the saved image when we render the template.
This is a little tricky and there are lots of ways to do this. Let's look at one of the simpler approaches, step by step. (And there's a picture of the steps below if you're more of a visual learner.)
First we need to save the image. But what will it be named? There can be problems using a static name since the program can be used by many people at the same time. While we could create separate image names for each user (with something like UUID), a simpler way is to use Python's tempfile
library which will create a temporary file with a unique name. The code below will create a tempfile, get its name, and write the response of the image generation step to the tempfile. We won't enter it in our code quite yet, since we need to get a URL first.
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
There are a number of ways to process the saved file, but one of the simplest and safest is using a data URL.
Data URLs allow the actual data to be sent in the URL, not just a path to it. The syntax for a data URL is:
data:[image/png][;base64],<data>
To get the base64 encoding of the image, we will need to open the file that was saved by tempfile
and read it into a variable. Yes, this will be a large string, but that should be fine with modern browsers and servers. We then will use the base64
library to encode that into a string that we can send in the data URL.
Our final code to do the third step (creating the URL) will be:
# 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}"
You can see all these steps in the image below:
You'll need to import tempfile and base64 at the beginning of your program.
import tempfile
import base64
Try running your program from Cloud Shell by being sure you're in the folder with main.py
and running the command:
python main.py
You can then preview it using the Preview on port 8080 at the top right of your screen.
7. A common error
At some point, you may notice that when running the program (either while testing or after you deploy it), you receive a message like the following:
This is most likely caused by a prompt that violates Google's Responsible AI practices . A prompt as simple as "kittens playing with colorful balls" can cause this problem. (But fear not, you can get images of "kittens playing with colorful toys.")
To deal with this error, we'll add code to catch the exception that is raised when we attempt to generate the image. If there is one, we'll render the home.html
template again, with a message showing.
First, let's add a div in the home.html template after the first form that will be displayed if there is an 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>
Then, add code in main.py
to catch a possible exception when calling the generate_images code in display_image
. If there is an exception, the code will render the home.html
template with a message.
# 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)
This is not the only Responsible AI feature of Imagen. There are a number of features that protect the generation of people and children and general filters on the images. You can see more about these here.
8. Deploying the app to the web
You can deploy the app to the web using the command from the imageapp
folder in Cloud Shell. Be sure to use your actual project id in the command.
gcloud run deploy imageapp \
--source . \
--region us-central1 \
--allow-unauthenticated \
--project your-project-id
You should see a response like the following, telling you where to find your application:
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. Cleaning Up
While Cloud Run does not charge when the service is not in use, you might still be charged for storing the container image in Artifact Registry. You can delete your repository or delete your Cloud project to avoid incurring charges. Deleting your Cloud project stops billing for all the resources used within that project.
To delete your container image repository:
gcloud artifacts repositories delete cloud-run-source-deploy \ --location $REGION
To delete your Cloud Run service:
gcloud run services delete imageapp \ --platform managed \ --region $REGION
To delete your Google Cloud project:
- Retrieve your current project ID:
PROJECT_ID=$(gcloud config get-value core/project)
- Make sure this is the project you wish to delete:
echo $PROJECT_ID
- Delete the project:
gcloud projects delete $PROJECT_ID
10. Congratulations
Congratulations, you've successfully built a web application that will display images created by Imagen. How can you use this in your application?
What's next?
Check out some of these codelabs...