Created
March 23, 2023 12:18
-
-
Save negipoyoc/4fbb8d5136a834661cee15abf7102167 to your computer and use it in GitHub Desktop.
ChatGPTに自分のコードのパフォーマンス改善やテストコードの生成などをお願いするUnity Editor拡張です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using Cysharp.Threading.Tasks; | |
using UnityEditor; | |
using UnityEngine; | |
using UnityEngine.Networking; | |
using Object = UnityEngine.Object; | |
namespace LuppetEditor | |
{ | |
public class ChatGptCodeReviewerWindow : EditorWindow | |
{ | |
private bool _isWaitingForResponse; | |
private float _copyFeedbackTime; | |
private int _promptType; | |
private string _promptText; | |
private const string ChatGptapiUrl = "https://api.openai.com/v1/chat/completions"; | |
private const string APIKey = "{{自分のOpenAIのAPIKeyを入力してね}}"; | |
// ウィンドウを開くためのメニュー項目 | |
[MenuItem("Window/ChatGPT Code Reviewer")] | |
public static void ShowWindow() | |
{ | |
GetWindow<ChatGptCodeReviewerWindow>("ChatGPT Code Reviewer"); | |
} | |
// ドラッグアンドドロップ用の変数 | |
private Object _codeFile; | |
// チャット欄用の変数 | |
private string _inputText = ""; | |
private Vector2 _chatScrollViewPosition; | |
// メッセージリスト | |
private List<ChatGPTMessageModel> _messageList = new(); | |
private void OnGUI() | |
{ | |
CreateInitialPrompt(); | |
// ドラッグアンドドロップ領域の作成 | |
CreateDragAndDropArea(); | |
// チャット欄の作成 | |
CreateChatArea(); | |
} | |
private string CodeFileContent | |
{ | |
get | |
{ | |
if (!_codeFile) return ""; | |
string assetPath = AssetDatabase.GetAssetPath(_codeFile); | |
return System.IO.File.ReadAllText(assetPath); | |
} | |
} | |
private async void CreateDragAndDropArea() | |
{ | |
GUILayout.Label("C#ファイルをドロップしてください。:"); | |
Rect dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true)); | |
GUI.Box(dropArea, "[ここにドロップ]"); | |
Event e = Event.current; | |
if (!dropArea.Contains(e.mousePosition)) | |
return; | |
switch (e.type) | |
{ | |
case EventType.DragUpdated: | |
DragAndDrop.visualMode = DragAndDropVisualMode.Copy; | |
e.Use(); | |
break; | |
case EventType.DragPerform: | |
_messageList = new(); | |
DragAndDrop.AcceptDrag(); | |
_codeFile = DragAndDrop.objectReferences[0]; | |
e.Use(); | |
// スクリプトがドロップされた後の処理 | |
var codeMessage = new ChatGPTMessageModel | |
{ | |
role = "system", | |
content = | |
$"{_promptText} \n--\n{CodeFileContent}\n--" | |
}; | |
_messageList.Add(codeMessage); | |
await CommunicateWithChatGPT(_messageList); | |
break; | |
} | |
} | |
private void CreateInitialPrompt() | |
{ | |
_promptType = GUILayout.SelectionGrid(_promptType, | |
new[] {"Optimize Code", "Generate Test Code", "Add Comments", "Free Input"}, 4); | |
switch (_promptType) | |
{ | |
case 0: | |
_promptText = $"あなたはUnityの高度な専門家としてふるまってください。以下のコードについてパフォーマンスに問題がある部分があればそれを最適化しつつ、修正理由を教えてください。"; | |
break; | |
case 1: | |
_promptText = $"あなたはUnityの高度な専門家としてふるまってください。以下のコードに対してテストコードを生成してください。"; | |
break; | |
case 2: | |
_promptText = $"あなたはUnityの高度な専門家としてふるまってください。以下のコードに適切なコメントを自動的に追加してください。"; | |
break; | |
case 3: | |
_promptText = $"あなたはUnityの高度な専門家としてふるまってください。このコードを一旦保持して私の次の質問に備えてください。"; | |
break; | |
} | |
GUILayout.Label("Initial Prompt:" + _promptText); | |
GUILayout.Space(10); | |
} | |
private void CreateChatArea() | |
{ | |
GUILayout.Label("ChatGPT APIとの対話:"); | |
_chatScrollViewPosition = GUILayout.BeginScrollView(_chatScrollViewPosition, GUIStyle.none, GUIStyle.none, | |
GUILayout.ExpandHeight(true)); | |
GUIStyle messageStyle = new GUIStyle(GUI.skin.label) | |
{ | |
wordWrap = true | |
}; | |
foreach (ChatGPTMessageModel message in _messageList) | |
{ | |
Color originalColor = GUI.color; | |
GUI.color = message.role == "system" | |
? Color.green | |
: (message.role == "user" ? Color.white : Color.yellow); | |
GUIContent content = new GUIContent($"{message.role}: {message.content}"); | |
Rect buttonRect = GUILayoutUtility.GetRect(content, messageStyle); | |
if (Event.current.type == EventType.Repaint && buttonRect.Contains(Event.current.mousePosition)) | |
{ | |
EditorGUIUtility.AddCursorRect(buttonRect, MouseCursor.Link); | |
content.tooltip = "クリックしてコピー"; | |
} | |
if (GUI.Button(buttonRect, content, messageStyle)) | |
{ | |
EditorGUIUtility.systemCopyBuffer = message.content; | |
_copyFeedbackTime = Time.realtimeSinceStartup; | |
} | |
GUI.color = originalColor; | |
} | |
GUILayout.EndScrollView(); | |
if (_isWaitingForResponse) | |
{ | |
EditorGUILayout.HelpBox("ChatGPTのレスポンスを待っています...", MessageType.Info); | |
} | |
GUILayout.Space(10); | |
GUILayout.BeginHorizontal(); | |
_inputText = GUILayout.TextField(_inputText, GUILayout.ExpandWidth(true)); | |
if (GUILayout.Button("送る", GUILayout.Width(100))) | |
{ | |
SendButtonClicked(); | |
} | |
GUILayout.EndHorizontal(); | |
if (_copyFeedbackTime > 0 && Time.realtimeSinceStartup - _copyFeedbackTime < 2) | |
{ | |
EditorGUI.HelpBox(GUILayoutUtility.GetLastRect(), "コピーしました!", MessageType.Info); | |
} | |
} | |
private async void SendButtonClicked() | |
{ | |
if (string.IsNullOrEmpty(_inputText)) | |
return; | |
ChatGPTMessageModel userMessage = new ChatGPTMessageModel {role = "user", content = _inputText}; | |
_messageList.Add(userMessage); | |
_inputText = ""; | |
// ここでChatGPT APIと通信 | |
await CommunicateWithChatGPT(_messageList); | |
} | |
private async UniTask CommunicateWithChatGPT(List<ChatGPTMessageModel> messages) | |
{ | |
ChatGPTCompletionRequestModel requestData = new ChatGPTCompletionRequestModel | |
{ | |
model = "gpt-3.5-turbo", | |
messages = messages | |
}; | |
string json = JsonUtility.ToJson(requestData); | |
byte[] bodyRaw = Encoding.UTF8.GetBytes(json); | |
using (UnityWebRequest www = new UnityWebRequest(ChatGptapiUrl, "POST")) | |
{ | |
www.uploadHandler = new UploadHandlerRaw(bodyRaw); | |
www.downloadHandler = new DownloadHandlerBuffer(); | |
www.SetRequestHeader("Content-Type", "application/json"); | |
www.SetRequestHeader("Authorization", $"Bearer {APIKey}"); | |
_isWaitingForResponse = true; | |
await www.SendWebRequest(); | |
_isWaitingForResponse = false; | |
if (www.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.LogError("Error: " + www.error); | |
} | |
else | |
{ | |
ChatGPTResponseModel response = | |
JsonUtility.FromJson<ChatGPTResponseModel>(www.downloadHandler.text); | |
if (response.choices.Length > 0) | |
{ | |
ChatGPTMessageModel chatGPTMessage = response.choices[0].message; | |
_messageList.Add(chatGPTMessage); | |
Repaint(); | |
} | |
else | |
{ | |
Debug.LogError("Error: No choices in ChatGPT response"); | |
} | |
} | |
} | |
} | |
} | |
[Serializable] | |
public class ChatGPTMessageModel | |
{ | |
public string role; | |
public string content; | |
} | |
//ChatGPT APIにRequestを送るためのJSON用クラス | |
[Serializable] | |
public class ChatGPTCompletionRequestModel | |
{ | |
public string model; | |
public List<ChatGPTMessageModel> messages; | |
} | |
//ChatGPT APIからのResponseを受け取るためのクラス | |
[System.Serializable] | |
public class ChatGPTResponseModel | |
{ | |
public string id; | |
public string @object; | |
public int created; | |
public Choice[] choices; | |
public Usage usage; | |
[System.Serializable] | |
public class Choice | |
{ | |
public int index; | |
public ChatGPTMessageModel message; | |
public string finish_reason; | |
} | |
[System.Serializable] | |
public class Usage | |
{ | |
public int prompt_tokens; | |
public int completion_tokens; | |
public int total_tokens; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment