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 and mint the unique NFT in Polygon so you can see it on OpenSea. Pretty cool right ?
The source code is available on this Github repo.
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 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.
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)
// entities/nft.entity.ts
[...]
@Prop({
type: PropType.Text,
})
owner: string;
@Prop({
type: PropType.Link,
options: {
isHiddenInCreateEdit: true,
},
})
image: string;
And one more thing, we can add a function below the @BeforeInsert() decorator to hook our custom logic right before the moment where the entity gets stored in the database:
@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 to generate an image based on our prompt: the name field of the NFT entity.
We are going to use axios 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 and store it in the .env
file at your project root as OPENAI_API_KEY
// 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:
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 !
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.
We will use Pinata 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 to upload it to IPFS.
// 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:
// entities/nft.entity.ts
[...]
@BeforeInsert()
async mintNFT() {
console.log("Before Insert...");
const generatedImage: string = await generateAiArt(this.name);
this.image = await pin(generatedImage);
}
Conclusion
That's it for the first part ! Then we will use Hardhat 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 ! ❤️❤️❤️
And if you thought that CASE is pretty cool to build your CRUD apps (it really is), ⭐ star us on Github to follow the project. The product has so much room to improve, we are really looking to create a great community around it. 🫶
Top comments (1)
Hi Bruno !
Thanks for your very detailed tutorial and for the pretty cool idea of this NFT generator ! 🔥