How to build an image generator app in Next Js (using Dall-e-2 API and Next Js)

what we are going to build (Next Js Project demo)

Hi, welcome here In this tutorial, we are going to build an image generator app with OpenAi’s Dall e 2 API and Next Js. The prerequisites for this project are as follows:

  1. Node.js should be installed in your system.
  2. Create a brand new Next Js project. Just copy the code below:
npx create-next-app my-app
JavaScript

The brand-new project should look like this:

Next Js image generator app with Dall e 2 api
Next Js image generator app with Dall e 2 API

Here is your index.js file, copy the code below and paste it into index.js. Don’t forget to add your API key.

import Head from 'next/head'
import { useState } from 'react'
import axios from 'axios';


export default function Home() {

  const [token, setToken] = useState("your-api-key")
  const [prompt, setPrompt] = useState("")
  const [number, setNumber] = useState(4)
  const [results, setResults] = useState([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(false)
  const [type, setType] = useState("png")

  function generateImages () {
    if (token != "" && prompt != "")
    {
      setError(false);
      setLoading(true);
      axios.post(`/api/images?t=${token}&p=${prompt}&n=${number}`).then(
        (res) => {
          setResults(res.data.result);
          setLoading(false);
        }
      )
      .catch((err) => {
        setLoading(false);
        setError(true);
      });
    } else {
      setError(true);
    }
  }

  function download(url) {
    axios.post(`/api/download`, {url: url, type: true}).then(
      (res) => {
        const link = document.createElement("a");
        link.href = res.data.result;
        link.download = `${prompt}.${type.toLowerCase()}`;
        link.click();
      }
    )
    .catch((err) => {console.log(err);})
  }

  return (
    <div className="container">
      <Head>
        <title>Next Image Generator</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="main">
        <h1 className="title">
          Create images with
          <span className="titleColor">NextJs + Dalle2</span>
        </h1>
        <p className="description">
        
          <input
          id="prompt"
          type="text"
          value={prompt}
          onChange={(e) => setPrompt(e.target.value)}
          placeholder="Enter your query"
          />
          
          <input
          id="number"
          type="text"
          value={number}
          onChange={(e) => setNumber(e.target.value)}
          placeholder="Enter the number of images"
          max="10"
          />

          <button onClick={generateImages}>
            Generate
          </button>

        </p>

        <div>
          Download as: {" "}
          <select className="dSelect" id="type" value={type} onChange={(e) => setType(e.target.value)}>
            <option className="dOption" value="webp">Webp</option>
            <option className="dOption" value="png">Png</option>
            <option className="dOption" value="jpg">Jpg</option>
            <option className="dOption" value="avif">Avif</option>
          </select>
          {" "}
          You can download the image with a single click
        </div>
        <br />
        {error ? ( <div className="error">Something went wrong. Try again.</div> ) : ( <></> )}
        {loading && <p>Loading...</p>}

        <div className="grid">
          {
            results.map((result) => {
              return (
                <div className="card">
                  <img
                  className="imgPreview"
                  src={result.url}
                  onClick={() => download(result.url)}
                  />
                </div>
              )
            })
          }
        </div>

      </main>

    </div>
  )
}
JavaScript

Here is your code for the globals.css file:

html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
  body {
    color: white;
    background: black;
  }
}


/* lets add the styling */

input {
  font-size: 16px;
  padding: 10px;
  margin: 10px;
  border: none;
  outline: none;
  margin-bottom: 10px;
  border-radius: 3px;
}
button{
  font-size: 16px;
  padding: 10px;
  border: none;
  border-bottom: 5px solid #ccc;
  margin-bottom: 10px;
  border-radius: 6px;
  color: rgb(15, 15, 15);
  transition: all 0.3s ease-in-out;
}

button:hover {
  background-color: rgb(15, 15, 15);
  cursor: pointer;
  color: white;
}
.dSelect{
  font-size: 16px;
  padding: 10px;
  margin: 10px;
  border: none;
  border-bottom: 1px solid #ccc;
  margin-bottom: 10px;
  border-radius: 3px;
  outline: none;
}
.dOption{
  font-size: 16px;
  padding: 10px;
  margin: 10px;
  border: none;
  border-bottom: 1px solid #ccc;
  margin-bottom: 10px;
  border-radius: 3px;
  outline: none;
}
.container {
  color: white;
  padding: 0 2rem;
  background-image: linear-gradient( 135deg, #25bce2 10%, #FCFF00 100%);
}
.main {
  min-height: 100vh;
  padding: 4rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.titleColor {
  color: rgb(15, 15, 15);
}

.title {
  margin: 0;
  line-height: 1.15;
  font-size: 4rem;
  color: white;
}

.title,
.description {
  text-align: center;
}

.description {
  margin: 3rem 0;
  line-height: 1.5;
  font-size: 1.5rem;
}
.grid {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  max-width: 1200px;
}
.card {
  padding: 1rem;
  text-align: left;
  color: inherit;
  text-decoration: none;
  border-radius: 10px;
  transition: color 0.15s ease, border-color 0.15s ease;
  max-width: 400px; /* 300px for 3 in a row */
}
.imgPreview {
  width: 100%;
  border-radius: 5px;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  line-height: 1.42857143;
  list-style: none;
  box-sizing: border-box;
  outline: 0;
  text-decoration: none;
  position: relative;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  flex-direction: column;
  background: #FFF;
  border: none;
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.671);
  pointer-events: auto;
  cursor: pointer;
  transition: all .5s ease-in-out;
}

.imgPreview:hover,
.imgPreview:focus,
.imgPreview:active {
  transform: scale(1.1);
  cursor: pointer;
  /* transition-duration: 1s; */
}
CSS

After creating a Next Js project, make two files in the API directory (download.js and images.js). Copy the code below, and past it to the corresponding files:

The code for the ‘images.js’ is as follows:

export default async function handler(req, res) {
  const { Configuration, OpenAIApi } = require("openai");
  const configuration = new Configuration({
    apiKey: req.query.t,
  });
  const openai = new OpenAIApi(configuration);
  const response = await openai.createImage({
    prompt: req.query.p,
    n: parseInt(req.query.n),
    size: "1024x1024",
  });
  console.log(response.data.data);
  res.status(200).json({ result: response.data.data })
}
JavaScript

The code for the ‘download.js’ is as follows:

import axios from 'axios';
import sharp from "sharp";

export default async function handler (req, res) {
    const url = req.body.url;
    const type = req.body.url;

    const response = await axios.get(url, {responseType: "arraybuffer"})
    const base64 = Buffer.from(response.data, "binary").toString("base64");

    if(type == 'png') {
        const png = await sharp(Buffer.from(base64, "base64")).png().toBuffer();
        const pngBase64 = Buffer.from(png, "binary").toString("base64");
        res.status(200).json( { result: `data:image/png;base64,${pngBase64}`});
    } else if (type == 'jpg'){
        const jpg = await sharp(Buffer.from(base64, "base64")).jpg().toBuffer();
        const jpgBase64 = Buffer.from(jpg, "binary").toString("base64");
        res.status(200).json( { result: `data:image/jpg;base64,${jpgBase64}`});
    } else if (type == 'avi'){
        const avif = await sharp(Buffer.from(base64, "base64")).avif().toBuffer();
        const avifBase64 = Buffer.from(avif, "binary").toString("base64");
        res.status(200).json( { result: `data:image/avif;base64,${avifBase64}`});
    } else {
        const webp = await sharp(Buffer.from(base64, "base64")).webp().toBuffer();
        const webpBase64 = Buffer.from(webp, "binary").toString("base64");
        res.status(200).json( { result: `data:image/webp;base64,${webpBase64}`}); 
    }
}
JavaScript

After writing the code into the files (don’t forget to save it ?,) you can run the command below:

npm run dev
JavaScript

Here is complete to build image generated app using next js and open ai.