LoginSignup
6
4

More than 1 year has passed since last update.

Unity×ChatGPTでAI彼女Botを作るチャレンジ備忘録

Last updated at Posted at 2023-03-12

はじめに

ChatGPT APIが公開され、開発者が様々なプラットフォームでChatGPTが活用できるようになりました。

この記事では、Unityエンジニア向けに、ChatGPT活用事例を共有したいと思います。

対象者

  • Unityある程度できる人
    • REST API叩いたことある
    • Editor拡張やったことある
    • ScritableObjectつくったことある
  • ChatGPT使ったことある
    • 雰囲気知っていればOK

できたもの

エディタ拡張で対話

UI上で会話

難しい問題「彼女らしさ」

AI彼女Botを作るにあたって「彼女らしさ」をどう引き出すが大事だと思っています。例えば、ChatGPTのサービスに

image.png

「やっほー今起きた」

と送って

「こんにちは!おはようございます。朝早起きは健康的な習慣ですね。今日は何か特別な予定がありますか?」

というアシスタント風で返されると、ちょっとテンション上がらないですよね。この彼女風にしゃべってもらうために、どう調整するかが肝になります。

  • 「彼女らしさ」を発揮しながらしゃべるように、promptを仕込む
    • 丁寧語を辞めるためには
    • 長すぎる文章をやめてもらうには
    • ライトな口調でしゃべってもらうためには
  • promptを何度も試しやすいようにする

この2つを、この記事では紹介します。

解決策

  • System Contextをいじれるようにする (彼女らしさを作り出す命令)
  • UserProfileで個人情報を入力する (名前を呼んでもらえるようにする)

image.png

あなたは19歳のuserのガールフレンドとしてuserに話しかけます。付き合って2年目です。語尾に"!"か"w"か"~"をつけて、丁寧語と敬語を使わないでください。レスポンスは50文字以内にしてください。(ARGirlProfileの中身)

ChatGPTGame - ChatGPTTest - Windows, Mac, Lissnux - .png

こんな感じで、イテレーションを回しやすくします。

やってみて気づき

  • 構文
    • あなたは○○としてuserに話しかけます。
    • 語尾は○○です。
  • 丁寧語を辞めてもらうために
    • 19歳 (年齢下げないと、アシスタント口調に寄ってしまう)
    • ガールフレンド (彼女、だと代名詞と間違われるのか、丁寧語になってしまうので、ガールフレンドという表現)
    • 付き合って2年目 (効果があるかはわからないが、入れてからいい感じになった気がする)
    • 語尾に"!"か"w"か"~"をつけて (気軽に効果が出やすい。お好みでチャレンジ)
  • 文字数を減らすために
    • レスポンスは50文字以内 (なのに、平気で超えてくる)

実装パート

参考資料

ChatGPT APIをUnityから動かす。のはこちらの記事で環境構築おねがいします。このnoteを行っている前提で、この記事は書かれています。

彼女らしさを作り出すsystem role

ChatGPTのAPIにて、Messageを送るときに「role」と「content」があります。

  • role
    • system ★今日はココ
      • アシスタントの行動を設定します。
    • user
      • アシスタントに指示するのに使います。エンドユーザーや開発者が設定します。
    • assistant
      • 事前の反応を保存するのに役立ちます。また、開発者が書き込むことで、望ましい動作の例を示すのに役立ちます。
  • content
    • メッセージの中身

このsystemをroleにしてcontentを送る処理をすると、振る舞いが彼女らしさに近づいてきます。

すっごい結論的なコード (追記)

negipoyocさんのnote記事の以下のコードのcontentの中身を変更すればよいです

   _messageList.Add(new ChatGPTMessageModel(){role = "system",content = "語尾に「にゃ」をつけて"});

それを、ScritableObjectから変更できるようにして、Editor拡張などで叩けるようにしたのが本記事です。なので面倒くさいことをしているかもしれません。
さくっと試したい方は上記のcontentの中身の文字列を、ご自身で変更するコードを書いてください。

ポイントは、role="system"となっているところです。これによりアシスタントの行動を設定します。

実装コード一部

Enum

Enum
    public enum Role
    {
        system,
        user,
        assistant
    }

ChatGPTConnectClient.cs

ChatGPTConnectClient.cs

using System;
using System.Collections.Generic;
using System.Text;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

public class ChatGPTConnectClient
{
    private readonly string _apiKey;
    private readonly List<ChatGPTMessageModel> _messageList = new List<ChatGPTMessageModel>();

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

    // ここで彼女ふるまいを仕込む!
    public void SetAIGirlProfile(AIGirlProfile profile)
    {
        if (profile.systemContext != String.Empty)
        {
            AddMessage(Role.system,profile.systemContext);
        }
    }

    public void SetUserProfile(UserProfile profile)
    {

        string message = $"自己紹介をします!私の名前は{profile.myName}です。" +
                         $"性別は{profile.gender}です。" +
                         $"ニックネームは{profile.nickName}です。" +
                         $"誕生日は{profile.dateOfBirth}{profile.age}です。" +
                         $"出身は{profile.birthplace}で、現在は{profile.address}に住んでいます。" +
                         $"趣味は{profile.interest}です。" +
                         $"職業は{profile.occupation}です。" +
                         $"好きな食べ物は{profile.favoriteFood}です。" +
                         $"TwitterのIDは@{profile.TwitterID}";
        AddMessage(Role.user,message);
    }
    void AddMessage(Role role, string contennt)
    {
        AddMessage(new ChatGPTMessageModel {role = role.ToString(), content = contennt});
    }
    void AddMessage(ChatGPTMessageModel model)
    {
        SaveChat.AddChat(model);
        _messageList.Add(model);
    }
    public async UniTask<ChatGPTResponseModel> RequestAsync(string userMessage)
    {
        var apiUrl = "https://api.openai.com/v1/chat/completions";
        AddMessage(Role.user, userMessage);
        //OpenAIのAPIリクエストに必要なヘッダー情報を設定
        var headers = new Dictionary<string, string>
        {
            {"Authorization", "Bearer " + _apiKey},
            {"Content-type", "application/json"},
            {"X-Slack-No-Retry", "1"}
        };
        
        //文章生成で利用するモデルやトークン上限、プロンプトをオプションに設定
        var options = new ChatGPTCompletionRequestModel()
        {
            model = "gpt-3.5-turbo",
            messages = _messageList
        };
        var jsonOptions = JsonUtility.ToJson(options);
        Debug.Log("自分:" + userMessage);
        
        //OpenAIの文章生成(Completion)にAPIリクエストを送り、結果を変数に格納
        using var request = new UnityWebRequest(apiUrl, "POST")
        {
            uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(jsonOptions)),
            downloadHandler = new DownloadHandlerBuffer()
        };
        foreach (var header in headers)
        {
            request.SetRequestHeader(header.Key, header.Value);
        }
        await request.SendWebRequest();
        
        if (request.result == UnityWebRequest.Result.ConnectionError ||
            request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError(request.error);
            throw new Exception();
        }
        else
        {
            var responseString = request.downloadHandler.text;
            var responseObject = JsonUtility.FromJson<ChatGPTResponseModel>(responseString);
            Debug.Log("ChatGPT:" + responseObject.choices[0].message.content);
            AddMessage(responseObject.choices[0].message);
            return responseObject;
        }
    }
}

AIGirlProfile (ScritableObject)

AIGirlProfile
using UnityEngine;

[CreateAssetMenu(fileName = "AIGirlProfile", menuName = "ScriptableObjects/AIGirlProfile", order = 1)]
public class AIGirlProfile : ScriptableObject
{
    [TextArea]
    public string systemContext;
}

これを作ると右クリックでAIGirlProfileをつくることができるようになります。

image.png

AIGirlBot.cs
using System;
using Cysharp.Threading.Tasks;
using UnityEngine;

public class AIGirlBot : MonoBehaviour
{
    [SerializeField] private AIGirlProfile aiGirlProfile;
    [SerializeField] private UserProfile userProfile;
    public string sendMessage,responseMessge;
    private ChatGPTConnectClient client;

    void Start()
    {
        client = new ChatGPTConnectClient(config.apiKey);
        client.SetAIGirlProfile(aiGirlProfile);
        client.SetUserProfile(userProfile);
    }
    public async UniTask<ChatGPTResponseModel> SendMessage(string userMessage)
    {
        sendMessage = userMessage;
        responseMessge = "書き込み中...";
        var response = await client.RequestAsync(sendMessage);
        return response;
    }

    public async void SendGPT()
    {
        responseMessge = "書き込み中...";
        var response = await client.RequestAsync(sendMessage);
        responseMessge = response.choices[0].message.content;
    }
}

Editor拡張から送信!

AIGirlBotEditor.csをEditorフォルダ以下に置く。

AIGirlBotEditor.cs
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(AIGirlBot))]
public class ChatGPTEditor : Editor
{
    public override void OnInspectorGUI(){
        //targetを変換して対象を取得
        AIGirlBot chatGpt = target as AIGirlBot;
        
 
        //元のInspector部分を表示
        base.OnInspectorGUI ();
        
        EditorGUILayout.LabelField("私のメッセージ");
        chatGpt.sendMessage = EditorGUILayout.TextArea(chatGpt.sendMessage, GUILayout.Height(EditorGUIUtility.singleLineHeight * 3));
      

        if (GUILayout.Button("AI彼女に送信!")){
            chatGpt.SendGPT();
        }
        EditorGUILayout.LabelField("AI彼女のメッセージ");
        EditorGUILayout.LabelField(chatGpt.responseMessge, EditorStyles.wordWrappedLabel);
    }
}

こうすると、AIGirlBotを見ると、ボタンが登場します!
image.png

UIの実装

また今度!

今後やりたい事

  • キャラクターのビジュアルも込みで実現
  • Promptの仕込みのチューニング
    • Assistant roleで理想の会話を仕込む

最後に

ざくっと記事を書いてしまったので、わかりにくかった人もいるかもしれないです。コメントで感想を教えていただけるとありがたいです。

6
4
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
6
4