見出し画像

【GPT-4×Unity】AIと一緒にゲームを作ってみた(おまけ1: UnityをGPTに動かしてもらおう)

 こんな企画を立てていて、続きを書く予定だったのですが脇道にそれたのでおまけにした……という感じの記事です。

 なんとなくUnity側の操作もGPTにお任せできたら……と思ったのでやってみました。もう誰かしらやってるだろうけど。


まずはおためし

筆者
ありがとうございます。ですが、Unityから直接GPTを頼ることができたほうがいいかもしれませんね。
UnityのC#のスクリプトからGPTのAPIにアクセスする方法はあるでしょうか? 参考までに、curlコマンドを使ってGPT APIにアクセスしてメッセージを送るやり方の一例を添えておきます。

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

試しに、TextFieldから質問を入力し、決定ボタンを押すとGPT APIにそれを送り、結果が帰ってきたら画面上のTextに返答を表示するスクリプトを書いてもらえますでしょうか。

GPT-4
UnityのC#スクリプトからGPT APIにアクセスするには、UnityWebRequestを使用してHTTPリクエストを送信します。以下に、質問を入力し、決定ボタンを押すとGPT APIにそれを送り、結果が帰ってきたら画面上のTextに返答を表示するスクリプトの例を示します。

まず、Unityで新しいプロジェクトを作成し、必要なUI要素(InputField, Button, Text)をシーンに追加してください。

次に、GptApiManagerという名前で新しいC#スクリプトを作成し、以下のコードをコピーしてください。

csharpCopy codeusing System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class GptApiManager : MonoBehaviour
{
    public InputField inputField;
    public Button submitButton;
    public Text responseText;
    private string openaiApiKey = "your_api_key_here";

    private void Start()
    {
        submitButton.onClick.AddListener(OnSubmit);
    }

    private void OnSubmit()
    {
        StartCoroutine(SendQuestionToGpt(inputField.text));
    }

    private IEnumerator SendQuestionToGpt(string question)
    {
        string apiUrl = "https://api.openai.com/v1/chat/completions";
        string jsonPayload = "{\"model\": \"gpt-3.5-turbo\", \"messages\": [{\"role\": \"user\", \"content\": \"" + question + "\"}]}";

        using (UnityWebRequest request = new UnityWebRequest(apiUrl, "POST"))
        {
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", "Bearer " + openaiApiKey);
            request.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(jsonPayload));
            request.downloadHandler = new DownloadHandlerBuffer();

            yield return request.SendWebRequest();

            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                responseText.text = "Error: " + request.error;
            }
            else
            {
                string response = request.downloadHandler.text;
                responseText.text = ProcessApiResponse(response);
            }
        }
    }

    private string ProcessApiResponse(string jsonResponse)
    {
        // ここでJSONレスポンスを解析して、適切な回答を返します。
        // 簡単のため、この例ではレスポンス全体を返しますが、実際にはJSONを解析して適切な部分を取得する必要があります。
        return jsonResponse;
    }
}

このスクリプトをシーン内の空のGameObjectにアタッチし、inputFieldsubmitButton、およびresponseTextを対応するUI要素にアサインしてください。

最後に、上記のコード中にあるyour_api_key_hereを実際のOpenAI APIキーに置き換えてください。これで、UnityプロジェクトでGPT APIに質問を送信し、返答を表示することができるようになります。ただし、このスクリプトはエラーハンドリングやJSONレスポンスの解析が簡略化されているため、返答を取得するためにJSONレスポンスの解析を改善する必要があります。以下に、JSONレスポンスを解析して適切な回答を取得するコードを追加したスクリプトを示します。

まず、JsonUtilityを使ってレスポンスを解析するために、次のクラスを追加します。

csharpCopy codeusing System.Collections.Generic;

[System.Serializable]
public class GptResponseMessage
{
    public string role;
    public string content;
}

[System.Serializable]
public class GptResponseChoices
{
    public List<GptResponseMessage> messages;
}

[System.Serializable]
public class GptResponse
{
    public List<GptResponseChoices> choices;
}

次に、ProcessApiResponseメソッドを以下のように更新して、実際の回答を取得できるようにします。

csharpCopy codeprivate string ProcessApiResponse(string jsonResponse)
{
    GptResponse response = JsonUtility.FromJson<GptResponse>(jsonResponse);
    GptResponseMessage responseMessage = response.choices[0].messages.Find(msg => msg.role == "assistant");

    return responseMessage != null ? responseMessage.content : "Error: Couldn't find the response.";
}

この更新により、APIからのJSONレスポンスを適切に解析し、GPT-4からの回答を表示できるようになります。このスクリプトは基本的なエラーハンドリングを行っていますが、さらに堅牢なエラーハンドリングを実装することをお勧めします。

また、APIキーを直接スクリプトに記述するのはセキュリティリスクがあるため、安全な方法でAPIキーを管理することを検討してください。例えば、Unityエディタで環境変数を使用したり、セキュアな設定ファイルを使用したりすることができます。


 ここまででとりあえずUnityに入れたら、APIからのレスポンスを受け取るところまではできました。しかし回答文が画面に表示されません。
 ちょっと中を見てみたところ、JSONになってるレスポンスからGPTの回答の部分を抜き出すことができなかったようです。修正をお願いしてみます。


筆者
すみません、教えていただいたコードをUnityで動かしてみましたが、うまく返答を受け取ることができません。 確認したら、ProcessApiResponseメソッドでresponse.choices[0].messagesの中身が入っていないようです。 どうすればよいでしょうか? APIからのレスポンスだけは別途取れたので、参考までに送ります。
(※APIレスポンスJSONを添付)

GPT-4
お手数をおかけして申し訳ありません。APIからのレスポンスを確認したところ、choicesのJSON構造が異なることがわかりました。以下に修正されたクラス定義とProcessApiResponseメソッドを示します。

まず、次のクラス定義に更新してください。

csharpCopy codeusing System.Collections.Generic;

[System.Serializable]
public class GptResponseMessage
{
    public string role;
    public string content;
}

[System.Serializable]
public class GptResponseChoice
{
    public GptResponseMessage message;
    public string finish_reason;
    public int index;
}

[System.Serializable]
public class GptResponse
{
    public List<GptResponseChoice> choices;
}

次に、ProcessApiResponseメソッドを以下のように更新してください。

csharpCopy codeprivate string ProcessApiResponse(string jsonResponse)
{
    GptResponse response = JsonUtility.FromJson<GptResponse>(jsonResponse);
    GptResponseMessage responseMessage = response.choices[0].message;

    return responseMessage != null ? responseMessage.content : "Error: Couldn't find the response.";
}

これでAPIからのJSONレスポンスが正しく解析され、GPT-4からの回答を表示できるようになるはずです。もしまだ問題がある場合は、お知らせください。


 結果……

真ん中のフィールドに入力して送信ボタン押してしばらく待つと回答が出ます

 できちゃった! すげー!
 GPT-4は確か2021年半ばくらいまでのデータしか学習に使ってないのを思い出したのでAPIのアクセス例だけ添えておいたのですが……『"role": "assistant"』とか入れてるあたり知ってたのか。まあ当然っちゃ当然か。
 いずれにせよやりたいことを伝えるだけでコードを書いてくれ、修正も必要ならしてくれるというのは非常にありがたいです。

 そういえばこれを書いてる間にGitHub Copilot Xなんてのが出ちゃいましたね……

 ここまでやったようなことがVSCodeから直接できるようになるっぽいです。これで独りでも怖くない……?


Editor拡張から質問できるようにする

 今度はEditor拡張からGPT APIにアクセスできる仕組みを作ってもらいます。非同期処理の勝手がちょっと違ってくるようなので、また初めからコードを書いてもらいました。
 長くなってしまうので、ここからはコードとGPT-4とのやりとりについてはGitHubにアップロードしていきます。以下をご覧ください。

 スクリーンショットのみこちらに貼っておきます。API KeyフォームにAPIキーを入れ、ModelフォームでGPT-3.5 or 4を選択し、質問を入力してOKボタンを押すと回答が返ってきます。

スクリプト自動生成

 実は既に前例があるのですが……

 とりあえず上記を参考にしつつほぼほぼGPT-4に頼る形で似たようなの作ってみました、というだけのを下に。

 指示の内容の違いもあるのではないかと思いますが、GPT-3.5だと「説明をつけないでほしい」という部分をどうしても無視してしまうようです。

GPT-3.5の例

 ではGPT-4なら……と思いましたがやっぱりブロック部分くっついちゃってますね。

GPT-4の例

 一応余計な部分を削除すれば正常には動くので、スクリプト側でブロック部分以外全部削除→ブロック部分も削除して保存、という処理をしたほうが早いかもしれません。
(2023/03/26追記)
 「```csharp」〜「```」で囲まれた部分だけ取り出す処理を追加しました。これで概ねそのまま動きます。

 できればエラーが発生したら自動的に修正もしてくれる機能とかも追加してみたいところ。

おわりに

 ひとまずEditor拡張、シーン内の両方からGPT APIを叩けるようになりました。Unityゲーも全部AIで作れてしまう時代が近いのかもしれません……

 本命のAIによるゲーム制作の方を放置してしまっていたので、ちょっとずつ再開していきます。


この記事が気に入ったらサポートをしてみませんか?