Build an AI-powered NFT generator with TS, GPT, Polygon and CASE (Part 1/2)
Published: 2023-09-07 15:00:53

---
title: Build an AI-powered NFT generator with TS, GPT, Polygon and CASE (Part 1/2)
published: true
description: Let's build an instant NFTs generator web app ! In one click generate an image with OpenAI, store it on IPFS and mint the NFT to see it on OpenSea !  

tags: 
# cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/df07njcp9axj60prr14c.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-09-07 12:15 +0000
---

Let's build an instant NFTs generator! ✨✨

We will create a web app that will let users mint a NFT in one click: creating an AI art from a prompt, storing it on [IPFS](https://ipfs.tech) and mint the unique NFT in [Polygon](https://polygon.technology) so you can see it on [OpenSea](https://opensea.io). Pretty cool right ? 

_The source code is available on this [Github repo](https://github.com/brunobuddy/ai-nft-generator)._

{% embed https://www.youtube.com/watch?v=jzvrvcvq4nk %}

## Steps summary

### Part 1
- A. Create a dashboard with a "create NFT" form
- B. Generate AI Art with OPEN AI Image generation
- C. Store it on IPFS

### Part 2
- A. Create NFT contract
- B. Deploy it to Polygon
- C. Mint an NFT on the flow with image and metadata

## Part 1


### A. Create a dashboard with a "create NFT" form

First let's generate our dashboard with [CASE](https://case.app) by running this command:

```
npx create-case-app my-nft-app
```

This will create a CASE CRUD app where you can add your NFT entity.

![CASE login page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ajo6z9v3u2mw66v7fwx.png)

Then from the root of the project run:
```
npm run case:entity nft
```
This command will create the `nft.entity.ts` file in the _entities_ folder. You should see in your browser that you have a new __NFT__ link in the sidebar. 

You can click on it and you will see that the NFT entity has already one "name" property: a simple text field. Let's add 2 more:
- The **owner** of the NFT that will receive the wallet address of the owner
- The **image** that will receive the url of the image on IPFS (hidden in the form as it will be automatically filled)

```ts
  // entities/nft.entity.ts
  [...]
  @Prop({
    type: PropType.Text,
  })
  owner: string;

  @Prop({
    type: PropType.Link,
    options: {
      isHiddenInCreateEdit: true,
    },
  })
  image: string;
```
![Create NFT form on CASE](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sycr46b2ha6mqyduagr2.png)

And one more thing, we can add a function below the [@BeforeInsert()](https://docs.case.app/custom-logic?id=beforeinsert) decorator to hook our custom logic right before the moment where the entity gets stored in the database:

```ts
@BeforeInsert()
async mintNFT() {
  console.log("Before Insert...");

  // Mint that NFT !
}
```


### B. Generate AI Art with OPEN AI Image generation

It is now the time to call the [OPEN AI Image generation API](https://platform.openai.com/docs/guides/images/image-generation-beta) to generate an image based on our prompt: the name field of the NFT entity.

We are going to use [axios](https://axios-http.com) to make the HTTP requests. Let's install it:
```
npm i axios
```

Then you can create the file that will call the API to generate our AI art. Let's call it `generate-ai-art.ts` You will need to [generate your OpenAI API key](https://platform.openai.com/account/api-keys) and store it in the `.env` file at your project root as `OPENAI_API_KEY` 

```ts
// utils/generate-ai-art.ts
import axios from "axios";

export const generateAiArt = async (prompt: string): Promise<string> => {
  const response = await axios.post(
    "https://api.openai.com/v1/images/generations",
    {
      // We pass the prompt as the prompt argument.
      prompt,
      // Smallest size available, let's limit our footprint.
      size: "256x256",
    },
    {
      headers: {
        // Get your own key and at it to the .env file
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
    }
  );

  // Get the image URL from the API response.
  return response.data.data[0].url;
};
```

Back to our `nft.entity.ts` file, we can import the function and trigger it:

```ts
import { generateAiArt } from "../utils/generate-ai-art";
[...]

@BeforeInsert()
async mintNFT() {
  console.log("Before Insert...");

  // "This" refers to the NFT entity we are creating.
  this.image = generateAiArt(this.name);
}
```
If you go back to your CASE dashboard and create a new NFT, you will see that the submission loads a bit and once done, the image field is field with a link to the AI generated image like my "red bear". Cheers !


![AI generated image with OpenAi for "red bear"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/prexjgax37ok6ows9f2k.png)


### C. Store it on IPFS

IPFS is a great way for storing NFT related data: it is decentralized and resilient. If your NFT image url points out to your server, it looses some of its value as you can change it whenever you want.


![Pinata homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08ykizhmrx8qm4uwided.png)



We will use [Pinata](https://www.pinata.cloud/) as a gateway for IPFS. Once again you will need to create an accout to get your secret token for API authentication.
```
npm i @pinata/sdk
```
We are going to create a new file called `pin-to-IPFS.ts` to hold the script.

I recommend to create a `storage` folder in order to store your temporary files. Indeed we are downloading the file first and the we will pin it to IPFS.

In this script, we are using a basic download function to get the image from the OpenAI servers and the we use the [Pinata SDK](https://www.npmjs.com/package/@pinata/sdk) to upload it to IPFS.

```ts
// utils/pin-to-IPFS.ts
const axios = require("axios");
const fs = require("fs");
const pinataSDK = require("@pinata/sdk");

export const pin = async (url: string): Promise<string> => {
  const imagePath: string = await downloadFile(url, "storage/file.png");

  // Init the SDK.
  const pinata = new pinataSDK({ pinataJWTKey: process.env.PINATA_JWT });

  // Read the downloaded file.
  const stream = fs.createReadStream(imagePath);

  // Push it to the IPFS network.
  const pinataRes = await pinata.pinFileToIPFS(stream, {
    pinataMetadata: {
      name: "NFT art",
    },
  });

  // Delete local file.
  fs.unlinkSync(imagePath);

  // We return a link with the hash.
  return "ipfs://" + pinataRes.IpfsHash;
};

// Simple download file function.
const downloadFile = async (url: string, path: string): Promise<string> => {
  const res = await axios.get(url, { responseType: "stream" });

  return new Promise((resolve, reject) => {
    res.data
      .pipe(fs.createWriteStream(path))
      .on("error", reject)
      .once("close", () => resolve(path));
  });
};
```

And now we just need to connect the dots too have the full experience:
```ts
// entities/nft.entity.ts
  [...]
  @BeforeInsert()
  async mintNFT() {
    console.log("Before Insert...");

    const generatedImage: string = await generateAiArt(this.name);
    this.image = await pin(generatedImage);
  }
```

![CASE detail page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rdz2he2pb63u6vpq36f.png)


## Conclusion

That's it for the first part ! Then we will use [Hardhat](https://hardhat.org/) to **deploy our Solidity Contract on the Polygon testnet**, and then overload our `mintNFT()` function with the actual minting. If you want to see the Part 2 quickly, give us some love and we will execute ! ❤️❤️❤️

![CASE dashboards](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ey3atbhuijh6kw84q3ob.png)

And if you thought that [CASE](https://case.app) is pretty cool to build your CRUD apps (it really is), [⭐ star us on Github](https://github.com/casejs/case) to follow the project. The product has so much room to improve, we are really looking to create a great community around it. 🫶