BLOG — Developer Tutorials

543 days ago

Power Your dApp with ChatGPT

The combination of AI and web3 has the potential to address existing challenges in the field of AI while also unlocking numerous innovative opportunities in web3. By bringing AI onto the blockchain, smart contracts gain the ability to make autonomous decisions and predictions based on dynamic on-chain data, leading to the emergence of various new functionalities, all without the need for human inputs. AI can play a significant role in driving the adoption of decentralized networks, with AI agents potentially utilizing crypto infrastructure for payments and accessing digital resources like storage, compute, and bandwidth.

Take for instance, an AI programmed to write code for companies. This AI, working 24/7, can be employed through blockchain-based smart contracts, and it gets paid automatically for each pull request it successfully merges. It's not only a real-world example but an indicator of a new era in software development, demonstrating the exciting possibilities that can unfold at the intersection of AI and blockchain.

This powerful union is sending ripples across various sectors. In DeFi, machine learning is being used for predictive analysis, dynamic parameter adjustments, and transaction history analytics. In gaming, it's enhancing user experiences by creating real-time game content and adaptive characters. In social media, AI is transforming the landscape through automated posting and personalized content filtering. These are just the tip of the iceberg when it comes to the possibilities unveiled by the convergence of AI and web3.

In this tutorial, we will explore how Gelato’s Web3 Functions enable smart contracts to leverage the power of AI by connecting them to OpenAI ChatGPT API to generate creative content based on a given prompt. Gelato’s Web3 Functions equip smart contracts with the ability to seamlessly interact with any type of off-chain data. In our application Gelato’s Web3 Functions help us to connect the off-chain Open AI API to generate creative content and automate it to schedule every 8 hours.

AI-enabled Content Posting

Let's dive into the workflow of our application, which begins with the LensGelatoGPT smart contract. This contract handles the management of prompts for automated content creation using AI. It communicates with the Lens Protocol master contract, the LensHub.sol, to make sure all actions are performed by the rightful profile owners and to keep track of the prompts for each profile.

LensHub.sol serves as the heart of the system, interfacing with all interactions within the Lens Protocol.

Gelato’s Web3 Functions code then invokes the OpenAI API to generate creative content, guided by the prompts obtained from the LensGPT Smart Contract. Following this, the Lens Publication Metadata is obtained and validated using the LensClient. Once validated, the content is encapsulated in the metadata, and uploaded to IPFS using the Web3Storage API.

Finally the postData object is created which is then encoded into the call data for the LensHub contract's "post" function & then published on the Lens Protocol.

The culmination of this entire process is the appearance of your content on Lenster, a social media web application built using Lens Protocol. This intricate off-chain process, from content creation to its publication, is seamlessly executed, thanks to Gelato’s Web3 Functions!

Prerequisites

Ensure you have the following before you start:

  • Signed up for the Gelato Web3 Functions beta.
  • Installed Node.js v16+, NPM, and Git.
  • Set up a Web3 wallet in your browser, such as MetaMask.
  • Account created on Alchemy, Web3 storage & Open AI

Once set up, we can dive in!

Your Dev Environment

Start by cloning the Gelato Web3 Functions lensgpt Repository: git clone https://github.com/gelatodigital/lensgpt-tutorial.git

Install the dependencies:

yarn install

Code Structure

The code structure should look like this:

Configure Secrets

Alchemy ID Private Key An OpenAI Key A Web3.Storage Key

Obtain Alchemy ID & Private Key: Locate the .env.template file in your root folder, copy it and rename the copy to .env. These keys are only required if deploying your smart contract to testnet/mainnet.

Here are the steps for acquiring these:

Acquiring an Alchemy ID

Sign Up for a free Alchemy Account Creating an account with Alchemy is simple, sign up for free.

Create an Alchemy App You need an API key to authenticate your requests. You can create API keys from the dashboard. Navigate to “Create App” and fill in the details to get your new key and paste it in .env..

Acquiring a Private Key

  • Go to your Metamask wallet and do the following:
  • Click on the three dots next to ‘Account Address’
  • Then click on ‘Account Details’
  • Export the private key
  • Enter your Metamask wallet password
  • Copy the private key & paste it in .env

Obtain OpenAI and Web3.Storage Keys Find the .env.template file in the web3-functions/lens-ai directory. Again, make a copy of it and rename the copy to .env and put the API keys.

Sign in on the Web3 Storage website using either your GitHub or email, navigate to your account section and generate a new API Token.

For the OpenAI API Key, visit the OpenAI website, create a new secret key by filling out the provided form, and note down the secret key shown. Once obtained, these keys need to be entered into the newly created .env file.

Now you're all set to get started!

Code Explanation

The LensGelatoGPT smart contract plays a crucial role in managing prompts for automated content creation with AI, interacting seamlessly with the LensHub contract.

One of the vital functions is communicating with LensHub to verify profile ownership when prompts are set or removed. It ensures that only rightful owners can set the prompts acting as stimuli for AI-generated content.

In the LensGelatoGPT contract, the LensHub's getDispatcher function is utilized within the setPrompt function. This is to ascertain that the dispatcher for a profile is set to the dedicated msg.sender proxy contract. This confirms that only authorized entities can set prompts for AI-generated content on the profiles.

The dedicated msg.sender proxy contract, a unique feature of Web3 functions, acts as a transaction middleware, routing them to the designated destination contract.

Now, let's take a look at the main functions of the LensGelatoGPT contract:

LensGelatoGPT contract

  • setPrompt: This function allows a profile owner to set a prompt for their profile. The prompt acts as the input for the AI content generator. It validates the ownership using the LensHub contract and ensures the fee for the transaction is correct.
	    function setPrompt(
        uint256 _profileId,
        string calldata _prompt
    ) external payable onlyProfileOwner(_profileId) {
        require(msg.value == fee, "LensGelatoGPT.setPrompt: fee");
        require(
            bytes(_prompt).length <= 160,
            "LensGelatoGPT.setPrompt: length"
        );
        require(
            lensHub.getDispatcher(_profileId) == dedicatedMsgSender,
            "LensGelatoGPT.setPrompt: dispatcher"
        );
        _profileIds.add(_profileId);

        promptByProfileId[_profileId] = _prompt;
    }
  • stopPrompt: This function allows a profile owner to remove a prompt from their profile, effectively stopping AI content generation. Ownership is again verified through LensHub.
 function stopPrompt(
       uint256 _profileId
   ) external onlyProfileOwner(_profileId) {
       require(
           _profileIds.contains(_profileId),
           "LensGelatoGPT.stopPrompt: 404"
       );
       _profileIds.remove(_profileId);
       delete promptByProfileId[_profileId];  }
  • getPaginatedPrompts: This function is used to fetch a paginated list of prompts. It returns an array of Prompt structs, which includes the profile ID and the associated prompt.

-collectFee: This function enables the collection of fees accrued from setting prompts. It can only be executed by the contract's ProxyAdmin.

function collectFee(address payable _to) external onlyProxyAdmin {
        _to.sendValue(address(this).balance);
    }
 

LensGelatoGPT Web3 Function

This fetches prompts from a smart contract, uses OpenAI to generate text based on these prompts, uploads the generated content to IPFS, and then posts the content to Lens.

Let's break down the key parts of the index.ts file and examine their role in the overall workflow:

Importing necessary libraries and contract ABIs

These import statements include various utilities necessary for the function to work correctly. Web3Function and Web3FunctionContext are required to define and interact with the function. Contract and utils from the ethers library are used for interacting with Ethereum smart contracts and general utilities (like address validation). OpenAI API is used to generate content. The lensHubAbi file contains the application binary interface (ABI) of the LensHub contract, which defines how to interact with it.

import { Web3Function, Web3FunctionContext } from "@gelatonetwork/web3-functions-sdk";
import { Contract, utils } from "ethers";
import { Configuration, OpenAIApi } from "openai";
import { v4 as uuidv4 } from "uuid";
import { Web3Storage, File, CIDString } from "web3.storage";
import { lensHubAbi } from "../../../helpers/lensHubAbi";
Validate user arguments and secrets

In this section, the function fetches the secrets (API keys) and user arguments (contract addresses) required to execute the function. If any of these are invalid or missing, the function will return an error.

Check this to learn more about userArgs and secrets.


const WEB3_STORAGE_API_KEY = await secrets.get("WEB3_STORAGE_API_KEY");
const OPEN_AI_API_KEY = await secrets.get("OPEN_AI_API_KEY");
const lensGelatoGPTAddress = userArgs.lensGelatoGPT as string;
const lensHubAddress = userArgs.lensHubAddress as string;
                        const collectModuleAddress = userArgs.collectModule as string;
Fetching prompts from the LensGelatoGPT contract

The function fetches a set of prompts from the LensGelatoGPT contract using the getPaginatedPrompts function. The function returns a specified range of prompts.

prompts.push(
  ...(await lensGelatoGpt.getPaginatedPrompts(
    nextPromptIndex,
    nextPromptIndex + NUMBER_OF_POSTS_PER_RUN
  ))
);
Generate AI text and post it to LensHub

This script runs through a list of prompts, generates content based on each prompt using the OpenAI API.The code then generates metadata for the content and validates it using LensClient.The validated metadata is then stored on IPFS using Web3Storage. The code then creates a data structure called postData with all the necessary data, including profileId, contentURI (the URL of the content on IPFS), and other module-related data.Finally, it creates an interface instance using the lensHubAbi and pushes a new object to the callDatas array with the lensHubAddress and the encoded function data for posting the data.

for (const prompt of nonEmptyPrompts) {
    // ...
    const response = await openai.createCompletion({ /* ... */ });
    text = response.data.choices[0].text as string;
    // ...
    cid = await storage.put([myFile]);
    contentURI = `https://${cid}.ipfs.w3s.link/publication.json`;
    // ...
    callDatas.push({
      to: lensHubAddress,
      data: iface.encodeFunctionData("post", [postData]),
    });
}
Updating the execution state

This section updates the storage state after each execution. It keeps track of the start time of the last run, and the index of the next prompt. This is used to determine whether it's time to run the function again, and which prompts should be processed in the next run.

if (lastIntervalRunFinished) {
  await storage.set("lastRunStartTime", blockTime.toString());
}
if (isLastRun) {
  await storage.set("nextPromptIndex", "0");
} else {
  await storage.set(
    "nextPromptIndex",
    (nextPromptIndex + NUMBER_OF_POSTS_PER_RUN).toString()
  );}

In summation: the function fetches prompts from a smart contract, generates AI-written text based on these prompts, posts this text to LensHub, and updates its state for the next run.

Running Web3 Functions

The LensGelatoGPT Smart Contract

Deploying on Mumbai Network Run this command in root of the project directory: npx hardhat run deploy/LensGelatoGPT.deploy.ts --network mumbai

Copy the smart contract address above.

Deploying Web3 Functions code

In the userArgs.json file in the web3-functions/lensChatGPT folder, replace the lensGelatoGPT address with your deployed address

Then run this command to deploy the Web3 Functions (it is stored on IPFS), to compile your Web3 Function and deploy it to IPFS, use:

npx hardhat w3f-deploy W3FNAME

In our case:

npx hardhat w3f-deploy lensChatGPT

Once uploaded, Gelato Nodes will pin the file on your behalf on IPFS. If the upload was successful, you should get the IPFS CID of your Web3 Function returned.

✓ Web3Function deployed to ipfs. ✓ CID: QmRVJPL5MSyxRxJWoYGYBGEifBwrUA4pAfhAspwQ9j7mnb

To create a task that runs your Web3 Function every minute, visit:

https://beta.app.gelato.network/new-task?cid=QmRVJPL5MSyxRxJWoYGYBGEifBwrUA4pAfhAspwQ9j7mnb

Creating a Web3 Function Task via the UI

  1. Go to the Link: Click on the link you got when you set up your Web3 Function, the IPFS CID will already be there. This lets you look at the code of your Web3 Function.

  2. Enter user arguments: Type in the arguments you entered in userArgs.Json file: lensGelatoGPT, lensHubAddress, and collectModule

  3. Choose Your Network: Pick the network for your task to work on.

  4. Add Your Keys: Put in your Web3 storage and OpenAI API keys.

  5. Give Life to Your Task: Last but not least, you'll be asked to name your task. Hit the "Create Task" button, confirm the name and task creation with your wallet, et voila!

Monitoring Your Task Performance

You can keep an eye on how your task is doing from your Web3 Functions Task dashboard. It's got everything you need:

  • Executions: Check how many times your task has run on specific dates.

  • Task Logs: Look at logs Web3 Function's code has sent out.

  • Code, Storage, & Secrets: Review your code, storage details, and your secrets for additional insights.

With this dashboard, you'll have all the information about your task right at your fingertips.

Conclusion

In this comprehensive guide, we've explored how to leverage the power of AI and blockchain through the integration of OpenAI, Web3 Storage, Lens Protocol, and Gelato. This represents a significant step forward in harnessing the potential of AI and Web3.

As we continue to witness the convergence of AI and blockchain, it's exciting to imagine the possibilities this synergy holds for various sectors. We hope this tutorial has equipped you with the knowledge to explore these potentials further.

Happy coding, and welcome to the internet of tomorrow!

Dive Deeper with Gelato

Web3 Functions provide an innovative solution for developers to create serverless, decentralized applications with ease.

Join our community and developer discussion on Discord.

Web3 Functions are available today in private beta. For more information, please check out the Web3 Functions documentation. To learn how to write, test, and deploy your own Web3 Functions, check out our in-depth tutorial.

Apply here to be one of the first to test Gelato's Web3 Functions!