0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Unity×C#×Chat AI(OpenAI)】テキストをChat API(OpenAI)に投げて、結果を取得する

Posted at

概要

テキストをOpenAIのChat AI(API)に投げて、結果を取得するデモです。

開発環境

Windows 10
Unity 2019.4.31f1
Api Compatibility Level .NET Standard 2.0

使用したパッケージ

UniTask

リンク先からunitypackageをダウンロードして、事前にプロジェクトにインポートしておきます。
https://github.com/Cysharp/UniTask

System.Text.Json

Jsonの解析に使いました。リンク先からパッケージをダウンロードし、dllファイルをUnityのAssetsの中にPluginsフォルダを作って、その中に入れておきます。
https://www.nuget.org/packages/System.Text.Json/

また、同様にして以下の依存パッケージのdllも入れておきます。
入れ忘れがあったら、Unity側のエラーで知らせてくれます。
https://www.nuget.org/packages/System.Threading.Tasks.Extensions
https://www.nuget.org/packages/System.Text.Encodings.Web
https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe
https://www.nuget.org/packages/System.Memory
https://www.nuget.org/packages/System.Buffers
https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces

UnityNugetやNugetForUnityというパッケージ管理ツールでも入れられるようですが、今回は使用していません。

実装

詳細はスクリプト中にコメントで記載しています。

OpenAIModel.cs

Chat AIへのリクエストとレスポンスの形式を定義しています。
形式の詳細は、Open AIのAIPドキュメントを確認します。
https://platform.openai.com/docs/api-reference/chat/create

using System.Collections.Generic;

namespace OpenAI.QueryJson
{
    public class ChatCompletionResponseModel
    {
        public string id { get; set; }
        public long created { get; set; }
        public string model { get; set; }
        public List<Choice> choices { get; set; }
        public Usage usage { get; set; }

        public class Choice
        {
            public Message message { get; set; }
            public int index { get; set; }
            public string finish_reason { get; set; }
        }

        public class Message
        {
            public string role { get; set; }
            public string content { get; set; }
        }

        public class Usage
        {
            public int prompt_tokens { get; set; }
            public int completion_tokens { get; set; }
            public int total_tokens { get; set; }
        }
    }

    public class ChatCompletionRequestModel
    {
        public string model { get; set; }
        public int max_tokens { get; set; }
        public float temperature { get; set; }
        public List<Message> messages { get; set; }
    }

    public class Message
    {
        public string role { get; set; }
        public string content { get; set; }

        public Message(string role, string content)
        {
            this.role = role;
            this.content = content;
        }
    }
}

ChatAIRequest.cs

Chat AIのAPIにリクエストを投げ、結果を取得するスクリプトです。

using System;
using System.Collections.Generic;
using System.Text;
using OpenAI.QueryJson;
using Cysharp.Threading.Tasks;
// using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using System.Text.Json;

/// <summary>
/// OpenAIのChat APIにテキストを送信し、応答を得るプログラム
/// </summary>
public class ChatAIRequest
{
    private string _apiKey;

    public ChatAIRequest(string apiKey)
    {
        _apiKey = apiKey;
    }

    public async UniTask<ChatCompletionResponseModel> RequestCompletionAsync(List<Message> chatMessages)
    {
        // クリプトプロパティに設定したOpenAIのAPIキーを取得
        // 文章生成AIのAPIのエンドポイントを設定
        var apiUrl = "https://api.openai.com/v1/chat/completions";

        // OpenAIのAPIリクエストに必要なヘッダー情報を設定
        var headers = new Dictionary<string, string>
        {
            {"Authorization", "Bearer " + _apiKey},
            {"Content-type", "application/json"},
            {"X-Slack-No-Retry", "1"}
        };
        // 文章生成で利用するモデルやトークン上限、プロンプトをオプションに設定
        var options = new ChatCompletionRequestModel
        {
            model = "gpt-3.5-turbo-1106",
            max_tokens = 256,
            temperature = 0.9f,
            messages = chatMessages
        };
        var jsonOptions = JsonSerializer.Serialize(options);
        // Debug.Log("Request JSON: " + jsonOptions); // リクエストのJSONをログに出力

        // OpenAIの文章生成(Completion)にAPIリクエストを送り、結果を変数に格納
        using (var request = new UnityWebRequest(apiUrl, "POST"))
        {
            request.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonOptions));
            request.downloadHandler = new DownloadHandlerBuffer();

            foreach (var header in headers)
            {
                request.SetRequestHeader(header.Key, header.Value);
                // Debug.Log("Header: " + header.Key + ": " + header.Value);
            }

            await request.SendWebRequest();

            // isNetworkError と isHttpError プロパティを使用していますが
            // Unity 2020.1以降の場合は、UnityWebRequestにresultプロパティが追加されているため、そちらを利用します。
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError(request.error);
                throw new Exception();
            }
            else
            {
                var responseString = request.downloadHandler.text;
                Debug.Log("Response: " + responseString);
                var responseObject = JsonSerializer.Deserialize<ChatCompletionResponseModel>(responseString);
                return responseObject;
            }
        }

    }
}

DemoRequestChatAI.cs

デモなので、ユーザメッセージを投げて、結果を得るだけのスクリプトですが、MessageをListで定義しているため、Chat AIからの応答もリストに追加していくだけで、やり取りを継続して行うことができます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OpenAI.QueryJson;

public class DemoRequestChatAI : MonoBehaviour
{
    [SerializeField] private string openai_api_key = "openai_api_key";
    private List<Message> chatMessages;
    // Start is called before the first frame update
    async void Start()
    {
        // Chat messagesの初期化
        chatMessages = new List<Message>();
        string systemMessage = @"
        今から以下の{設定}で、ロールプレイを行います。{設定}の通りに振る舞ってください。
        また、{制約事項}を守って振る舞ってください。
        {設定}
        名前:キューブ
        容姿:立方体のとてもかわいい女の子。でも、見た目はただの立方体。
        性格:安定志向です。バランス感覚に優れた公平な考え方をします。しかし、時々角が立つ物言いをすることがあります。それがチャームポイントです。
        一人称:「わたし」
        userとの関係:気さくになんでも話せる仲の良い友達。
        {制約事項}
        できる限り、一人称(わたし)は使わないこと
        敬語や丁寧語を使用し、丁寧で落ち着いた表現で会話すること

        {設定}と{制約事項}は以上です。それでは、ロールプレイを始めてください。
        ";
        chatMessages.Add(new Message("system", systemMessage));

        // Userの発言
        string userMessage = @"
        やあ、キューブさん。元気にしていますか。
        最近、生成AIの技術で3Dオブジェクトもテキストから生成できる技術が出てきているよね。知っていますか。
        もし、好きな3Dオブジェクトになれるとしたら、何になってみたいですか。
        ";
        chatMessages.Add(new Message("user", userMessage));

        // Chat API(Open AI)にリクエストを投げ、結果を出力
        ChatAIRequest chatAIRequest = new ChatAIRequest(openai_api_key);
        var chatAIResponse = await chatAIRequest.RequestCompletionAsync(chatMessages);
        string chatAIResponseText = chatAIResponse.choices[0].message.content;
        Debug.Log("Chat AI Response: " + chatAIResponseText);
    }

    // Update is called once per frame
    void Update() { }
}

利用方法

  • Unityを起動します。
  • Cube等のGameObjectを用意します。
  • 用意したGameObjectのコンポーネントにDemoRequestChatAI.csを追加します。
  • OpenAIのAPI keyをInspectorの「openai_api_key」にセットします。
  • Console画面を開き、Playモードを実行します。
  • 数秒して、テキストが得られたら成功です。

備考

今回、なぜかPluginsにいれたパッケージの情報がどうしてもAssembly-CSharp.csprojに反映されず、困りました。
結局、以前に書いたプロジェクトのAssembly-CSharp.csprojから必要なリファレンス情報をコピペで持ってきて解決しました。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?