Build an AI wallpaper generator app using Rapid and OpenAI

•

Wed Feb 08 2023

•

17 min read

With the release of ChatGPT, AI has become the new big thing. And there is a solid reason why. ChatGPT is a chatbot that uses OpenAI’s GPT 3 API to interact with the user.

OpenAI offers many other APIs to its users that they can use to implement different use cases of the APIs via building web or mobile apps.

In this piece, we will utilize the DALL•E API that OpenAI offers, use another API from RapidAPI Hub, and build a simple AI wallpaper generator app. So without any further ado, let’s jump in!

Our toolkit

Before we jump into the coding part, we need to select the tools and technologies we will be using to build our wallpaper generator. I have already selected our toolkit which you can find below:

Next.js

To implement the front end, we will use Next.js. It is a web framework built on top of React.js.

Next.js extends the capabilities of React.js by providing the developers with features like server-side rendering, static site generation, incremental static generation, serverless functions, file-system-based routing, dynamic routing, etc. It provides better optimization, additional structure, and features to your application.

DALL·E API

We will use one of OpenAI’s APIs called DALL·E. It allows users to generate unique and diverse images from textual descriptions. The API is based on state-of-the-art machine learning algorithms and has the ability to generate a wide range of images, from photorealistic to highly imaginative.

RapidAPI Hub

On top of the DALL·E API API, we will be using an API from RapidAPI Hub. RapidAPI Hub is the world’s largest API Hub that houses over 40,000+ usable APIs. These APIs are divided into 49 different categories.

We will use the Thefluentme API from RapidAPI Hub.

Loading component...

RapidAPI Client

To test DALL·E API endpoints, we will use RapidAPI Client, a VS Code extension that lets you test APIs without leaving your code editor.

RapidAPI Client is a full-featured HTTP client that lets you test and describes the APIs you build or consume. Designed to work with your VS Code themes, RapidAPI Client makes composing requests, inspecting responses, generating code, and types for application development simple and intuitive.

Loading component...

Tailwind CSS

Lastly, to style our application, we will use Tailwind CSS. It is a utility-first CSS framework for building responsive and fast-loading user interfaces. It offers a set of pre-designed CSS classes that can be easily combined to create complex UI elements and designs without having to write custom CSS code.

Initial Setup

We plan to use the DALL•E API. Since OpenAI is its provider, we will need an OpenAI account. So go ahead and create one. Once you are done, you will get $18.00 worth of free credits which will be valid for three months.

Before building the application around the API, we need to test it. This is where RapidAPI Client comes into the picture. Let’s go ahead and install it.

Open your Visual Studio Code and click on the Extensions icon from the left sidebar. Search for RapidAPI Client and it will pop up. From here, all you need to do is click on the Install button and you are good to go.

Loading component...

I assume you have created an account by now on RapidAPI Hub. If you haven’t, you can click here to create one.

Let’s go ahead and subscribe to the Thefluentme API. Click on Subscribe to Test button. It will redirect you to another page where different available subscription packages will be shown. Let’s go with the free one for now.

After all this, you will be redirected back to the original page. Here you will have your RapidAPI key, i.e., x-rapidapi-key. Please save it somewhere. It will be used later in the application.

Test DALL·E API

Let’s test our API. We will do it by going through the following steps:

STEP #1

Head to DALL·E API documentation on OpenAI. Click the copy button in the example request on the right. Please ensure that you have selected cURL as a library.

STEP #2

Now go back to Visual Studio Code and open the command palette. Search for RapidAPI: Create a new request from the clipboard or cURL command and select it.

It will create a RapidAPI Client request where everything will be filled from the cURL command we copied in step 1. Head to the Headers section inside RapidAPI Client request and add your OpenAI API key beside Bearer.

Loading component...

Lastly, click on the Send button. RapidAPI Client will make the API call to the DALL·E API. If the call is successful, you will see an API response on the right.

If an API request fails, RapidAPI Client will display the status code and the error message, so you know what went wrong.

Code AI Wallpaper Generator

Now that we have tested our API, let’s start building our AI Wallpaper generator app. Here is what our application will look like in the end.

Bootstrap a Next.js Tailwind CSS app

We need a starter template for Next.js with Tailwind CSS. Fortunately, Vercel offers one that we can use and start building without wasting any time.

Please go ahead and open your terminal to run the following command:

sh
npx create-next-app -e with-tailwindcss wallai

It will take a few minutes depending on your internet connection. Once it is done, you will see a wallai directory created where you will find a Next.js Tailwind CSS TypeScript project.

Please go ahead and open this directory in your code editor.

Project Files

This Next.js template provides different files and directories. Let’s take a look at them.

  • pages directory: Inside it, you will find files like index.tsx, _app.tsx, and another directory called api. You only need to know about the index.tsx file that is the main entry point in your project.
  • public directory: This directory contains icons. You place your static files here to load later in the application.
  • node_modules: It’s another directory that contains all the third-party packages you are using in your application.
  • package.json: This file contains the metadata of your project.
  • package-lock.json: This file is responsible for tracking the exact version of every installed package.
  • postcss.config.js: This file contains PostCSS configurations to work with Tailwind CSS.
  • tailwind.config.js: It contains TailwindCSS configurations.
  • next.config.js: This file contains your apps Next.js configuration. - readme.md: It’s a markdown file for documentation.

Please go ahead and copy this Next.js config in your next.config.js file.

STEP 1: Add a title

Now that you know everything about the template you created, let’s start coding. Open the pages/index.tsx file and remove all the existing code. After this, copy-paste the following code there:

tsx
import type { NextPage } from "next";
import Head from "next/head";
const Home: NextPage = () => {
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>WallAI</title>
<link rel="icon" href="/favicon.ico" />
</Head>
</div>
)
}
export default Home;

Now start the project by running the following command in your project terminal:

sh
npm run dev

It will execute the Next.js project on localhost 3000. Once you open the link, you will see a blank page. It’s because we have not written any code which translated into a UI.

However, you will see a title at the top that will say WallAI. It’s because we used the Next.js Head component to set a title for our Homepage.

STEP 2: Building a Hero section

Let’s build some UI. We can start by creating a simple Hero section.

tsx
import type { NextPage } from "next";
import Head from "next/head";
const Home: NextPage = () => {
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>WallAI</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex w-full flex-1 flex-col items-center justify-center md:px-20 text-center my-16">
<h1 className="text-7xl font-bold font-sans text-[#0055d9]">WallAI</h1>
<p className="mt-8 text-2xl md:w-2/5 text-[#081477] font-bold">
Create unique and stunning wallpapers using API
</p>
</main>
</div>
)
}
export default Home;

This will create a heading and a tagline for you. You can change it to however you like.

STEP 3: User description and buttons

Now that we have a heading and tagline, let’s create a text box and two buttons. The first button will suggest a wallpaper and the second one will generate the wallpaper based on user-provided text.

For this, go ahead and copy the following code inside index.tsx.

tsx
import type { NextPage } from "next";
import Head from "next/head";
const Home: NextPage = () => {
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>WallAI</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex w-full flex-1 flex-col items-center justify-center md:px-20 text-center my-16">
<h1 className="text-7xl font-bold font-sans text-[#0055d9]">WallAI</h1>
<p className="mt-8 text-2xl md:w-2/5 text-[#081477] font-bold">
Create unique and stunning wallpapers using API
</p>
<div className="mt-12 flex max-w-xl flex-col flex-wrap sm:w-full border border-gray-300 p-6 rounded-md shadow-sm">
<div className="flex mt-4">
<p className="flex items-center justify-center rounded-[99px] w-[30px] h-[30px] bg-[#ef386a] text-white">
<span className="text-sm">1</span>
</p>
<p className="mt-1 ml-2">
Please write description of your wallpaper
</p>
</div>
<div className="w-full text-left ml-[38px]">
<textarea
className="w-5/6 h-[200px] mt-2 text-sm rounded-md border border-gray-300 shadow-sm p-2 focus:ring-black"
placeholder="1000 characters max"
maxLength={1000}
/>
</div>
<div className="mt-6 flex space-x-4 justify-center w-full">
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
>
Suggest wallpaper
</button>
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
>
Generate wallpaper
</button>
</div>
</div>
</main>
</div>
)
}
export default Home;

We have created another div inside the main tag. This div further contains sibling divs where we have created a text box and two buttons.

STEP 4: State Management and Refs

We need to create two state variables to store the user-provided image description and the wallpaper URL we will receive from the API.

I will also create two refs for our two buttons. There are two reasons why I did this.

  1. To avoid unnecessary API calls if the user clicks on a button multiple times.
  2. To improve the UX of the application by showing a loading state.
tsx
import React, { useState, useRef } from "react";
import type { NextPage } from "next";
import Head from "next/head";
const Home: NextPage = () => {
const [description, setDescription] = useState<string>("");
const [wallpaper, setWallpaper] = useState<string | null>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const suggestButtonRef = useRef<HTMLButtonElement>(null);
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>WallAI</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex w-full flex-1 flex-col items-center justify-center md:px-20 text-center my-16">
<h1 className="text-7xl font-bold font-sans text-[#0055d9]">WallAI</h1>
<p className="mt-8 text-2xl md:w-2/5 text-[#081477] font-bold">
Create unique and stunning wallpapers using API
</p>
<div className="mt-12 flex max-w-xl flex-col flex-wrap sm:w-full border border-gray-300 p-6 rounded-md shadow-sm">
<div className="flex mt-4">
<p className="flex items-center justify-center rounded-[99px] w-[30px] h-[30px] bg-[#ef386a] text-white">
<span className="text-sm">1</span>
</p>
<p className="mt-1 ml-2">
Please write description of your wallpaper
</p>
</div>
<div className="w-full text-left ml-[38px]">
<textarea
className="w-5/6 h-[200px] mt-2 text-sm rounded-md border border-gray-300 shadow-sm p-2 focus:ring-black"
placeholder="1000 characters max"
maxLength={1000}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>
<div className="mt-6 flex space-x-4 justify-center w-full">
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
ref={suggestButtonRef}
>
Suggest wallpaper
</button>
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
ref={buttonRef}
>
Generate wallpaper
</button>
</div>
</div>
</main>
</div>
)
}
export default Home;

STEP 5: Installing Axios

Let’s create a .env.local file in the root directory. This file will contain API keys from RapidAPI Hub and OpenAI.

RAPIDAPI_KEY=YOUR-RAPIDAPI-KEY OPENAI_API_KEY=YOUR-API-KEY

Now let’s install axios since we will be using it to request the API. For this, open your project terminal and run the following command:

sh
npm i axios

Now you just need to import axios at the top of index.tsx.

STEP 6: Integrating Thefluentme API

We will use the "Generate Post" endpoint of Thefluentme API.

Loading component...

Please create a list.ts file inside pages/api directory. It will create a serverless REST endpoint for us. The endpoint will look like this:

http://localhost:3000/api/list

We will use this endpoint to generate a list of 30 words that describes a wallpaper. Please go ahead and copy the following code in this file:

ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
const options = {
method: "POST",
url: "https://thefluentme.p.rapidapi.com/generate-post",
headers: {
"content-type": "application/json",
"X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
"X-RapidAPI-Host": "thefluentme.p.rapidapi.com",
},
data: '{"post_title":"Suggest a list with 30 items that contains any word that describes a wallpaper","ai_model":"advanced_01","post_min_length":"199","post_max_length":"500"}',
};
try {
const response = await axios.request(options);
const suggestions: string[] = [];
response.data.ai_post.split(" ").map((word: string) => {
if (!word.match(/[\d.]+/)) {
suggestions.push(word);
}
});
res.status(200).json( suggestions);
} catch (err) {
res.status(500).json({ error: err });
console.log(err);
}
}
}

If you carefully take a look, right after I received the API response, I have filtered the result via regex. When it is done, I have sent the suggestions array as a response to the API request.

STEP 7: Integrating the DALL•E API

Let’s use the OpenAI API and integrate it into our AI wallpaper generator app. If you want to ensure the API is working correctly, you can test it right inside VS Code using RapidAPI Client.

Loading component...

Create a generate.ts file inside pages/api directory. This will again create a serverless endpoint for us.

http://localhost:3000/api/generate

Now copy the following code in this file:

ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
const { description } = req.body;
const options = {
prompt: `Generate a wallpaper like ${description}`,
n: 1,
size: "1024x1024",
};
const config = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
};
try {
const response = await axios.post(
"https://api.openai.com/v1/images/generations",
options,
config
);
res.status(200).json(response.data);
} catch (err) {
res.status(500).json({ error: err });
console.log(err);
}
}
}

This code makes an API call to the DALL•E API and returns the results to the user. It executes when the user makes an API call to the generate endpoint I mentioned above.

Let’s call this endpoint in our index.tsx file. For this, please go ahead and copy the following code there:

tsx
import React, { useState, useRef } from "react";
import type { NextPage } from "next";
import Head from "next/head";
import Image from "next/image";
import axios from "axios";
type IProps = {
data: string[];
}
const Home: NextPage<IProps> = ({ data }) => {
const [description, setDescription] = useState<string>(
data[0]
);
const buttonRef = useRef<HTMLButtonElement>(null);
const suggestButtonRef = useRef<HTMLButtonElement>(null);
const [wallpaper, setWallpaper] = useState<string | null>(null);
/**
* Generate Wallpaper
*
*
*/
const generateWallpaper = async () => {
buttonRef.current!.disabled = true;
setWallpaper(null);
try {
buttonRef.current!.innerText = "Generating wallpaper...";
const response = await axios.post("/api/generate", {
description,
});
setWallpaper(response.data.data[0].url);
} catch (err) {
console.log(err);
setWallpaper(null);
} finally {
buttonRef.current!.innerText = "Generate wallpaper";
buttonRef.current!.disabled = false;
}
};
/**
* Generate suggested wallpaper
*
*
*/
const suggestWallpaper = async () => {
buttonRef.current!.disabled = true;
suggestButtonRef.current!.disabled = true;
setWallpaper(null);
// Get random word from data
const index = Math.floor(Math.random() * data.length);
const word = data[index];
data.slice(index, 1);
setDescription(word);
try {
suggestButtonRef.current!.innerText = "Suggesting wallpaper...";
const response = await axios.post("/api/generate", {
description: word,
});
setWallpaper(response.data.data[0].url);
} catch (err) {
console.log(err);
setWallpaper(null);
} finally {
suggestButtonRef.current!.innerText = "Suggest wallpaper";
buttonRef.current!.disabled = false;
suggestButtonRef.current!.disabled = false;
}
}
return (
<div className="flex min-h-screen flex-col items-center justify-center py-2">
<Head>
<title>WallAI</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex w-full flex-1 flex-col items-center justify-center md:px-20 text-center my-16">
<h1 className="text-7xl font-bold font-sans text-[#0055d9]">WallAI</h1>
<p className="mt-8 text-2xl md:w-2/5 text-[#081477] font-bold">
Create unique and stunning wallpapers using API
</p>
<div className="mt-12 flex max-w-xl flex-col flex-wrap sm:w-full border border-gray-300 p-6 rounded-md shadow-sm">
<div className="flex mt-4">
<p className="flex items-center justify-center rounded-[99px] w-[30px] h-[30px] bg-[#ef386a] text-white">
<span className="text-sm">1</span>
</p>
<p className="mt-1 ml-2">
Please write description of your wallpaper
</p>
</div>
<div className="w-full text-left ml-[38px]">
<textarea
className="w-5/6 h-[200px] mt-2 text-sm rounded-md border border-gray-300 shadow-sm p-2 focus:ring-black"
placeholder="1000 characters max"
maxLength={1000}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>
<div className="mt-6 flex space-x-4 justify-center w-full">
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
onClick={suggestWallpaper}
ref={suggestButtonRef}
>
Suggest wallpaper
</button>
<button
className="w-full py-2 md:text-sm bg-[#081477] rounded-md text-white"
onClick={generateWallpaper}
ref={buttonRef}
>
Generate wallpaper
</button>
</div>
</div>
{wallpaper && (
<div className="mt-12">
<h2 className="mb-12 font-bold">Here is your wallpaper ↓</h2>
<a href={wallpaper!} title="wallpaper" download={true}>
<Image
src={wallpaper!}
width={512}
height={512}
alt="wallpaper"
className="rounded-lg"
/>
</a>
</div>
)}
</main>
<div className="flex flex-col mt-10 justify-center">
<p className="block mt-10 mb-10 text-center text-secondary text-xs uppercase font-bold">
Made by{" "}
<a href="https://rapidapi.com/?utm_source=github.com/RapidAPI&utm_medium=DevRel&utm_campaign=DevRel" className="underline">
Rapid
</a>{" "}
DevRel Team • Powered by <a href="https://openai.com/" className="underline">OpenAI</a> and <a href="https://rapidapi.com/hub?utm_source=RapidAPI.com/examples&utm_medium=DevRel&utm_campaign=DevRel" className="underline">Rapid</a>
</p>
</div>
</div>
);
};
export default Home;
export async function getServerSideProps() {
const res = await axios.post("/api/list");
const { data } = res;
if (!data) {
return {
notFound: true,
};
}
return {
props: {
data,
},
};
}

Let’s look at the code. I have used server-side rendering to request the list endpoint we created in step 6. This endpoint will provide a suggestion array that we can use to generate different wallpapers.

I have created a generateWallpaper function that executes when the user clicks on the Generate Wallpaper button. This function makes an API call to the /generate endpoint and then sets the wallpaper URL in the state variable.

I have also coded a suggestWallpaper function that is similar to generateWallpaper but instead of using the user prompt, it takes a random word out of our suggestion array and uses it to generate a wallpaper.

Lastly, I have conditionally rendered a Next.js image component, so we can display the wallpaper as soon as the API call to the /generate endpoint is successful.

After a successful API call, a wallpaper will be generated like this:

Wrap up

That’s all, folks! We have successfully created an AI wallpaper generator app using Thefluentme API from RapidAI Hub, RapidAPI Client, and OpenAI. We have deployed the app and you can look at the live preview here. You can find the source code of this app here.

Loading component...

If you want to read more about RapidAPI Client, we have written several articles on effectively using this API testing VS Code extension. You can find all these articles here. I recommend starting with a deep introduction to RapidAPI Client.