「Unity/ChatGPT」の版間の差分
提供: 初心者エンジニアの簡易メモ
(→エラーについて) |
|||
(同じ利用者による、間の14版が非表示) | |||
行1: | 行1: | ||
− | |||
− | |||
==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を取得する
- https://beta.openai.com/ でアカウントを作成
- "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 からクレジットで、払えば使えるようになる。