facebook twitter hatena line email

Unity/ChatGPT

提供: 初心者エンジニアの簡易メモ
移動: 案内検索

apiを取得する

  1. https://beta.openai.com/ でアカウントを作成
  2. "create new secret key"を押してAPIキーを作成する

参考

https://techblog.kayac.com/2022-group-calendar-unity-openapi

料金確認

https://platform.openai.com/account/usage

リクエスト制限

https://platform.openai.com/docs/guides/rate-limits/overview

無料ユーザは、20リクエスト/分まで 従量ユーザは、60~3000リクエスト/分まで

unityサンプル

Main.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Main : MonoBehaviour
{
    [SerializeField] GptView gptView;
    GptUseCase gptUseCase = null;
    void Awake()
    {
        if (ReferenceEquals(gptUseCase, null))
        {
            GptRepository gptRepository = new GptRepository();
            GptPresenter gptPresenter = new GptPresenter(gptView);
            gptUseCase = new GptUseCase(
                gptPresenter,
                gptRepository
                );
            gptUseCase.Begin();
        }
    }
    void OnDestroy()
    {
        if (!ReferenceEquals(gptUseCase, null))
        {
            gptUseCase.Finish();
        }
    }
}

GptUseCase.cs

using UnityEngine;
using System.Linq;
using Cysharp.Threading.Tasks;
using TMPro;
using UniRx;

public class GptUseCase
{
    GptPresenter gptPresenter;
    GptRepository gptRepository;
    CompositeDisposable disposable = null;
    public GptUseCase(
        GptPresenter gptPresenter,
        GptRepository gptRepository
        )
    {
        this.gptPresenter = gptPresenter;
        this.gptRepository = gptRepository;
    }
    /// <summary> 初回処理 </summary>
    public void Begin()
    {
        disposable = new CompositeDisposable();
        gptPresenter.Bind();
        gptPresenter.ExecOnClickAsObservable
            .Subscribe(async _ => {
                TMP_InputField input = gptPresenter.GptView.Input;
                string prompt = input.text;
                if (!string.IsNullOrEmpty(prompt))
                {
                    var response = await gptRepository.GetAPIResponse(prompt);
                    string outputText = response.Choices.FirstOrDefault().Text;
                    string outputText = prompt;
                    outputText = outputText.TrimStart('\n');
                }
            })
            .AddTo(disposable);
    }
    /// <summary> 終了処理 </summary>
    public void Finish()
    {
        disposable.Dispose();
        disposable = null;
    }
}

GptDefine.cs

public class GptDefine
{
    /// <summary>
    /// APIエンドポイント
    /// </summary>
    public const string API_END_POINT = "https://api.openai.com/v1/completions";
    /// <summary>
    /// API KEY
    /// </summary>
    public const string API_KEY = "API_KEY";
    /// <summary>
}

GptPresenter.cs

using UniRx;
using System;

public class GptPresenter
{
    GptView gptView = null;
    public GptView GptView { get => gptView; set => value = gptView; }
    /// <summary> 実行Observable </summary>
    IObservable<Unit> execOnClickAsObservable = null;
    public IObservable<Unit> ExecOnClickAsObservable { get => execOnClickAsObservable; }
    public GptPresenter(GptView gptView)
    {
        this.gptView = gptView;
    }
    public void Bind()
    {
        execOnClickAsObservable = gptView.ExecButton.OnClickAsObservable();
    }
}

GptRepository.cs

using UnityEngine.Networking;
using Newtonsoft.Json;
using System;
using Cysharp.Threading.Tasks;

public class GptRepository
{
    /// <summary>
    /// APIからレスポンス取得
    /// </summary>
    /// <param name="prompt"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public async UniTask<GptAPIResponseEntity> GetAPIResponse(string prompt)
    {
        GptAPIRequestEntity requestEntity = new()
        {
            Prompt = prompt,
            MaxTokens = 200
        };
        string requestJson = JsonConvert.SerializeObject(requestEntity, Formatting.Indented);
        byte[] data = System.Text.Encoding.UTF8.GetBytes(requestJson);
        string jsonString = null;
        using (UnityWebRequest request = UnityWebRequest.Post(GptDefine.API_END_POINT, "POST"))
        {
            request.uploadHandler = new UploadHandlerRaw(data);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", "Bearer " + GptDefine.API_KEY);
            await request.SendWebRequest();
            switch (request.result)
            {
                case UnityWebRequest.Result.InProgress:
                    break;
                case UnityWebRequest.Result.Success:
                    jsonString = request.downloadHandler.text;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        return JsonConvert.DeserializeObject<GptAPIResponseEntity>(jsonString);
    }
}

GptView.cs

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class GptView : MonoBehaviour
{
    /// 入力欄
    [SerializeField]
    private TMP_InputField input;
    public TMP_InputField Input { get => input; }
    /// 出力欄
    [SerializeField]
    private TextMeshProUGUI output;
    public TextMeshProUGUI Output { get => output; }
    /// 実行ボタン
    [SerializeField]
    private Button execButton;
    public Button ExecButton { get => execButton; }
}

エラーについて

429エラーレスポンス

リクエストの処理中にサーバーでエラーが発生しました。と返ってくるので、多分サーバーに負荷がかかってる状態なのかも。

UnityWebRequestException: HTTP/1.1 429 Too Many Requests
{
  "error": {
    "message": "The server had an error while processing your request. Sorry about that!",
    "type": "server_error",
    "param": null,
    "code": null
  }
}
Cysharp.Threading.Tasks.UnityAsyncExtensions+UnityWebRequestAsyncOperationAwaiter.GetResult () [0x00000] in <00000000000000000000000000000000>:0 
--- End of stack trace from previous location where exception was thrown ---

You exceeded your current quota, please check your plan and billing details.

現在の割り当てを超えています。とのことで、無料割当分が、なくなったとか、で使えなくなってる状態。https://platform.openai.com/account/billing/overview からクレジットで、払えば使えるようになる。