facebook twitter hatena line email

「Unity/ChatGPT」の版間の差分

提供: 初心者エンジニアの簡易メモ
移動: 案内検索
(エラーについて)
 
(同じ利用者による、間の14版が非表示)
行1: 行1:
==unityサンプル==
 
github: https://github.com/hexthedev/OpenAi-Api-Unity
 
  
 
==apiを取得する==
 
==apiを取得する==
行8: 行6:
 
==参考==
 
==参考==
 
https://techblog.kayac.com/2022-group-calendar-unity-openapi
 
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
 +
<pre>
 +
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();
 +
        }
 +
    }
 +
}
 +
</pre>
 +
GptUseCase.cs
 +
<pre>
 +
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;
 +
    }
 +
}
 +
</pre>
 +
GptDefine.cs
 +
<pre>
 +
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>
 +
}
 +
</pre>
 +
GptPresenter.cs
 +
<pre>
 +
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();
 +
    }
 +
}
 +
</pre>
 +
GptRepository.cs
 +
<pre>
 +
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);
 +
    }
 +
}
 +
</pre>
 +
GptView.cs
 +
<pre>
 +
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; }
 +
}
 +
</pre>
 +
==エラーについて==
 +
===429エラーレスポンス===
 +
 +
リクエストの処理中にサーバーでエラーが発生しました。と返ってくるので、多分サーバーに負荷がかかってる状態なのかも。
 +
 +
<pre>
 +
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 ---
 +
</pre>
 +
 +
===You exceeded your current quota, please check your plan and billing details.===
 +
現在の割り当てを超えています。とのことで、無料割当分が、なくなったとか、で使えなくなってる状態。https://platform.openai.com/account/billing/overview からクレジットで、払えば使えるようになる。

2023年7月24日 (月) 11:41時点における最新版

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 からクレジットで、払えば使えるようになる。