マイクラのチャットからコマンドみたいな感じでAPI呼んでchatGPTみたいなことをできるようにした話

#### 概要
- マイクラサーバーの設定でRCONを使えるようにする
- pythonで最新のログを監視
- ログに設定したコマンド名が含まれていたらOpenAIのAPIを呼び出す
- 結果をRCONでマイクラに渡す

こんな感じ
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/846177/7a6bdab0-ab82-2d63-4f84-825be72fd30a.png)



#### サーバーの設定
server.propertiesの以下の行を変更

```server.properties
rcon.port=適当なポート番号
rcon.password=適当なパスワード
enable-rcon=true
```

#### pythonコード
```minechat.py
import time
from mcrcon import MCRcon
import openai

openai_key = "自分のAPIキー" 
openai.api_key = openai_key

server_address = 'サーバーのアドレス'
server_pass = '設定したパスワード'
server_port= 設定したポート

mclog_file_path = "サーバーのlatest.logのパス"

system_settings = """
あなたはマインクラフトに詳しいプレイヤーです。
マインクラフトに関する質問や雑談に応答してください。
"""

chatGPTcommand = "minechat" # マイクラから呼ぶコマンド名



# ログの末尾1行を読み込むする関数
def read_last_line(filename):
    with open(filename, "rb") as file:
        file.seek(-2, 2)
        while file.read(1) != b"\n":
            file.seek(-2, 1)
        last_line = file.readline().decode("shift-jis").strip()
    print(last_line)
    return last_line



# 最新のログにchatGPTのコマンドが含まれているか確認する関数
def logcheck():
    lastlog = read_last_line(mclog_file_path)

    line = lastlog.strip()
    if chatGPTcommand in line:
            cmd_index = line.index(chatGPTcommand)
            result = line[cmd_index + len(chatGPTcommand):]
            return result
    return None



# chatGPTに投げる関数
def completion(new_message_text:str, settings_text:str = '', past_messages:list = []):

    if len(past_messages) == 0 and len(settings_text) != 0:
        system = {"role": "system", "content": settings_text}
        past_messages.append(system)
    new_message = {"role": "user", "content": new_message_text}
    past_messages.append(new_message)

    result = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=past_messages
    )
    response_message = {"role": "assistant", "content": result.choices[0].message.content}
    past_messages.append(response_message)
    response_message_text = result.choices[0].message.content
    return response_message_text, past_messages




def main():

    messages = []
    while True:
        # 1秒ごとにログを確認
        time.sleep(1)
        input_str = logcheck()

        # コマンドが呼ばれていなければ次サイクルへ
        if input_str == None:
            continue

        # 応答を返す
        with MCRcon(server_address, server_pass, server_port) as mcr:
            mcrlog = mcr.command("say chatGPTの応答待ち...")
            new_message, messages = completion(input_str, system_settings, messages)
            mcrlog = mcr.command("say chatGPT : "+ new_message)




if __name__ == "__main__":
    main()
```

#### 使い方
サーバーをたてて、上記のプログラムを実行する。
マイクラのチャットで以下のように入力する。
```
minechat (質問したい文章)
```
”応答待ち”と表示されればひとまずコマンドの認識はできている。
API投げてから帰ってくるまでにはだいたい数秒くらいかかる。
pythonのプログラムを止めるときはCtrl+C
パターンマッチを適当にやってるので、コマンドではなく普通のチャットで"minechat"の文字列を入れたときもコマンドとして認識されてしまう点は注意。




#### 感想とか
chatGPTすごいですね。上記のプログラムも一部chatGPTさんに教えてもらいながら書きました。
今回のプログラムはとりあえず最低限な内容で作りましたが、対話相手にキャラクターを付けたり自動読み上げを付けたりと、機能の幅を広げられそうです。




#### 参考にした記事
- https://qiita.com/mutchan1k/items/0084af949a9f1dd44e6b
- https://qiita.com/sakasegawa/items/db2cff79bd14faf2c8e0
- https://qiita.com/yt0f1/items/dc6357f6b3f2a37c5253