LoginSignup
2
3

More than 1 year has passed since last update.

【Live2D + Unity + ChatGPT】CatGPT作ったよ

Last updated at Posted at 2023-04-08

猫のChatGPT
名付けて、CatGPT を作りました。

OpenAI

OpenAIのAPIキーを取得する。
こちらを参照
https://qiita.com/tatsuya1970/items/c04cb7b6d07c4cf51007#3-openai

Live2D

まずは、UnityHubで "2D" のプロジェクトを新規作成します。
Image from Gyazo

Unityが立ち上がったら、
2次元のイラストを自由に動かすことができるLive2DのSDKである「Cubism SDK for Unity」をプロジェクトにインポートします。

ダウンロードはこちらから
https://www.live2d.com/download/cubism-sdk/download-unity/

こんなエラーが出ますが、多分無視して大丈夫と思います。

ArgumentNullException: Value cannot be null.
Parameter name: shader

Live2Dのウェブサイトからキャラクターをダウンロードします、
https://www.live2d.com/download/sample-data/

初音ミクなどありますが、
今回はCatGPTなので「黒猫のひじき」をダウンロード。

そして、ダウンロードしたキャラクターのフォルダごとUnity の Project にそのままドラッグします。

Prefab が生成されるので、Sceneに適当に置きます。

Image from Gyazo


Unityの設定

UI

こんな画面にします。
Image from Gyazo

UIを設置します。
Image from Gyazo

あとで自分に分かるように名前を変えました。
Image from Gyazo

アニメーション

「黒猫のひじき」の8個のモーション全部を 黄色のノード(Idle) に繋げる。
モーションの名前や左側のParameterの名前は1からの8数字にした。
(今回はランダムでモーションを選ぶためモーションの名前が数字の方がコーディングしやすい)
 
Image from Gyazo

Idle と各モーションの Inspector は
Idle -> 各モーション

Condition を true に設定
Image from Gyazo

モーション -> Idle はデフォルトのまま

スクリプト

汚いコードですが晒します。

今どきは、UniTaskやCoroutineを使わずasync/await とかを使うのでしょうけど・・・

まず、JSON Object アセットをインストールします。
https://assetstore.unity.com/packages/tools/input-management/json-object-710?locale=ja-JP

で、以下のスクリプトを入力

answer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System;
using Defective.JSON;
using TMPro;

public class answer : MonoBehaviour
{
    private Animator animator;
    public Button button;          // OKボタン
    public GameObject inputField;  //ユーザー入力するフィールド

    [SerializeField] 
    TextMeshProUGUI responseText;

    //OpenAIのAPIにリクエストするとき必要
    [Serializable]
    public class body
    {
        public string model;  
        public Transfers[] messages;
    }

    [Serializable]
    public class Transfers
    {
        public string role;
        public string content;
    }

    public void OnClick()
    {
        animator = GameObject.Find("hijiki").GetComponent<Animator>();

        //ユーザーが投稿した内容を取得
        string mes = inputField.GetComponent<Text>().text;

        var url = "https://api.openai.com/v1/chat/completions";

        // ボットの性格を設定
        string chara = "あなたは猫ですが人間の言葉も理解できます。語尾に「にゃ」をつけるなど猫っぽい話し方をしてください。";

        string itemJson 
            = "{ \"model\": \"gpt-3.5-turbo\"," +
            "\"messages\": [" +
            "{ \"role\": \"system\", \"content\": \"" + chara +"\"}," +
            "{ \"role\": \"user\", \"content\": \"" + mes + "\"}]}";

        body item = JsonUtility.FromJson<body>(itemJson);

        string serialisedItemJson = JsonUtility.ToJson(item);
        // Debug.Log("serialisedItemJson " + serialisedItemJson);

        StartCoroutine(post(url, serialisedItemJson));
    }


    private IEnumerator post(string url, string body)
    {
        var request = new UnityWebRequest(url, "POST");
        byte[] postData = System.Text.Encoding.UTF8.GetBytes(body);

        request.uploadHandler = new UploadHandlerRaw(postData);
        request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");
        // OpenAi のAPIキー
        request.SetRequestHeader("Authorization", "Bearer OpenAIのAPIキー");

        yield return request.SendWebRequest();

        // 通信エラーチェック
        if (request.isNetworkError)
        {
            Debug.Log(request.error);
            animator.SetBool("2", true); //機嫌が悪いアニメーション
            yield return new WaitForSeconds(0.8f);
            animator.SetBool("2", false);
        }
        else
        {
            Debug.Log(request.responseCode);
            if (request.responseCode == 200 || request.responseCode == 201)
            {
                string text = request.downloadHandler.text;
                Debug.Log(text);
                JSONObject json = new JSONObject(text);
                JSONObject choices = json.GetField("choices");
                JSONObject message = choices[0].GetField("message");

                string content = message.GetField("content").ToString();
                Debug.Log(content);           
                string motion = UnityEngine.Random.Range(1,9).ToString();  //モーションをランダムで選ぶ
                animator.SetBool(motion, true);
                responseText.text =  content;
                yield return new WaitForSeconds(3.0f);
                animator.SetBool(motion, false);            
            }
            else
            {
                responseText.text = request.responseCode + "エラーだよ!!\nどこかが間違ってるよ。";
                Debug.Log("エラー");
                animator.SetBool("2", true); //機嫌が悪いモーション
                yield return new WaitForSeconds(0.8f);
                animator.SetBool("2", false);
                yield return new WaitForSeconds(3.0f);
           }
       }
   }
}

(コード説明) 猫のキャラクター設定

上のコードの中間部分の変数charaで指定してます。
該当部分を抽出しますと、

string chara = "あなたは猫ですが人間の言葉も理解できます。語尾に「にゃ」をつけるなど猫っぽい話し方をしてください。";

string itemJson 
    = "{ \"model\": \"gpt-3.5-turbo\"," +
      "\"messages\": [" +
      "{ \"role\": \"system\", \"content\": \"" + chara +"\"}," +
      "{ \"role\": \"user\", \"content\": \"" + mes + "\"}]}";

なお、今回は記憶を持たせてないので、しりとりとか連続性のある話はできません。 記憶といっても、今までの会話の内容(JSON)を Add していくのだと思うのですが、もっと他にいいやり方もありそうだし、次回の課題にします。

Inspector の設定

最後に Button のInspector を以下のように設定。

Image from Gyazo

以上です。



※本作品のキャラクターには株式会社Live2Dの著作物であるサンプルデータが株式会社Live2Dの定める規約に従って用いられています。本作品は制作者の完全な自己の裁量で制作されています。

2
3
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
2
3