How to Create ChatGPT Plugins - Unlock the Power of AI and Blockchain
Headshot
Jun 22, 2023
by Ed Marquez
Developer Relations Engineer

Goals

By reading this article, you will learn:

  • The benefits of using AI and blockchain together
  • What ChatGPT and Hedera are
  • How to create a ChatGPT plugin that interacts with Hedera
  • How to use the plugin to get HBAR and token balances for Hedera accounts

Tools You Will Use

Try it Yourself

Artificial Intelligence (AI) and Blockchain

AI and blockchain are two technological trends that have captured everyone’s attention – but what are these trends all about? AI is about autonomous systems that can learn, make decisions, and adapt. Blockchain is a secure and immutable way to record transactions or digital interactions. The learning aspect of AI, coupled with blockchain's immutable nature, introduces a revolutionary change in how data can be processed and utilized.

The intersection of AI and blockchain will most likely impact various sectors. For instance, in healthcare, AI can analyze securely stored patient records for personalized treatment, while blockchain ensures the integrity of the data. In finance, smart contracts combined with AI-driven decision-making can automate processes, from simple transactions to complex investments. In supply chain management, AI can optimize routes and reduce costs while blockchain provides data transparency, traceability, and immutability. These are a few examples of systems that will have the ability to not only solve increasingly complex problems but to adapt and improve continually as the AI interacts with and learns from securely stored data. This combination of technologies unlocks opportunities for smarter, more efficient solutions across countless industries.

Understanding ChatGPT and Hedera

ChatGPT needs no introduction, but here it is: It’s a conversational AI tool capable of understanding and responding to text inputs in a human-like manner. Plugins enhance its functionality even further. They act as add-ons, equipping ChatGPT with extra capabilities like specialized knowledge or specific task performance. This makes ChatGPT adaptable to a wide array of unique needs and applications. For example, a plugin could enable ChatGPT to convert currencies in real-time, integrate with a calendar system to manage appointments, or retrieve and process data from a blockchain. In this article, you will create a plugin that interacts with the Hedera network.

Hedera is a decentralized, open-source, proof-of-stake, EVM-compatible public ledger. For simplicity, you can call it a blockchain. Hedera uses a leaderless consensus algorithm, which gives the network the highest degree of security and performance mathematically possible. In addition, the network is governed by a collusion-resistant, decentralized council of leading enterprises, universities, and web3 projects from around the world. This council includes organizations like Google, Boeing, IBM, Ubisoft, Dell Technologies, London School of Economics and more.

The decentralized network offers services (with APIs) and tooling that facilitate development of web 3 components and applications. More specifically, the main services are:

  • Hedera Consensus Service (HCS): Verifiable timestamping and ordering of events for any software application
  • Hedera Token Service (HTS): Create, mint, and manage native fungible and non-fungible tokens (NFT) with or without smart contracts
  • Smart Contract Service: Build and deploy Solidity smart contracts. EVM-compatible

In terms of Hedera’s value and uniqueness, this cutting-edge technology and well-governed network enables you to meet and exceed technical requirements with your software implementations in the areas of performance, cost, security, reliability, and sustainability. The Hedera services enable you to create new use cases for your business or project that integrate with many of the development languages and frameworks you are already familiar with - whether you come from traditional web development or from the Web3 development world.

Now that you know about ChatGPT and Hedera, let’s start building! Here’s a preview of the end result:

1 SAMPLE RESULT

How to Create a ChatGPT Plugin: A Step-by-Step Guide

We want to enable ChatGPT to obtain the HBAR (ℏ) and token balances of a Hedera account. Now, what does that mean?

Accounts are the central starting point when interacting with the Hedera network and using its services. An account is an entity stored in the ledger that holds tokens. Accounts can hold the native network token (HBAR), fungible tokens, and NFTs created on Hedera. Account balances can be viewed on a Network Explorer and obtained programmatically using the mirror node REST API - the plugin will use this REST API. Keep in mind that the network returns HBAR information in tinybars (tℏ), where 100,000,000 tℏ are equivalent to 1 ℏ.

Let’s use Replit as the integrated development environment (IDE). Replit helps keep the setup simple as it is an online IDE and code collaboration tool. Log in and create a new Repl with a Python template as shown in the GIF below.

Description of the image

1. Making an API: Adding Your Own Functions for the Plugin

Add the Python code below in the main.py file. This code uses Flask and Waitress in Python to create and serve the API with your functionality. The central piece of the code that contains the custom functionality is the HederaPlugin class, which defines methods to interact with Hedera's mirror node REST API. The plugin is initialized with the base URL of the Hedera mainnet public mirror node.

The methods get_hbar_balance and get_token_balance in the HederaPlugin class fetch the balances of a specific Hedera account ID. These functions construct the URL for the REST API request, call the method query_mirror_node_for using that URL to obtain the relevant balance and token information from the Hedera mirror nodes, and then parse the JSON response. The functions return the balance data or None if the account or token can't be found.

Flask and Waitress are used for the server setup. Flask is a web framework for Python and it’s used to define four API routes. The /get_hbar_balance and /get_token_balance routes use the HederaPlugin class to retrieve HBAR and token balances. The /.well-known/ai-plugin.json and /openapi.yaml routes serve the AI plugin manifest and OpenAPI specification from the root directory of the application. Notice that the ./well-known is a requirement for the manifest mentioned in the OpenAI documentation.

Waitress is used to serve the Flask application. The server is set to run on host 0.0.0.0 and listens on port 5000. Using Serving the application with Waitress ensures that the plugin can handle user traffic.

Code Snippet Background
from waitress import serve
from flask import Flask, jsonify, request, send_from_directory
import requests


class HederaPlugin:

  # Define the constructor for the class
  def __init__(self, base_url):
    # Initialize the base_url attribute
    self.base_url = base_url

  # Define methods to get the account balance
  def get_hbar_balance(self, account_id):
    # Define the endpoint for the balance API
    endpoint = "/balances"

    # Construct the full URL for the API request
    url = f"{self.base_url}{endpoint}?account.id={account_id}"

    balance_info = self.query_mirror_node_for(url)

    if balance_info is not None:
      # Iterate over the 'balances' in the response data
      for item in balance_info.get('balances', []):

        # Check if the account ID matches the requested account
        if item['account'] == account_id:

          # Calculate the HBAR balance and return it
          hBalance = float(item['balance']) * 1E-8
          return hBalance

    # Return None if the account or was not found
    return None

  def get_token_balance(self, account_id, token_id):
    # Define the endpoint for the balance API
    endpoint = "/balances"

    # Construct the full URL for the API request
    url = f"{self.base_url}{endpoint}?account.id={account_id}"

    balance_info = self.query_mirror_node_for(url)

    if balance_info is not None:

      # Iterate over the 'balances' in the response data
      for item in balance_info.get('balances', []):

        # Check if the account ID matches the requested account
        if item['account'] == account_id:

          # Iterate over the 'tokens' in the item
          for token in item.get('tokens', []):

            # Check if the token ID matches the requested token
            if token['token_id'] == token_id:

              # Define the endpoint for the token info API
              endpoint2 = "/tokens"
              # Construct the full URL for the token info API request
              url2 = f"{self.base_url}{endpoint2}/{token_id}"

              tokenInfo = self.query_mirror_node_for(url2)

              if tokenInfo is not None:

                # Get the number of decimals for the token
                decimals = float(tokenInfo['decimals'])

                # Calculate the token balance and return it
                tBalance = float(token['balance']) / (10**decimals)

                return tBalance

      # Return None if the query is wrong or if the account or token was not found
      return None

  def query_mirror_node_for(self, url):
    # Make a GET request to the mirror node REST API
    info = requests.get(url)
    # Check if the response status code is 200 (OK)
    if info.status_code == 200:
      # Parse the token info JSON response data
      info_data = info.json()
      return info_data
    else:
      # Return None if mirror node query is wrong or unsuccessful
      return None


# Initialize the plugin with the mainnet base URL
plugin = HederaPlugin("https://mainnet-public.mirrornode.hedera.com/api/v1")

# Create the Flask web server
app = Flask(__name__)


@app.route('/get_hbar_balance', methods=['GET'])
def get_hbar_balance():
  # Use query parameter 'account_id' to specify the account ID
  account_id = request.args.get('account_id', '')
  hbar_balance = plugin.get_hbar_balance(account_id)
  if hbar_balance is not None:
    return jsonify({'account_id': account_id, 'hbar_balance': hbar_balance})
  else:
    return jsonify({
      'error':
      'Could not get the HBAR balance for this account. Some possible reasons: The account ID may be incorrect or the mirror query was unsuccessful.'
    }), 404


@app.route('/get_token_balance', methods=['GET'])
def get_token_balance():
  # Use query parameter 'account_id' to specify the account ID
  account_id = request.args.get('account_id', '')
  token_id = request.args.get('token_id', '')
  token_balance = plugin.get_token_balance(account_id, token_id)
  if token_balance is not None:
    return jsonify({'account_id': account_id, 'token_balance': token_balance})
  else:
    return jsonify({
      'error':
      'Could not get the token balance for this account. Some possible reasons: The account and token ID may not be associated, the entity IDs may be incorrect, or the mirror query was unsuccessful.'
    }), 404


@app.route("/.well-known/ai-plugin.json", methods=['GET'])
def serve_ai_plugin():
  return send_from_directory(app.root_path,
                             'ai-plugin.json',
                             mimetype='application/json')


@app.route("/openapi.yaml", methods=['GET'])
def serve_openapi_yaml():
  return send_from_directory(app.root_path,
                             'openapi.yaml',
                             mimetype='text/yaml')


if __name__ == "__main__":
  serve(app, host="0.0.0.0", port=5000)

Now run your Python application and note down the URL shown in the navigation bar of the Webview.

Description of the image

2. Documenting the API: Keeping Things Organized with OpenAPI yaml

Now it’s time to document and organize your custom functionality by adding the file openapi.yaml to your directory. The OpenAPI yaml file is a language-agnostic way to describe your API, including the various endpoints and the input and output for each operation. The yaml file follows the OpenAPI specification. This specification is extensive and highly detailed, so be sure to check the official OpenAPI documentation if you need more information.

For this file, the OpenAPI version is specified at the beginning. This is followed by an info section that provides general information about the API, including its title, description, and version. The servers section indicates the base URL for the API – this is the URL that was generated and noted after running main.py.

The paths section is where the real action happens. It details the available API endpoints and the operations they support. In this case, there are two paths: /get_hbar_balance and /get_token_balance. Both of these paths support a GET operation. An operationId is used for easy referencing (getHbarBalance and getTokenBalance). The getHbarBalance takes a single query parameter, account_id. Note that the getTokenBalance operation accepts two query parameters: account_id and token_id. For each parameter, the yaml file specifies where it's located (in), its name (name), its data type (schema), and a brief description (description). The responses section lists possible HTTP status codes and the schema of the response body. In this case, the response returns the Hedera account ID as a string and the corresponding balance as a number for both operations.

Code Snippet Background
openapi: 3.0.1
info:
  title: Hedera Account Balance
  description: Get the HBAR and token balance of a Hedera account.
  version: 'v2'
servers:
  - url: https://hedera-account-balance-plugin.replit.app
paths:
  /get_hbar_balance:
    get:
      operationId: getHbarBalance
      summary: Get the HBAR balance of a specific Hedera account
      parameters:
        - in: query
          name: account_id
          schema:
            type: string
          description: The ID of the Hedera account
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/getAccountBalanceResponse'
  /get_token_balance:
    get:
      operationId: getTokenBalance
      summary: Get the token balance of a specific Hedera account
      parameters:
        - in: query
          name: account_id
          schema:
            type: string
          description: The ID of the Hedera account
        - in: query
          name: token_id
          schema:
            type: string
          description: The token ID of the HTS Token
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/getAccountBalanceResponse'
components:
  schemas:
    getAccountBalanceResponse:
      type: object
      properties:
        account:
          type: string
          description: The ID of the Hedera account.
        balance:
          type: number
          description: The balance of the Hedera account.

3. Adding a JSON Manifest File: Describing What Your Plugin Does

The JSON manifest file is like a directory for your plugin. It provides essential details about the plugin, both for human users and AI models, like ChatGPT. It acts as a guide for ChatGPT to understand the functionality of the plugin and how to interact with it, while also providing human users with clear and concise information about what the plugin does and how it can be used.

In our manifest file, key details include both a name_for_human and name_for_model fields. The description_for_human and description_for_model also provide explanations about the plugin's functionality for both audiences. The auth field indicates the type of authentication required to access the API, in this case, no authentication is needed. The api section specifies the type of API (OpenAPI) and the url to access its specification – this URL should be the base URL from running main.py plus the openapi.yaml file. Other fields include a logo_url for an image that represents the plugin, contact_email for support or queries, and legal_info_url that directs to the plugin's legal information page.

Every field in this manifest file helps make the plugin more understandable and easier to use for both humans and AI models, and it's an important piece to make your plugin as user-friendly as possible. For more information about the manifest, check out the OpenAI documentation.

Code Snippet Background
{
    "schema_version": "v1",
    "name_for_human": "Hedera Account Balance",
    "name_for_model": "HederaAccountBalance",
    "description_for_human": "Gets the HBAR and token balance of a Hedera account.",
    "description_for_model": "Helps the user to fetch the balance of a Hedera account. The user can provide the account ID and token ID (optional) and the model will make a request to the Hedera mirror node REST API.",
    "auth": {
        "type": "none"
    },
    "api": {
        "type": "openapi",
        "url": "https://hedera-account-balance-plugin.replit.app/openapi.yaml"
    },
    "logo_url": "https://s2.coinmarketcap.com/static/img/coins/64x64/4642.png",
    "contact_email": "[email protected]",
    "legal_info_url": "https://hedera.com/terms"
}

4. Installing the Plugin in the ChatGPT UI: Making It All Work

Your ChatGPT plugin is now ready to be installed! If you have a ChatGPT Plus membership, then you can access and install verified plugins. At the time of this writing, you may still need to request access to the plugins waitlist to install plugins you develop – see the plugins home page for more information.

Remember to grab the server URL in openapi.yaml as you’ll need it in this step. The one from this example is:

https://hedera-account-balance-plugin.replit.app

Now follow the steps shown below:

Description of the image

5. Chatting with ChatGPT: Using Your Plugin

Now that your plugin is installed and enabled, you can use it by simply asking ChatGPT questions about the HBAR and/or token balances of Hedera accounts.

In the case shown below, we ask ChatGPT how many HBAR and units of token 0.0.2283230 (KARATE) are owned by account 0.0.3019125. The results are verified using HashScan, which is a network explorer for Hedera.

Description of the image
5p2 HASHCAN RESULT

Wrapping Up: Looking Back and Looking Ahead

In this article, you learned to combine the strengths of AI and blockchain technology. The journey of creating a ChatGPT plugin is enriching, and it opens doors to explore new dimensions of AI and blockchain. You successfully paired ChatGPT and Hedera, two powerful tools, to form a unique solution! You started by crafting a Python API for your custom functionality, then described your API using OpenAPI yaml, and finally documented the plugin's purpose in the JSON manifest file.

This guide is just the beginning. You can continue having fun verifying your plugin, making it production-grade, and following best practices. The possibilities with Hedera and ChatGPT plugins are endless. You could create plugins that fetch other types of information from the mirror nodes, like the number NFTs minted in the last hour or transactions processed in the last day. You could also submit transactions to the Hedera network, perhaps record data on the Hedera Consensus Service, or even create HTS tokens. The world of AI and blockchain is yours to explore!

Continue Learning