Utilizing ChatGPT to Interact with a Blockchain-Based Game
Tags: chatgpt, moonstream, gamedev, web3
Published: 2023-04-20 10:46:36

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](https://moonstream.to/)'s blockchain-based text game, [Great Wyrm](https://greatwyrm.xyz/). The completed code can be found in the [kompotkot/gofp-chatgpt-bot](https://github.com/kompotkot/gofp-chatgpt-bot) repository.

![Great Wyrm session](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zuygb16rr1x8t3zisbof.png)

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](https://caldera.xyz/)'s `wyrm.constellation` blockchain network. To join, register through the provided [Discord link](https://discord.gg/knBnttUPqH).

Our code will be written in Python. Since Great Wyrm is built upon the Ethereum blockchain, we will utilize the [brownie](https://pypi.org/project/eth-brownie/) library for network interactions and the [moonworm](https://pypi.org/project/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](https://github.com/great-wyrm/contracts), while the prepared ABI is available in [Moonstream's documentation](https://docs.moonstream.to/engine/mechanics/garden-of-forking-paths/).

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:

```bash
mkdir -p gcb/build/contracts/
cp abi/GOFP.json gcb/build/contracts/gofp.json
```

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

```json
{
  "abi": [
    ...
  ]
}
```

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:

```bash
moonworm generate-brownie --name gofp -o gcb -p gcb
```

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

```bash
brownie networks add Constellation wyrm host=https://wyrm.0xconstellation.com/http chainid=322
```

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

```bash
export GOFP_CONTRACT_ADDRESS="0x42A8E82253CD19EF8274D48fC0bC89cdf1B4425b"
```

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

```bash
python -m gcb.gofp num-sessions --network wyrm --address "$GOFP_CONTRACT_ADDRESS"
```

Next, we will proceed to configure ChatGPT. This requires an API key generated on the [OpenAI website](https://platform.openai.com/account/api-keys), which enables interaction with the platform. Add this key to the code using a variable:

```bash
export OPENAI_API_KEY="sk-..."
```

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

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

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

```bash
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
```

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`:

```python
add_default_arguments(parser=parser_play, transact=True)
```

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:

```python
network.connect(args.network)
contract = gofp(contract_address=args.address)
```

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

```python
session_info_raw = contract.get_session(args.session)
...
current_stage_indexed = contract.get_current_stage(args.session)
```

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:

```python
session_data_raw = requests_call(method=data.Method.GET, url=session_info.uri)
```

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:

```python
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}
"""
```

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

```python
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,
)
```

For more comprehensive interaction with the bot, OpenAI offers a range of detailed settings available in the [endpoint documentation](https://platform.openai.com/docs/api-reference/chat/create).

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

```python
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
)
```

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

```bash
gcb play --address "$GOFP_CONTRACT_ADDRESS" \
  --network wyrm \
  --confirmations 0 \
  --sender "$DEV_KEYFILE" \
  --password "$DEV_KEYFILE_PASSOWRD" \
  --session 4 \
  --token 2
```

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

```bash
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'>
```

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!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7n8v4lsehnca7s5mb3ds.png)