Draw a Website: Transform your imagination into a website using Gemini models!

1. Introduction

In the world of web development, the process of transforming a design concept into a functional website can be both time-consuming and complex. However, with the advent of generative AI models like Gemini, this process is becoming increasingly streamlined and accessible. We will build a solution that specializes in converting hand-drawn wireframes into website code. This powerful tool empowers designers and developers alike to bring their website visions to life with unprecedented ease and efficiency.

In this lab, we will build a web application that allows users to generate website code (html, css, and javascript) from wireframes and prompts that the user enters using Vertex AI's Generative AI Models (Gemini 1.5 Flash, Gemini 1.5 Pro, etc.). The application will be built using Flask, a popular Python web framework, and will use the Vertex AI client library to interact with the Generative Models service.

What you'll build

By the end of this lab, you will have a working web application that can generate images from wireframes and prompts. You will also have a better understanding of how to use Vertex AI's Generative AI models.

Your web application will look like this:

5bccb261882c1bf0.png

How the App flows

  1. Upload a Hand-Drawn Wireframe: Users can upload an image of their hand-drawn wireframe to the app.
  2. Select a Model: The app provides a selection of pre-trained Gemini models optimized for different design styles.
  3. Provide a Prompt: Users can optionally provide a text prompt to guide the model's generation.
  4. Generate Website Code: The app sends the wireframe and prompt to Gemini, which generates the corresponding website code.
  5. Display the Result: The generated code is displayed in the app's response page.

We will start by discussing the basics of wireframes and prompts, and how they can be used to generate website code. We will then walk through the steps of building the web application, including how to handle user input, generate response, and display the results.

2. Before you begin

  1. In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
  2. Ensure that billing is enabled for your Google Cloud project. Learn how to check if billing is enabled on a project.
  3. You'll use Cloud Shell, a command-line environment running in Google Cloud. To access it, click Activate Cloud Shell at the top of the Google Cloud console.

1829c3759227c19b.png

  1. Once connected to Cloud Shell, you check that you're already authenticated and that the project is set to your project ID using the following command:
gcloud auth list
  1. Run the following command in Cloud Shell to confirm that the gcloud command knows about your project.
gcloud config list project
  1. If your project is not set, use the following command to set it:
gcloud config set project <YOUR_PROJECT_ID>
  1. Make sure that the following APIs are enabled:
  • Cloud Run
  • Vertex AI

The alternative to using the gcloud command is going through the console using this link. Refer to documentation for gcloud commands and usage.

3. Step 1: Bootstrap a Python Cloud Run Web App

We will create the Python Cloud Run web application template first from Cloud Shell.

Navigate to the Cloud Shell Terminal and click on the Open Editor button. b16d56e4979ec951.png

Make sure the Cloud Code project is set in the bottom left corner (status bar) of the Cloud Shell editor, as highlighted in the image below and is set to the active Google Cloud project where you have billing enabled. Authorize if prompted.

f5003b9c38b43262.png

Click that active project on the status bar and wait for the Cloud Code pop up to open. In the pop up select "New Application". 70f80078e01a02d8.png

From the list of applications, choose Cloud Run Application:

39abad102a72ae74.png

For the page 2/2, select Python Flask template:

a78b3a0311403ad.png

Provide the name of the project as you wish (e.g. "amazing-gemini-app") and click OK:

4d8f77279d9509cb.png

This will open up the template for the new project you just setup.

e85a020a20d38e17.png

That is how simple it is to bootstrap a web application with Google Cloud Shell.

4. Step 2: Build the Frontend

To do that, we will require a HTML page. That page will contain the code that defines the user interface for the web application. It includes a form that allows users to upload a hand-drawn wireframe image, select a generative model, and provide a text prompt. Upon submitting the form, the result will be displayed in another tab.

Copy the below code and replace your index.html file in the templates folder:

<!DOCTYPE html>
<html>
<head>
   <title>Draw a Website</title>
   <style>
       body {
           font-family: sans-serif;
           display: flex;
           justify-content: center;
           align-items: center;
           min-height: 100vh; /* Ensure form is centered vertically */
           background-color: #f4f4f4;
       }
       .container {
           background-color: white;
           padding: 30px;
           border-radius: 8px;
           box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
           text-align: center;
       }
       h2 {
           text-align: center;
           margin-bottom: 20px;
       }
       input[type="file"], textarea, select {
           width: 100%;
           padding:10px;
           margin-bottom: 15px;
           border: 1px solid #ccc;
           border-radius: 4px;
           box-sizing: border-box;
       }
       button {
           background-color: #4CAF50;
           color: white;
           padding: 12px 20px;
           border: none;
           border-radius: 4px;
           cursor: pointer;
       }
   </style>
</head>
<body>
   <div class="container">
       <h2>Draw a Website</h2>
       <form action="/response" target="_blank" method="post" enctype="multipart/form-data">
           <input type="file" id="image-upload" name="image-upload" accept=".png, .jpg, .jpeg">
           <select name="model">
               <option value="gemini-1.5-flash-001">Gemini 1.5 Flash</option>
               <option value="gemini-1.5-pro-001">Gemini 1.5 Pro</option>
               <option value="gemini-1.0-pro-vision-001">Gemini 1.0 Pro Vision</option>
               </select>
           <textarea name="prompt" placeholder="Write your prompt here. For example: 'Convert this drawing into an html page'">Convert this drawing into an html page</textarea>
           <button type="submit">Submit</button>
       </form>
   </div>
</body>
</html>

When a user interacts with the app, the following actions occur:

  1. The user selects a wireframe image, selects a model, and enters a prompt.
  2. When the user clicks the "Submit" button, the form data (image, model, and prompt) is sent to the /response URL using the HTTP POST method.
  3. The server-side code (implemented in app.py) processes the form data and generates the response using the specified model and prompt.
  4. The generated response is displayed in the new tab.

We are now ready with the front-end part of the web application.

5. Step 3: Build the Backend (Generative AI)

Let's write the main part of this web application. The app.py file that takes user input image, the choice of model, and the prompt and converts it into website code.

Copy the full code for app.py:

# Import the necessary libraries.
import os
import random
from flask import (
    Flask,
    render_template,
    request,
    redirect
)

import vertexai
from vertexai.generative_models import (
    GenerativeModel,
    Image
)

# Initialize the Flask app.
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16 MB per image

# TODO: Replace "YOUR_PROJECT_ID" before running
# Initialize the Vertex AI client library.
vertexai.init(project="YOUR_PROJECT_ID", location="us-central1")

# Define a function to generate response from a wireframe and a prompt.
def generate(wireframe, model, prompt):
    '''Generates a response from a wireframe and a prompt.
    Args:
    wireframe: The wireframe image.
    model: The generative model to use.
    prompt: The prompt to use.
    Returns:The generated response.
    '''
    # Create a GenerativeModel object.
    model = GenerativeModel(model)

    # Create a list of contents to pass to the model.
    contents = [
        wireframe,
        prompt
    ]
   
    # Generate the response.
    responses = model.generate_content(
        contents=contents,
        stream=True,
    )

    # Concatenate the response text.
    response = ""
    for res in responses:
        response += res.text.strip()
   
    # Return the generated response.
    return response

# Define the home page route.
@app.route('/', methods=['GET'])
def index():
    '''Renders the home page.
    Returns:The rendered template.
    '''
    return render_template('index.html')

# Define the response route.
@app.route('/response', methods=['GET', 'POST'])
def response():
    '''Handles the response to the user's input.
    Returns:The rendered template.
    '''
    # If the request is a POST request, process the form data.
    if request.method == 'POST':
        # Get the uploaded image from the request.
        uploaded_image = request.files['image-upload']
       
        # Convert the uploaded image to a wireframe image.
        wireframe = Image.from_bytes(uploaded_image.read())

        # Get the model and prompt from the request.
        model = request.form['model']
        prompt = request.form['prompt']
       
        # Generate the response and render the response.
        try:
            response = generate(wireframe, model, prompt)
            response = response.replace("```html", "").replace("```", "").strip()
            return response
        except ValueError as e:
            raise e
   
    # If the request is a GET request, redirect to the home page.
    else:
        return redirect('/')

# Run the app.
if __name__ == '__main__':
    # Get the server port from the environment variables.
    server_port = os.environ.get('PORT', '8080')

    # Run the app.
    app.run(debug=False, port=server_port, host='0.0.0.0')

The following is in essence what the code does:

  1. This code imports the necessary libraries for the application:

Flask: A lightweight web framework for Python.

os: For interacting with the operating system.

random: For generating random numbers.

vertexai: The Vertex AI client library.

GenerativeModel and Image: Classes from the Vertex AI Generative Models library.

  1. Initializing the flask app:

Next, it initializes the Flask application and sets the maximum allowed size for uploaded images to 16 MB.

  1. Initializing the Vertex AI Client

It initializes the Vertex AI client library with the specified project ID and location. Make sure to replace YOUR_PROJECT_ID with your project id.

  1. Defining the generate Function

This function takes a wireframe image, a generative model, and a prompt as inputs. It then generates the website html using the specified model and prompt. The generated response is returned as a string.

  1. Defining the Home Page Route

This function defines the home page route. When a user visits the root URL of the application, this function is called. It renders the index.html template, which is the home page of the application.

  1. Defining the Response Route

This function defines the response route. When a user submits the form on the home page, this function is called. It processes the uploaded image, model, and prompt, and then generates the website code. The generated response is displayed in the new tab.

  1. Running the application

This part of the code checks if the script is being run as the main program. If so, it gets the server port from the environment variables and runs the app on the specified port.

6. Step 4: Prepare Dependencies and Dockerfile

Make sure you have the following dependencies in the requirements.txt file:

Flask==2.3.3
requests==2.31.0
debugpy # Required for debugging.
google-cloud-aiplatform>=1.38

Replace the Dockerfile content with the below:

# Python image to use.
FROM python:3.11-slim

# Set the working directory to /app
WORKDIR /app

# copy the requirements file used for dependencies
COPY requirements.txt .

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Copy the rest of the working directory contents into the container at /app
COPY . .

# Run app.py when the container launches
ENTRYPOINT ["python", "app.py"]

7. Step 5: Deploy the Web Application

Now that we have the application components created, let's deploy the app.

Navigate to the Cloud Shell Terminal and make sure the current project is configured to your active project, if not you have use the gcloud configure command to set the project id:

gcloud config set project [PROJECT_ID]

Then enter the following commands in that order one by one:

cd draw-a-website
gcloud run deploy --source .

It will prompt you to enter a name for your service, let's say "draw-website". Choose the corresponding number for the region "us-central1". Say "y" when it asks if you want to allow unauthenticated invocations. Note that we are allowing unauthenticated access here because this is a demo application. Recommendation is to use appropriate authentication for your enterprise and production applications.

Once the deployment is complete, you should get a link similar to the below:

**https://draw-website-*****eua-uc.a.run.app/

Go ahead and test your application:

6ca7b67b7fce97de.png

8. Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this codelab, follow these steps:

  1. In the Google Cloud console, go to the Manage resources page.
  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.
  4. Alternatively you can go to Cloud Run on the console, select the service you just deployed and delete.

9. Congratulations

Congratulations! You have successfully built a quick web application in Python Flask deployed on Cloud Run that converts drawings into websites. The full repo is here. The draw-a-website app showcases the transformative power of Gemini in streamlining the web development process. By leveraging AI, we can empower designers and developers to create websites with greater speed, accuracy, and creativity. As generative AI models continue to evolve, we can expect even more groundbreaking applications in the future.