How to Build an AI NFT Generator with DALL-E (OpenAI)
In this tutorial, we'll walk through building an AI NFT generator using OpenAI's DALL-E API and thirdweb's engine. Users will be able to:
- Connect their wallet (Supporting 350+ wallets)
- Enter a prompt to generate an AI image using DALL-E
- Mint the generated image as an NFT and send it to their wallet
Check out the full video tutorial:
Step 1: Deploy the NFT Smart Contract
First, let's deploy an NFT collection smart contract that we'll mint our AI-generated NFTs to.
- Go to the thirdweb dashboard and under the "Contracts" tab, click "Deploy New Contract".
- Choose the "NFT Collection" contract type.
- Configure the contract settings like name, symbol, etc. Choose the network to deploy to.
- Click "Deploy Now" and approve the transaction in your wallet to deploy the contract.
- Once deployed, click "Permissions" and grant the wallet address of your thirdweb engine backend permission to mint NFTs.
Remember to save the contract address, we'll need it later.
Step 2: Set up the Next.js Project
Let's set up a new Next.js project for our AI NFT generator frontend:
npx thirdweb create app
Once your project is created, open it in your code editor and head over to the .env.example
file to add you thirdweb client ID.
Rename .env.example
to .env.local
Step 3: Get Contract
Next, let's get our NFT collection smart contract prepared to interact with in our app.
- Create an
utils
folder with acontract.ts
file within - Using
getContract
create a wrapper for our smart contract to easily interact with it using Connect SDK.
import { chain } from "@/app/chain";
import { client } from "@/app/client";
import { getContract } from "thirdweb";
export const nftCollectionContractAddress = "<contract_address>";
export const contract = getContract({
client: client,
chain: chain,
address: nftCollectionContractAddress,
});
Step 3: ConnectEmbed UI Component
Create a login page to require that a user connects a wallet before being able to generate an AI NFT.
<div>
<h1>AI NFT Generator</h1>
<ConnectEmbed
client={client}
/>
</div>
Step 4: AI NFT Generator Component
Let's create our main component where users can enter a prompt to generate an AI image which will then be minted as an NFT.
- Show a
ConnetButton
is a connected state when a user's wallet is connected to the app
export const AIGenerate = () => {
const account = useActiveAccount();
if(account) {
return (
<div>
<ConnectButton
client={client}
chain={chain}
/>
</div>
)
}
};
- Create state variables for
imagePrompt
,generatedImage
,isGenerating
,isMinting
const [imagePrompt, setImagePrompt] = useState("");
const [generatedImage, setGeneratedImage] = useState("");
const [isGenerating, setIsGenerating] = useState(false);
const [isMinting, setIsMinting] = useState(false);
- Show the AI generated image or a placeholder until an image is generated
<div style={{ margin: "20px 0"}}>
{generatedImage ? (
<MediaRenderer
client={client}
src={generatedImage}
/>
) : (
<div>
<p>
{isGenerating
? "Generating image..."
: "No image generated"}
</p>
</div>
)}
</div>
- Create a input where a user can enter prompt to generate image and buttons to mint and reset the input.
<div>
<form onSubmit={handleGenerateAndMint}>
{!generatedImage || isMinting ? (
<div>
<input
type="text"
placeholder="Enter image prompt..."
value={imagePrompt}
onChange={(e) => setImagePrompt(e.target.value)}
/>
<button
type="submit"
disabled={!imagePrompt || isGenerating || isMinting}
>{
isGenerating
? "Generating..."
: isMinting
? "Minting..."
: "Generate and Mint"}
</button>
</div>
) : (
<button onClick={() => setGeneratedImage("")}>
Generate Another NFT
</button>
)}
</form>
</div>
Step 5: OpenAI DALL-E Image Generation
Create request to OpenAI to generate image with user's prompt. Create api
/generateImage
/route.ts
import { NextRequest } from 'next/server';
import { OpenAI } from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export async function POST(req: NextRequest) {
const { imagePrompt } = await req.json();
if (!imagePrompt) {
return new Response(JSON.stringify({
error: "Missing required fields"
}), {
status: 400,
headers: {
'Content-Type': 'application/json',
},
});
}
const prompt = `${imagePrompt}`;
try {
const response = await openai.images.generate({
model: "dall-e-3",
prompt: prompt,
n: 1,
size: "1024x1024"
});
if (!response.data) {
throw new Error("Failed to generate image");
}
return new Response(JSON.stringify({ data: response.data}), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
} catch (error) {
console.error(error);
return new Response(JSON.stringify({
error: "Failed to generate image due to internal server error"
}), {
status: 500,
headers: {
'Content-Type': 'application/json',
},
});
}
};
Step 6: Mint the NFT with thirdweb Engine
Once the image is generated we'll upload the image to IPFS and then use that URI as the metadata of the NFT, which will then be minted using Engine and a backend wallet to the user's wallet.
import { NextRequest, NextResponse } from "next/server";
import { nftCollectionContractAddress } from "../../../../utils/contract";
const {
ENGINE_URL,
THIRDWEB_SECRET_KEY,
BACKEND_WALLET_ADDRESS,
CHAIN_ID,
} = process.env;
export async function POST(req: NextRequest) {
if(
!ENGINE_URL ||
!THIRDWEB_SECRET_KEY ||
!BACKEND_WALLET_ADDRESS ||
!CHAIN_ID
) {
return new NextResponse(
JSON.stringify({
error: "Missing required environment variables"
}),
{ status: 500 }
);
}
const { nftImage, address } = await req.json();
try {
const mintResponse = await fetch( `${ENGINE_URL}/contract/${CHAIN_ID}/${nftCollectionContractAddress}/erc721/mint-to`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${THIRDWEB_SECRET_KEY}`,
"x-backend-wallet-address": BACKEND_WALLET_ADDRESS,
},
body: JSON.stringify({
receiver: address,
metadata: {
name: "AI NFT",
description: `"AI generated NFT"`,
image: nftImage,
}
})
}
);
if (!mintResponse.ok) {
const error = await mintResponse.text();
throw new Error(`Failed to mint NFT: ${error}`);
}
return new NextResponse(JSON.stringify({ message: "NFT minted successfully" }), { status: 200 });
} catch (error) {
console.error('Minting error:', error);
return new NextResponse(
JSON.stringify({ error: "Failed to mint NFT" }),
{ status: 500 }
);
}
};
Step 7: Create Button to Generate and Mint NFT
Now we can create a button to take the user's prompt to generate, upload, and mint the NFT to the user's wallet.
const handleGenerateAndMint = async (
e: React.FormEvent<HTMLFormElement>
) => {
e.preventDefault();
setIsGenerating(true);
try {
const res = await fetch("/api/generateImage", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
imagePrompt
}),
});
if(!res.ok) {
throw new Error("Failed to generate image");
}
const data = await res.json();
setImagePrompt("");
const imageBlob = await fetch(data.data[0].url).then((res) => res.blob());
const file = new File([imageBlob], "image.png", { type: "image/png" });
const imageUri = await upload({
client: client,
files: [file],
});
if (!imageUri) {
throw new Error("Error uploading image to IPFS");
}
setGeneratedImage(imageUri);
setIsGenerating(false);
setIsMinting(true);
const mintRes = await fetch("/api/mint", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
nftImage: imageUri,
address: account?.address || "",
}),
});
if(!mintRes.ok) {
throw new Error("Failed to mint NFT");
}
alert("NFT minted successfully");
} catch (error) {
console.error(error);
} finally {
setIsMinting(false);
}
};
Step 6: Display AI Generated NFTs
Create a component to display the NFTs of the NFT Collection smart contract.
- Get the minted NFTs metadata from the contract
const { data: nfts, refetch: refetchNFTs } = useReadContract(
getNFTs,
{
contract: contract,
}
);
- Map through the array of NFTs returned and display the image of the NFT using
MediaRenderer
component
'use client';
import { client } from "@/app/client";
import { NFT } from "thirdweb";
import { MediaRenderer } from "thirdweb/react";
type NFTCollectionProps = {
nfts: NFT[];
};
export const NFTCollection = ({ nfts }: NFTCollectionProps) => {
return (
<div>
<h3>AI Generations:</h3>
<div>
{nfts.map((nft) => (
<div>
<MediaRenderer
client={client}
src={nft.metadata.image}
/>
</div>
))}
</div>
</div>
)
};
Conclusion
Congratulations, you've built a full stack AI NFT generator dapp using thirdweb and OpenAI! In this guide, we covered how to:
- Deploy an ERC721 NFT Collection contract using thirdweb
- Generate an AI image using OpenAI DALL-E
- Upload that image to IPFS and mint an NFT using Engine
Feel free to explore the final source code, make modifications, and adapt it for your own projects. If you have any questions or feedback, don't hesitate to reach out.
Happy building! 🚀