Utilizing ChatGPT to Interact with a Blockchain-Based Game

kompotkot

Sergei Sumarokov

Posted on April 20, 2023

Utilizing ChatGPT to Interact with a Blockchain-Based Game

In this article, we will guide you through the process of developing a prototype bot using OpenAI's ChatGPT 3.5 API, designed to participate in Moonstream.to's blockchain-based text game, Great Wyrm. The completed code can be found in the kompotkot/gofp-chatgpt-bot repository.

Great Wyrm session

Great Wyrm serves as a platform for hosting game sessions in a "game master - players" format. As the game undergoes active testing, its creators independently facilitate game sessions. The platform operates on Caldera's wyrm.constellation blockchain network. To join, register through the provided Discord link.

Our code will be written in Python. Since Great Wyrm is built upon the Ethereum blockchain, we will utilize the brownie library for network interactions and the moonworm library to generate a Python interface from the ABI.

Typically, for popular games, ABIs can be located on Etherscan under the "Code" tab, within the project's GitHub repository, or generated independently from .sol files using tools such as brownie. For the Great Wyrm game, the contract can be accessed through a GitHub link, while the prepared ABI is available in Moonstream's documentation.

Nonetheless, having only the ABI requires us to reconstruct the brownie structure for proper functionality. To accomplish this, follow these steps to create the necessary folders and copy the ABI:

mkdir -p gcb/build/contracts/
cp abi/GOFP.json gcb/build/contracts/gofp.json
Enter fullscreen mode Exit fullscreen mode

The resulting file, gcb/build/contracts/gofp.json, should appear as follows:

{
  "abi": [
    ...
  ]
}
Enter fullscreen mode Exit fullscreen mode

First, generate an interface at the ABI address, which will produce a Python file named gcb/gofp.py containing the gofp class and methods that outline the smart contract's functionality:

moonworm generate-brownie --name gofp -o gcb -p gcb
Enter fullscreen mode Exit fullscreen mode

Subsequently, the wyrm is added to brownie's local list of networks:

brownie networks add Constellation wyrm host=https://wyrm.0xconstellation.com/http chainid=322
Enter fullscreen mode Exit fullscreen mode

With the first part completed, we can now communicate with the smart contract by simply introducing a variable:

export GOFP_CONTRACT_ADDRESS="0x42A8E82253CD19EF8274D48fC0bC89cdf1B4425b"
Enter fullscreen mode Exit fullscreen mode

Let's query the smart contract to determine the total number of game sessions:

python -m gcb.gofp num-sessions --network wyrm --address "$GOFP_CONTRACT_ADDRESS"
Enter fullscreen mode Exit fullscreen mode

Next, we will proceed to configure ChatGPT. This requires an API key generated on the OpenAI website, which enables interaction with the platform. Add this key to the code using a variable:

export OPENAI_API_KEY="sk-..."
Enter fullscreen mode Exit fullscreen mode

To test the functionality, let's inquire about the available GPT models for usage:

curl https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY" | jq .data[].id | grep gpt
Enter fullscreen mode Exit fullscreen mode

Finally, return to the source code and examine important parts:

drwxrwxr-x build
-rw-rw-r-- cli.py
-rw-rw-r-- data.py
-rw-rw-r-- gofp.py
-rw-rw-r-- __init__.py
-rw-rw-r-- version.py
-rw-rw-r-- version.txt
Enter fullscreen mode Exit fullscreen mode

In the data.py file, we will utilize the pydantic library to define key structures such as SessionData, SessionDataStages, etc., for added convenience. The primary code can be found in cli.py.

While generating the CLI with argparse, it is necessary to enhance the parser with pre-generated flags and arguments sourced from gofp.py:

add_default_arguments(parser=parser_play, transact=True)
Enter fullscreen mode Exit fullscreen mode

Next, we require two primary arguments: --session to designate the game session to participate in, and --token to identify the token to operate with. Within the main handle_play function, first connect to the brownie network and initialize the contract instance:

network.connect(args.network)
contract = gofp(contract_address=args.address)
Enter fullscreen mode Exit fullscreen mode

Utilizing the moonworm library, we communicate with the smart contract via methods, allowing us to obtain information about the desired game session:

session_info_raw = contract.get_session(args.session)
...
current_stage_indexed = contract.get_current_stage(args.session)
Enter fullscreen mode Exit fullscreen mode

All that remains is to parse the response based on the structures defined in data.py and complete the logic that filters out inactive sessions, among other things.

Each session functions as a unique token, with its own tokenURI containing game stage descriptions, lore, and more. We will obtain this information using the fundamental requests library, implemented in the requests_call function, and parse it according to our predefined structures:

session_data_raw = requests_call(method=data.Method.GET, url=session_info.uri)
Enter fullscreen mode Exit fullscreen mode

Now, we should prepare text for ChatGPT. In this example, we will describe the expected task and request a JSON-formatted response. Under the answer key, ChatGPT should indicate its chosen path in the game, while providing a rationale for the choice under the description key:

message_to_bot = f"""Let's play. I will provide you with a short lore containing 
different paths to choose from. Please respond in JSON format. You should select 
one correct path and place it under the key 'answer' and provide an explanation 
for your choice under the key 'description'.

The lore: {session_data.stages[current_stage].lore}
Paths:
{paths}
"""
Enter fullscreen mode Exit fullscreen mode

Request a response from ChatGPT, ensuring a high timeout value is specified, as responses may occasionally take longer than expected:

openapi_headers = {
    "Authorization": f"Bearer {OPENAI_API_KEY}",
}
payload = {
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": message_to_bot}],
}

bot_resp_raw = requests_call(
    method=data.Method.POST,
    url=f"{OPENAPI_BASE_URL}/completions",
    headers=openapi_headers,
    json=payload,
    timeout=60,
)
Enter fullscreen mode Exit fullscreen mode

For more comprehensive interaction with the bot, OpenAI offers a range of detailed settings available in the endpoint documentation.

Upon receiving a response, we will process it and generate a transaction:

transaction_config = get_transaction_config(args)

tx_hash = contract.choose_current_stage_paths(
    session_id=args.session,
    token_ids=[args.token],
    paths=[bot_answer + 1],
    transaction_config=transaction_config
)
Enter fullscreen mode Exit fullscreen mode

Once prepared, using your keyfile, execute the code with the following command:

gcb play --address "$GOFP_CONTRACT_ADDRESS" \
  --network wyrm \
  --confirmations 0 \
  --sender "$DEV_KEYFILE" \
  --password "$DEV_KEYFILE_PASSOWRD" \
  --session 4 \
  --token 2
Enter fullscreen mode Exit fullscreen mode

The bot will retrieve the necessary data, parse the result, and report the transaction details:

INFO:gcb.cli:Fetch session 4 with stages [4, 1] and uri https://s3.amazonaws.com/static.greatwyrm.xyz/act1/reda_games/khina_beast_contest.json
INFO:gcb.cli:Current stage of session 4 is 1
INFO:gcb.cli:Fetch session data with title Khina's Beast Contest and active stage title Pit bat
INFO:gcb.cli:Asking ChatGPT to choose path
INFO:gcb.cli:Bot answer is: 1 and description: I would back the Copper hound because it has a useful skill that people could benefit from by sniffing out copper deposits. Additionally, they seem to be domesticated dogs so they may be more manageable than some of the other creatures. The downside is that they are not the most pleasant smelling animals and can be quite loud.
Transaction sent: 0x32bdff6127fdb94f0199f5cc10565c82fffb26768a1029f469a4b205fc5ed9fd
  Gas price: 0.0 gwei   Gas limit: 156629   Nonce: 15
  gofp.chooseCurrentStagePaths confirmed   Block: 470   Gas used: 118554 (75.69%)

<Transaction '0x32bdff6127fdb94f0199f5cc10565c82fffb26768a1029f469a4b205fc5ed9fd'>
Enter fullscreen mode Exit fullscreen mode

In conclusion, we have successfully established an integration between ChatGPT and Web3, laying the groundwork for a chatbot capable of engaging with a blockchain-based game. This combination offers numerous possibilities for extending functionality and tailoring the solution to various tasks and objectives.

Claim your reward!

💖 💪 🙅 🚩
kompotkot
Sergei Sumarokov

Posted on April 20, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related