How to Build an AI NFT Generator with DALL-E (OpenAI)

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:

  1. Connect their wallet (Supporting 350+ wallets)
  2. Enter a prompt to generate an AI image using DALL-E
  3. 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.

NFT Collection - ERC721 | Published Smart Contract
Create collection of unique NFTs.. Deploy NFT Collection in one click with thirdweb.
  1. Go to the thirdweb dashboard and under the "Contracts" tab, click "Deploy New Contract".
  2. Choose the "NFT Collection" contract type.
  3. Configure the contract settings like name, symbol, etc. Choose the network to deploy to.
  4. Click "Deploy Now" and approve the transaction in your wallet to deploy the contract.
  5. 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.

youtube-ai-nft-generator/utils/contract.ts at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
  1. Create an utils folder with a contract.ts file within
  2. 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.

youtube-ai-nft-generator/src/app/page.tsx at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
<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.

youtube-ai-nft-generator/components/AIGenerate.tsx at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
  1. 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>
    )
  }
};
  1. 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);
  1. 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>
  1. 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

youtube-ai-nft-generator/src/app/api/generate/route.ts at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
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.

youtube-ai-nft-generator/src/app/api/mint/route.ts at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
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.

youtube-ai-nft-generator/components/AIGenerate.tsx at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
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.

  1. Get the minted NFTs metadata from the contract
const { data: nfts, refetch: refetchNFTs } = useReadContract(
    getNFTs,
    {
        contract: contract,
    }
);
  1. Map through the array of NFTs returned and display the image of the NFT using MediaRenderer component
youtube-ai-nft-generator/components/NFTCollection.tsx at main · thirdweb-example/youtube-ai-nft-generator
Contribute to thirdweb-example/youtube-ai-nft-generator development by creating an account on GitHub.
'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! 🚀