Stack OverflowMediumdev.toGitHub
Creating an AI Image Generator with DALL-E API and NextJS 13

Creating an AI Image Generator with DALL-E API and NextJS 13

✍️ Published on Fri Nov 04 2022 (11 min read)

Introduction

Starting November 3, the neural network DALL-E 2 previously only accessible through restricted web interfaces, is now available in a public beta. This means developers can now use the neural network in their own applications to create images from natural text. This post will cover the steps to create a full-stack application that can interface with the API and generate some cool photos in our own web interface using the latest NextJS stack. The final app will look something like this:

What is DALL-E 2?

DALL-E 2 is a neural network trained on a massive data set of pairs of text and images scraped from the internet that is now competent enough to generate brand-new images from natural language/text. The model is capable of combining unrelated and abstract concepts to render any style of image. Here are some images generated by DALL-E 2 that gives a good idea of what the model is able to do.

An expressive oil painting of a basketball player dunking, depicted as an explosion of a nebula

a bowl of soup that is also a portal to another dimension, digital art

The model uses a process called "Diffusion" that draws a completely new picture starting from dots and incrementally changing the patterns until it resembles an image that is recognizable.

A bit About Next.js

Before we start, let's cover the latest iteration of Next.js from Vercel which lets you create a full-stack application with ease with features including server side rendering, client side rendering, out-of-the-box typescript support, all without much or any configuration. Other benefits include folder path based routing and seamless integration with vercel which lets you deploy directly from you Github account in a matter of seconds. The latest iteration (v13) adds supports fro React server components, ability to stream UI components incrementally, and turbopack, a Rust-based Webpack alternative . We'll be utilising some of the new features in this application.

Getting Started

Prerequisites

First, we'll need to have at least Node.js 14 installed on our systems (https://nodejs.org/en/download). Next, create a directory for your project and in this command in the terminal to initialise a node project.

npm init -y

Next, we'll need to install the project dependencies.

npm i [email protected] [email protected] [email protected] [email protected] openai

Add an app folder in the root directory and create a page.js file with the following contents.

export default function(){
	return <div>Hello world!</div>
}

We'll modify the contents later on.

Next, create a next.config.js folder with the following configuration.

module.exports =
    { experimental: { appDir: true } }

This will allow us to play with the latest Next 13 features, including the app folder layout.

Finally to run the application add a dev, build and start script inside the package.json file, which should look like this:

 "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },

The final folder structure should look something like this (don't worry about the layout.js , as Next.js is smart enough to create one for you)

Now, to run the project simply type the command npm run dev which should start a local dev server at localhost:3000 which should show you the web application. Another benefit of Next.js is that it supports Hot Module replacement out of the box enabling you the develop without having to refresh the app.

Code for Image Generation

page.js will contain the main component of the code and pages/api folder will contain the API that is responsible for generating the images and returning back to the client. This is where the full stack capabilities of Next.js shine, being able to do both frontend and backend from the same folder without needing much configuration.

In the page.js folder, we will add the following code:

'use client';

import { useState } from 'react';

export default function SearchPage() {
    const [prompt, setPrompt] = useState('');
    const [imageURL, setImageURL] = useState('');
    const [loading, setLoading] = useState(0);

    const handleSubmit = async (event) => {
        event.preventDefault()
        setLoading(1);
        const response = await fetch('/api/image', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                prompt
            })
        });
        const imageResponse = await response.json();
        // setImageURL(imageResponse.imageURL)
        console.log(imageResponse);
        setImageURL(imageResponse.imageURL);
        setLoading(0);
    }

    if (loading) {
        return <Loading></Loading>
    }

    if (imageURL !== '' && loading === 0) {
        return (
            <div className="imageContainer">
                <img src={imageURL}></img>
            </div>
        )
    }

    return (
        <div>
            <div className="search-box">
                <form onSubmit={handleSubmit}>
                    <button className="btn-search"><i className="fa fa-search"></i></button>
                    <input type="text" id="prompt" name="prompt" className="input-search" onChange={(e) => setPrompt(e.target.value)} placeholder="Generate Image with AI ..."></input>
                </form>
            </div>
        </div>
    )
}

function Loading(){
	return <div>Loading...</div>
}

We'll go through the main parts of the code:

  1. use client ensures that the component loads on the client instead of being server rendered. (Another neat feature that NextJS provides)
  2. handleSubmit function is responsible for calling the API endpoint that we will create later on. This simply takes the form input with the name prompt and passes it along to the API.
  3. The response will then be displayed as an image tag in the React component.

Next, we'll create a file called image.js inside /pages/api/image.js. Any js files inside the api folder will be treated as an API endpoint. Inside we create our endpoint with the code below:

import { Configuration, OpenAIApi } from "openai";
const configuration = new Configuration({
    apiKey: process.env.OPENAI_API_KEY,
});

export default async function handler(req, res) {
   if (!req.body.prompt) return res.status(400).json({message: 'Pass in prompt field for image generation'});
    const openai = new OpenAIApi(configuration);
    const response = await openai.createImage({
        prompt: req.body.prompt,
        n: 1,
        size: "1024x1024",
    });

    if (!response.data) throw new Error('Unable to get image');
    console.log('received url ' + response.data.data[0].url);

    res.status(200).json({ imageURL: response.data.data[0].url })
}

This is taking the prompt value from the API request and using the OpenAI SDK to generate the image and get its URL which we will pass back to the client. (Note that this will require an API key provided by OpenAI which is a simple endeavor, https://openai.com/)

Additionally, we have the option to add CSS to improve the layout of the project. This repository will have the complete CSS setup: https://github.com/nipeshkc7/dalle-nexjs-app

Deploying to vercel

Finally, to deploy to vercel, we'll need to setup a Github repository for the project. Then after signing up and vercel easily integrates with Github and deploys your site. It also takes care of the build process seamlessly. This is a major advantage of using Vercel for NextJS applications.

The deployment will then give you a live URL which you can now access from anywhere.

Concluding notes

With the deep integration of vercel, Next.js and Github, deploying full-stack applications can be done in a matter of minutes. We can also add databases into the mix through services like https://planetscale.com/ or https://pocketbase.io/ which is more ideal for side projects.

Resources

Also, find me on @hackernoon, @github and @medium