{"id":13642127,"url":"https://github.com/uezo/chatdollkit","last_synced_at":"2025-04-14T06:49:00.776Z","repository":{"id":40333275,"uuid":"248977013","full_name":"uezo/ChatdollKit","owner":"uezo","description":"ChatdollKit enables you to make your 3D model into a chatbot","archived":false,"fork":false,"pushed_at":"2025-03-29T13:40:56.000Z","size":118651,"stargazers_count":871,"open_issues_count":28,"forks_count":88,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-04-10T03:55:53.908Z","etag":null,"topics":["3d-model","azure","chatbot","chatgpt","gpt-3","unity","unity3d","virtualassistant"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uezo.png","metadata":{"files":{"readme":"README.ja.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-21T13:01:53.000Z","updated_at":"2025-04-07T04:16:07.000Z","dependencies_parsed_at":"2023-01-30T20:31:12.029Z","dependency_job_id":"eab939cd-9cbf-4f0a-8476-f150790cdb85","html_url":"https://github.com/uezo/ChatdollKit","commit_stats":{"total_commits":567,"total_committers":2,"mean_commits":283.5,"dds":"0.0017636684303351524","last_synced_commit":"f972cfa9b111e15d3ea6782b66eaaa655e06077f"},"previous_names":[],"tags_count":54,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uezo%2FChatdollKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uezo%2FChatdollKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uezo%2FChatdollKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uezo%2FChatdollKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uezo","download_url":"https://codeload.github.com/uezo/ChatdollKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837273,"owners_count":21169373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-model","azure","chatbot","chatgpt","gpt-3","unity","unity3d","virtualassistant"],"created_at":"2024-08-02T01:01:27.855Z","updated_at":"2025-04-14T06:49:00.748Z","avatar_url":"https://github.com/uezo.png","language":"C#","funding_links":[],"categories":["Chatbots"],"sub_categories":[],"readme":"﻿# ChatdollKit\nChatdollKitは、お好みの3Dモデルを使って音声対話可能なチャットボットを作るためのフレームワークです。 [🇬🇧README in English is here](https://github.com/uezo/ChatdollKit/blob/master/README.md)\n\n- [🐈 Live demo](https://unagiken.blob.core.windows.net/chatdollkit/ChatdollKitDemoWebGL/index.html) WebGLのデモです。「こんにちは」と話しかけると会話がスタートします。マルチリンガルなので、言語を切り替えたいときは「英語で話そう」といったようにリクエストしてみてください。\n- [🍎 iOS App: おしゃべりAI](https://apps.apple.com/ja/app/oshaberiai/id6446883638) プロンプトでキャラメイク×VRMでお好みの3Dモデル×VOICEVOXでお好みの声でおしゃべりできるバーチャルエージェントアプリ。ChatdollKitで開発。\n\n\u003cimg src=\"https://uezo.blob.core.windows.net/github/chatdoll/chatdollkit-overview-080beta.png\" width=\"720\"\u003e\n\n## ✨ 主な特長\n\n- **生成AI対応**: ChatGPT、Anthropic Claude、Google Gemini Pro、Difyなど、複数のLLMをサポートし、ファンクションコーリング（ChatGPT/Gemini）やマルチモーダル機能にも対応\n- **3Dモデル表現**: 発話とモーションの同期、表情やアニメーションの自律制御、瞬きや口の動きの同期をサポート\n- **対話制御**: 音声認識と音声合成（OpenAI、Azure、Google、Watson、VOICEVOX / AivisSpeech、Style-Bert-VITS2、にじボイスなど）の統合、対話状態（コンテキスト）の管理、意図抽出とトピックのルーティング、ウェイクワード検出をサポート\n- **マルチプラットフォーム**: Windows、Mac、Linux、iOS、Android、およびその他のUnityサポートプラットフォーム（VR、AR、WebGLを含む）に対応\n\n\n## 💎 バージョン0.8.10の新機能\n\n- **🌏 ダイナミック多言語切り替え**: 話す・聞くの双方について、使用する言語を会話の中で自律的に切り替えられるようになりました。\n- **🔖 長期記憶**: 過去の会話の内容を蓄積・検索できるようになりました。[ChatMemory](https://github.com/uezo/chatmemory)用のコンポーネントを提供していますが、mem0やZepなどに対応することもできます。\n\n---\n\n### 以前の更新内容\n\n#### 0.8.8および0.8.9\n\n- **✨ にじボイスのサポート**: AIによる感情豊かな音声生成サービス「にじボイス」のAPIが利用できるようになりました。\n- **🥰🥳 複数AITuber同士の会話**: AITuber同士が会話できるように！今までにない配信スタイルを楽しみましょう。\n- **💪 Difyを活用したAITuber**: あらゆるLLMへの対応はもちろん、ナレッジや機能を兼ね備えたAgenticなAITuberを高い運用性をもって実現できるように！\n\n\n#### 0.8.7\n\n- **✨ Update AITuber demo**: より多くのAPI、一括設定、UI操作などをサポートしました。\n\n\n#### 0.8.6\n\n- **🎛️ VOICEVOXとAivisSpeechの動的スタイル切り替え**: 声のスタイルを動的かつ自律的に切り替えることで、キャラクター表現を豊かにし、感情のニュアンスに対応できるようになりました。\n- **🥰 VRMランタイム読み込みの改善**: ランタイムでエラーなく3Dモデルをシームレスに切り替えられるようになり、ユーザー体験が向上しました。\n\n\n#### 0.8.5\n\n- **🎓 Chain of Thought Prompting**: Chain of Thought (CoT) プロンプティングに対応しました 🎉 AIキャラクターの思考力や感情コントロールの力を大幅にブーストすることができます。\n\n\n#### 0.8.4\n\n- **🧩 モジュール化による再利用性と保守性の向上**: 主要なコンポーネントをリファクタリングしました。モジュラー化によりユーザーによるカスタマイズ性が向上したほか、コードの再利用性も高まりました。詳細はデモをご確認ください。\n- **🧹 レガシーコンポーネントの削除**: v0.7.x以前で使用していたコンポーネントを削除し、全体がシンプルになりました。v0.7.xからアップデートする場合は[🔄 Migration from 0.7.x](#-migration-from-07x)をご参照ください。\n\n\n#### 0.8.3\n\n- **🎧 Stream Speech Listener**: 音声を逐次認識する`AzureStreamSpeechLister`を追加し、会話をよりスムーズなものにしました。\n- **🗣️ Improved Conversation**: キャラクターの発話を停止するInterrupt Wordsや会話に「間」を挿入する機構を追加し、会話体験をより自然で豊かなものにしました。\n- **💃 Easier Animation Registration**: キャラクターが利用するアニメーションの登録方法を簡易化し、ユーザーコードをより簡潔にできるようにしました。\n\n\n#### 0.8.2\n\n- **🌐 JavaScriptによるWebGLキャラクター制御**: WebGLビルドで実行されるChatdollKit UnityアプリケーションをJavaScriptから制御できるようになりました。これにより、Unityアプリとウェブベースのシステム間でよりシームレスな連携が可能になります。\n- **🗣️ SpeechSynthesizerの導入**: テキスト読み上げ（TTS）のための新しい`SpeechSynthesizer`コンポーネントが導入されました。このコンポーネントは`Model`パッケージに依存せず、プロジェクト間で再利用可能なため、キャラクター対話以外のあらゆるユースケースで利用することができます。\n\n\n#### 0.8.1\n\n- **🏷️ ユーザー定義タグのサポート**: AIの応答にカスタムタグを含めることができるようになり、動的なアクションが可能になりました。例えば、会話中に複数の言語を切り替えるために、応答に言語コードを埋め込むことができます。\n- **🌐 ソケットを介した外部制御**: ソケット通信を通じた外部コマンドをサポートするようになりました。会話の流れを指示したり、特定のフレーズをトリガーしたり、表情やジェスチャーを制御したりすることができ、AI Vtuberやリモートカスタマーサービスなどの新しいユースケースが可能になります。クライアント側のデモはこちら：https://gist.github.com/uezo/9e56a828bb5ea0387f90cc07f82b4c15\n\n#### 0.8 Beta\n\n- **⚡ AI対話処理の最適化**: 並列処理によってレスポンス速度を向上させ、独自のコードでの動作のカスタマイズも容易になりました。より高速で柔軟なAI会話をお楽しみください！\n- **🥰 感情豊かな発話**: 会話に合わせて声のトーンを動的に調整し、よりエンゲージングで自然な対話を実現します。\n- **🎤 マイク制御の強化**: マイク制御がこれまで以上に柔軟になりました！デバイスの開始/停止、ミュート/アンミュート、音声認識のしきい値調整を個別に簡単に行えます。\n\n\n## 🚀 クイックスタート\n\nセットアップ手順についてはこちらの動画をご覧いただくとより簡単に理解できます。ChatGPTと会話するデモシーンを動かせるまでの手順です: https://www.youtube.com/watch?v=rRtm18QSJtc\n\n[![](https://img.youtube.com/vi/rRtm18QSJtc/0.jpg)](https://www.youtube.com/watch?v=rRtm18QSJtc)\n\nバージョン0.8のデモを実行するには、依存関係をインポートした後、以下の手順に従ってください：\n\n- シーン `Demo/Demo08` を開きます。\n- シーン内の `AIAvatarVRM` オブジェクトを選択します。\n- インスペクタで以下のコンポーネントにOpenAI APIキーを設定します：\n  - ChatGPTService\n  - OpenAISpeechSynthesizer\n  - OpenAISpeechListener\n- Unityエディタで実行します。\n- 「こんにちは」または3文字以上の単語を話しかけます。\n\n\n## 🔖 もくじ\n\n- [📦 新規プロジェクトのセットアップ](#-新規プロジェクトのセットアップ)\n  - [依存関係のインポート](#依存関係のインポート)\n  - [リソースの準備](#リソースの準備)\n  - [AIAvatarVRMプレハブ](#aiavatarvrmプレハブ)\n  - [ModelController](#modelcontroller)\n  - [Animator](#animator)\n  - [AIAvatar](#aiavatar)\n  - [LLMサービス](#llmサービス)\n  - [音声サービス](#音声サービス)\n  - [マイクコントローラー](#マイクコントローラー)\n  - [実行](#実行)\n- [🎓 LLM Service](#-llm-service)\n  - [基本設定](#基本設定)\n  - [表情](#表情)\n  - [アニメーション](#アニメーション)\n  - [Pause in Speech](#pause-in-speech)\n  - [User Defined Tag](#user-defined-tag)\n  - [Multi Modal](#multi-modal)\n  - [Chain of Thought Prompting](#chain-of-thought-prompting)\n  - [Long-Term Memory](#long-term-memory)\n- [🗣️ Speech Synthesizer (Text-to-Speech)](#-speech-synthesizer-text-to-speech)\n  - [Voice Prefetch Mode](#voice-prefetch-mode)\n  - [Make custom SpeechSynthesizer](#make-custom-speechsynthesizer)\n  - [Performance and Quality Tuning](#performance-and-quality-tuning)\n- [🎧 Speech Listener (Speech-to-Text)](#-speech-listener-speech-to-text)\n  - [Settings on AIAvatar Inspector](#settings-on-aiavatar-inspector)\n  - [Using AzureStreamSpeechListener](#using-azurestreamspeechlistener)\n- [⏰ Wake Word Detection](#-wake-word-detection)\n  - [Wake Words](#wake-words)\n  - [Cancel Words](#cancel-words)\n  - [Interrupt Words](#interrupt-words)\n  - [Ignore Words](#ignore-words)\n  - [Wake Length](#wake-length)\n- [⚡️ AI Agent (Tool Call)](#-ai-agent-tool-call)\n- [🎙️ Devices](#-devices)\n  - [Microphone](#microphone)\n  - [Camera](#camera)\n- [💃 ３D Model Control](#-３d-model-control)\n  - [Idle Animations](#idle-animations)\n  - [Control by Script](#control-by-script)\n- [🎚️ UI Components](#-ui-components)\n- [🎮 Control from External Programs](#-control-from-external-programs)\n  - [ChatdollKit Remote Client](#chatdollkit-remote-client)\n- [🌐 WebGLでの実行](#-webglでの実行)\n- [🔄 Migration from 0.7.x](#-migration-from-07x)\n- [❤️ 謝辞](#-謝辞)\n\n\n## 📦 新規プロジェクトのセットアップ\n\nVRMモデルを使用したセットアップの手順は以下の通りです。VRChatのモデルを使用する場合の手順は、[README v0.7.7](https://github.com/uezo/ChatdollKit/blob/v0.7.7/README.md#-modelcontroller)を参照してください。\n\n**⚠️注意**: UnityのSRP (Scriptable Render Pipeline) プロジェクトテンプレートは使用しないでください。ChatdollKitが使用するUniVRMがSRPをサポートしていません。\n\n### 依存関係のインポート\n\n最新版の[ChatdollKit.unitypackage](https://github.com/uezo/ChatdollKit/releases)をダウンロードし、以下の依存関係をインポートした後、Unityプロジェクトにインポートしてください：\n\n- Unity Package Manager（ウィンドウ \u003e パッケージマネージャー）から `Burst`\n- [UniTask](https://github.com/Cysharp/UniTask)（Ver.2.5.4でテスト済み）\n- [uLipSync](https://github.com/hecomi/uLipSync)（v3.1.0でテスト済み）\n- [UniVRM](https://github.com/vrm-c/UniVRM/releases/tag/v0.127.2)(v0.127.2)\n- [ChatdollKit VRM Extension](https://github.com/uezo/ChatdollKit/releases)\n- JSON.NET: プロジェクトにJSON.NETがない場合、パッケージマネージャーから[+] \u003e gitのURLからパッケージを追加... \u003e com.unity.nuget.newtonsoft-jsonを追加してください\n- [Azure Speech SDK](https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/quickstarts/setup-platform?pivots=programming-language-csharp\u0026tabs=macos%2Cubuntu%2Cdotnetcli%2Cunity%2Cjre%2Cmaven%2Cnodejs%2Cmac%2Cpypi#install-the-speech-sdk-for-unity): （オプション）ストリームを使用したリアルタイム音声認識（`AzureStreamSpeechListener`）に必要です\n\n\u003cimg src=\"Documents/Images/burst.png\" width=\"640\"\u003e\n\n### リソースの準備\n\n3Dモデルをシーンに追加し、好みに合わせて調整します。また、シェーダーなど、3Dモデルに必要なリソースをインストールします。\n\nそして、アニメーションクリップをインポートします。このREADMEでは、デモでも使用されている[Anime Girls Idle Animations Free](https://assetstore.unity.com/packages/3d/animations/anime-girl-idle-animations-free-150406)を使用します。プロ版の購入をおすすめします👍\n\n### AIAvatarVRMプレハブ\n\n`ChatdollKit/Prefabs/AIAvatarVRM`プレハブをシーンに追加します。また、UIコンポーネントを使用するためにEventSystemを作成します。\n\n\u003cimg src=\"Documents/Images/readme081/01_aiavatar_prefab.png\" width=\"640\"\u003e\n\n### ModelController\n\nModelControllerのコンテキストメニューから`Setup ModelController`を選択します。\n\n\u003cimg src=\"Documents/Images/readme081/02_setup_modelcontroller.png\" width=\"640\"\u003e\n\n### Animator\n\nModelControllerのコンテキストメニューから`Setup Animator`を選択し、アニメーションクリップを含むフォルダまたはその親フォルダを選択します。この場合、`01_Idles`と`03_Others`のアニメーションクリップをオーバーライドブレンディング用に`Base Layer`に、`02_Layers`をアディティブブレンディング用に`Additive Layer`に配置します。\n\n\u003cimg src=\"Documents/Images/readme081/03_cdk_setup_animator.gif\" width=\"640\"\u003e\n\n次に、選択したフォルダに新しく作成されたAnimatorControllerの`Base Layer`を確認します。アイドルアニメーションとして設定したい状態への遷移の値を確認します。\n\n\u003cimg src=\"Documents/Images/readme081/04_check_idle_animation.png\" width=\"640\"\u003e\n\n最後に、ModelControllerのインスペクタで`Idle Animation Value`にその値を設定します。\n\n\u003cimg src=\"Documents/Images/readme081/05_set_idle_animation_param.png\" width=\"640\"\u003e\n\n### AIAvatar\n\n`AIAvatar`のインスペクタで、会話を開始するための`Wake Word`（例：hello / こんにちは🇯🇵）、会話を停止するための`Cancel Word`（例：stop / おしまい🇯🇵）、エラー発生時に表示される`Error Voice`と`Error Face`（例：Something wrong / 調子が悪いみたい🇯🇵）を設定します。\n\n`Prefix / Suffix Allowance`は、ウェイクワードの前後に許容される追加文字の長さです。例えば、ウェイクワードが\"Hello\"で、許容値が4文字の場合、\"Ah, Hello!\"という語句もウェイクワードとして検出されます。\n\n\u003cimg src=\"Documents/Images/readme081/06_setup_ai_avatar.png\" width=\"640\"\u003e\n\n### LLMサービス\n\n`ChatdollKit/Scripts/LLM`から対応するLLMサービスのコンポーネントをアタッチし、APIキーやシステムプロンプトなどの必要なフィールドを設定します。この例ではChatGPTを使用していますが、フレームワークはClaude、Gemini、Difyもサポートしています。\n\n\u003cimg src=\"Documents/Images/readme081/07_setup_chatgpt.png\" width=\"640\"\u003e\n\n### 音声サービス\n\n音声認識用に`ChatdollKit/Scripts/SpeechListener`から`SpeechListener`コンポーネントを、音声合成用に`ChatdollKit/Scripts/SpeechSynthesizer`から`SpeechSynthesizer`コンポーネントをアタッチします。APIキーや言語コードなどの必要なフィールドを設定します。SpeechListenerの設定で`PrintResult`を有効にすると、認識された音声がログに出力され、デバッグに役立ちます。\n\n\u003cimg src=\"Documents/Images/readme081/08_setup_speech.png\" width=\"640\"\u003e\n\n### マイクコントローラー\n\n`ChatdollKit/Prefabs/Runtime/MicrophoneController`をシーンに追加します。これにより、音声認識の最小音量を調整するUIが提供されます。周囲が騒がしい場合、スライダーを左にスライドさせることで騒音をフィルタリングできます。\n\n\u003cimg src=\"Documents/Images/readme081/09_add_microphone_controller.png\" width=\"640\"\u003e\n\n### 実行\n\nUnityエディタの再生ボタンを押します。キャラクターが待機アニメーションと瞬きを開始するのが確認できます。\n\n- 必要に応じてマイクの音量スライダーを調整します。\n- インスペクタで設定した`Wake Word`を話します（例：hello / こんにちは🇯🇵）。\n- キャラクターが \"こんにちは！元気？\" などと返事してくれます。\n\n\u003cimg src=\"Documents/Images/readme081/10_run.png\" width=\"640\"\u003e\n\nEnjoy👍\n\n\n## 🎓 LLM Service\n\n### 基本設定\n\nテキスト生成AIサービスとして、ChatGPT、Claude、Gemini、そしてDifyをサポートしています。試験的にCommand Rにも対応していますが、動作が安定しません。\nLLMサービスを使用するには、`ChatdollKit/Scripts/LLM`から該当するLLMServiceコンポーネントをAIAvatarオブジェクトにアタッチして、`IsEnabled`にチェックを入れてください。すでに他のLLMServiceがアタッチされている場合、使用しないLLMServiceの`IsEnabled`はチェックを外す必要がある点に注意してください。\n\nアタッチしたLLMServiceには、APIキーやシステムプロンプトをはじめとして、その他パラメーターをインスペクター上で設定することができます。これらのパラメーターの意味や設定すべき値等についてはLLMのAPIリファレンスを参照してください。\n\n\n### 表情\n\n会話の内容に合わせて、自律的に表情をコントロールすることができます。\n表情をコントロールするには、AIからの応答に`[face:表情名]`といったタグを含ませる必要があり、システムプロンプト等にその指示を含むことで実現することができます。以下はそのシステムプロンプトの例です。\n\n```\nYou have four expressions: 'Joy', 'Angry', 'Sorrow', 'Fun' and 'Surprised'.\nIf you want to express a particular emotion, please insert it at the beginning of the sentence like [face:Joy].\n\nExample\n[face:Joy]Hey, you can see the ocean! [face:Fun]Let's go swimming.\n```\n\n表情の名前は、AIがそれからどのような表情なのか理解できる必要があります。\nまた、VRMモデルに定義された表情をそのまま操作しますので、大文字小文字の違いも含めて一致させるようにしてください。\n\n\n### アニメーション\n\n会話の内容に合わせて、自律的に身振り手振り（以降、アニメーションといいます）をコントロールすることができます。\nアニメーションをコントロールするには、AIからの応答に`[anim:アニメーション名]`といったタグを含ませる必要があり、システムプロンプト等にその指示を含むことで実現することができます。以下はそのシステムプロンプトの例です。\n\n```\nYou can express your emotions through the following animations:\n\n- angry_hands_on_waist\n- brave_hand_on_chest\n- calm_hands_on_back\n- concern_right_hand_front\n- energetic_right_fist_up\n- energetic_right_hand_piece\n- pitiable_right_hand_on_back_head\n- surprise_hands_open_front\n- walking\n- waving_arm\n- look_away\n- nodding_once\n- swinging_body\n\nIf you want to express emotions with gestures, insert the animation into the response message like [anim:waving_arm].\n\nExample\n[anim:waving_arm]Hey, over here!\n```\n\nアニメーションの名前は、AIがそれからどのような身振り手振りなのか理解できる必要があります。\nまた、指定されたアニメーション名と`Animator Controller`に定義されたアニメーションを紐づけるため、以下の通り任意の箇所でコードベースで`ModelController`に登録する必要があります。\n\n```csharp\n// Base\nmodelController.RegisterAnimation(\"angry_hands_on_waist\", new Model.Animation(\"BaseParam\", 0, 3.0f));\nmodelController.RegisterAnimation(\"brave_hand_on_chest\", new Model.Animation(\"BaseParam\", 1, 3.0f));\nmodelController.RegisterAnimation(\"calm_hands_on_back\", new Model.Animation(\"BaseParam\", 2, 3.0f));\nmodelController.RegisterAnimation(\"concern_right_hand_front\", new Model.Animation(\"BaseParam\", 3, 3.0f));\nmodelController.RegisterAnimation(\"energetic_right_fist_up\", new Model.Animation(\"BaseParam\", 4, 3.0f));\nmodelController.RegisterAnimation(\"energetic_right_hand_piece\", new Model.Animation(\"BaseParam\", 5, 3.0f));\nmodelController.RegisterAnimation(\"pitiable_right_hand_on_back_head\", new Model.Animation(\"BaseParam\", 7, 3.0f));\nmodelController.RegisterAnimation(\"surprise_hands_open_front\", new Model.Animation(\"BaseParam\", 8, 3.0f));\nmodelController.RegisterAnimation(\"walking\", new Model.Animation(\"BaseParam\", 9, 3.0f));\nmodelController.RegisterAnimation(\"waving_arm\", new Model.Animation(\"BaseParam\", 10, 3.0f));\n// Additive\nmodelController.RegisterAnimation(\"look_away\", new Model.Animation(\"BaseParam\", 6, 3.0f, \"AGIA_Layer_look_away_01\", \"Additive Layer\"));\nmodelController.RegisterAnimation(\"nodding_once\", new Model.Animation(\"BaseParam\", 6, 3.0f, \"AGIA_Layer_nodding_once_01\", \"Additive Layer\"));\nmodelController.RegisterAnimation(\"swinging_body\", new Model.Animation(\"BaseParam\", 6, 3.0f, \"AGIA_Layer_swinging_body_01\", \"Additive Layer\"));\n```\n\nAnimation Girl Idle Animationsまたはその無償版を利用している場合、以下のように簡単に登録することもできます。\n\n```csharp\nmodelController.RegisterAnimations(AGIARegistry.GetAnimations(animationCollectionKey));\n```\n\n\n### Pause in Speech\n\nキャラクターの発話に「間」を挿入することで、会話をより自然で人間らしくすることができます。\n\n「間」の長さを制御するために、システムプロンプトを通じてAIの応答に [pause:秒数] タグを含めます。秒数はfloat値を指定することができ、そのポイントでの間の長さを正確に制御することができます。以下はシステムプロンプトの例です。\n\n```\nYou can insert pauses in the character's speech to make conversations feel more natural and human-like.\n\nExample:\nHey, it's a beautiful day outside! [pause:1.5] What do you think we should do?\n```\n\n\n### User Defined Tag\n\n表情やアニメーション以外に、開発者が定義したタグに応じた処理を実行することができます。\nシステムプロンプトで応答にタグを含ませるための指示をするとともに、`HandleExtractedTags`を実装します。\n\n以下は、会話の内容に合わせて部屋の照明を操作する例です。\n\n\n```\nIf you want switch room light on or off, insert language tag like [light:on].\n\nExample:\n[light:off]OK, I will turn off the light. Good night.\n```\n\n```csharp\ndialogProcessor.LLMServiceExtensions.HandleExtractedTags = (tags, session) =\u003e\n{\n    if (tags.ContainsKey(\"light\"))\n    {\n        var lightCommand = tags[\"light\"];\n        if (lightCommand.lower() == \"on\")\n        {\n            // Turn on the light\n            Debug.Log($\"Turn on the light\");\n        }\n        else if (lightCommand.lower() == \"off\")\n        {\n            // Turn off the light\n            Debug.Log($\"Turn off the light\");\n        }\n        else\n        {\n            Debug.LogWarning($\"Unknown command for light: {lightCommand}\");\n        }\n    }\n};\n```\n\n\n### Multi Modal\n\nLLMへのリクエストにカメラやファイル等から取得した画像を含むことができます。\n`DialogProcessor.StartDialogAsync`の第二引数として`payloads`の中に`imageBytes`というキーで画像のバイナリーデータを含むようにしてください。\n\nまた、ユーザーの発話内容を処理するための画像が必要なときに自律的に画像を取得するようにすることができます。\nAIからの応答に[vision:camera]というタグを含ませるようにシステムプロンプトに設定するとともに、このタグを受け取った際に呼び出される画像取得処理をLLM Serviceに実装してください。\n\n```\nYou can use camera to get what you see.\nWhen the user wants to you to see something, insert [vision:camera] into your response message.\n\nExample\nuser: Look! I bought this today.\nassistant: [vision:camera]Let me see.\n```\n\n```csharp\ngameObject.GetComponent\u003cChatGPTService\u003e().CaptureImage = async (source) =\u003e\n{\n    if (simpleCamera != null)\n    {\n        try\n        {\n            return await simpleCamera.CaptureImageAsync();\n        }\n        catch (Exception ex)\n        {\n            Debug.LogError($\"Error at CaptureImageAsync: {ex.Message}\\n{ex.StackTrace}\");\n        }\n    }\n\n    return null;\n};\n```\n\n\n### Chain of Thought Prompting\n\nChain of Thought (CoT) プロンプティングはAIのパフォーマンスを向上させる手法です。コンセプトとその適用例についてはAnthropicの解説を参照してください。 https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/chain-of-thought .\n\nChatdollKitはこのCoTの手法に、`\u003cthinking\u003e ~ \u003c/thinking\u003e`の中身を読み上げの対象外とすることで対応しています。\n\nまた、`LLMContentProcessor`のインスペクターの`ThinkTag`でタグの中の文字列をカスタマイズすることも可能です（reason、など）。\n\n\n### Long-Term Memory\n\nChatdollKit自体は長期記憶管理の仕組みを持っていませんが、`OnStreamingEnd`を実装することで記憶を蓄積することができ、また、記憶を取得するToolを使用することで蓄積した記憶を思い出して会話に反映することができます。\n\n以下は[ChatMemory](https://github.com/uezo/chatmemory)を使用した例です。\n\nはじめに、記憶を蓄積するための対応です。メインのGameObjectに`Extension/ChatMemory/ChatMemoryIntegrator`コンポーネントをアタッチして、ChatMemoryサービスのURLとユーザーIDを設定します。ユーザーIDは任意の値で構いませんが、複数ユーザーが利用するサービスを構築する場合はサービス内のユーザーを一位に特定できるIDをコードビハインドで設定するようにしてください。\n次に以下のコードを任意の箇所（Main等）に追加して、LLMのストリーム受信完了時に要求・応答のメッセージをChatMemoryに履歴として登録するようにします。\n\n```csharp\nusing ChatdollKit.Extension.ChatMemory;\n\nvar chatMemory = gameObject.GetComponent\u003cChatMemoryIntegrator\u003e();\ndialogProcessor.LLMServiceExtensions.OnStreamingEnd += async (text, payloads, llmSession, token) =\u003e\n{\n    chatMemory.AddHistory(llmSession.ContextId, text, llmSession.CurrentStreamBuffer, token).Forget();\n};\n```\n\n続いて記憶を検索し、会話の中に含める対応です。こちらはメインのGameObjectに`Extension/ChatMemory/ChatMemoryTool`を追加するだけでOKです。\n\n\n**NOTE:** ChatMemoryはいわゆるEpisodicな記憶を管理します。Factに相当するKnowledgeというエンティティーもありますが、自動的に抽出・保存されませんので、必要に応じて自身で対応してください。（デフォルトで検索対象には含まれています）\n\n\n## 🗣️ Speech Synthesizer (Text-to-Speech)\n\n音声合成サービスとしてクラウドサービスとして提供されるGoogle、Azure、OpenAI、Watsonをサポートするほか、キャラクターとしてより魅力的な音声を提供するVOICEVOX / AivisSpeech、VOICEROID、Style-Bert-VITS2, にじボイスをサポートします。\n音声合成サービスを使用するには、`ChatdollKit/Scripts/SpeechSynthesizer`の各サービス名が含まれる`SpeechSynthesizer`をAIAvatarオブジェクトにアタッチして、`IsEnabled`にチェックを入れてください。すでに他のSpeechSynthesizerがアタッチされている場合、使用しないSpeechSynthesizerの`IsEnabled`はチェックを外す必要がある点に注意してください。\n\nアタッチしたSpeechSynthesizerには、APIキーやエンドポイントなどのパラメーターをインスペクター上で設定することができます。これらのパラメーターの意味や設定すべき値等については各TTSサービス・製品のAPIリファレンスを参照してください。\n\n\n### Voice Prefetch Mode\n\n`Voice Prefetch Mode` は音声合成リクエストの管理と処理方法を決定します。デフォルトでは、システムは **Parallel** モードで動作します。以下のモードがサポートされています：\n\n1. **Parallel（デフォルト）**:  \n   このモードでは、複数の音声合成リクエストが同時に送信・処理されます。複数の音声を短時間で生成する場合に最適で、最速の応答時間を保証します。低遅延が重要で、十分なリソースが利用可能な場合に使用してください。\n\n2. **Sequential**:  \n   リクエストがキューに追加された順に1つずつ処理されます。このモードは、リソースが限られている場合や音声出力の順序を厳密に制御する必要がある場合に適しています。ただし、次のリクエストが処理されるまで待機時間が長くなる可能性があります。\n\n3. **Disabled**:  \n   このモードではプリフェッチは行われません。音声合成は明示的にトリガーされた場合にのみ実行されます。リソースを最小限に抑えたい場合や、プリフェッチが不要な場合に適しています。\n\n`Voice Prefetch Mode` は、`SpeechSynthesizer` コンポーネントのインスペクターで変更できます。選択したモードがパフォーマンスやリソース管理の要件に適していることを確認してください。\n\n\n### Make custom SpeechSynthesizer\n\nお好みの音声合成サービスを利用するために、カスタムのSpeechSynthesizerを簡単に作成・利用することができます。\n`ChatdollKit.Model.WebVoiceLoaderBase`を継承したクラスを作成し、発話文言の`string text`と各種パラメーターの`Dictionary\u003cstring, object\u003e parameters`を引数にとり、Unityで再生可能な`AudioClip`オブジェクトを返す非同期メソッド`DownloadAudioClipAsync`を実装してください。\n\n```csharp\nUniTask\u003cAudioClip\u003e DownloadAudioClipAsync(string text, Dictionary\u003cstring, object\u003e parameters, CancellationToken token)\n```\n\nなおWebGLでは圧縮音源の再生をサポートしないため、必要ならばプラットフォームに応じて処理を分岐するなど対応するようにしましょう。\n\n\n### Performance and Quality Tuning\n\n高速なレスポンスを実現するため、AIからの応答メッセージ全体を音声合成するのではなく、文章を句読点等で区切って順次音声合成・発話しています。\nこれは応答パフォーマンスを大幅に改善する一方で、特にStyle-Bert-VITS2などのAI音声合成を利用する場合、あまり細かく分割すると話し方やトーンの品質が犠牲になってしまいます。\nこのパフォーマンスと品質のバランスを両立するために、音声合成の区切り方を`LLMContentProcessor`コンポーネントインスペクター上で設定することができます。\n\n|項目|説明|\n|----|----|\n|**Split Chars**|区切文字。この文字で必ず区切って音声合成処理を行います。|\n|**Optional Split Chars**|オプション区切り文字。原則として区切りませんが、文章の長さが次の`Max Length Before Optional Split`よりも長い場合に区切ります。|\n|**Max Length Before Optional Split**|オプション区切り文字を区切り文字として使用する長さの閾値。|\n\n\n\n## 🎧 Speech Listener (Speech-to-Text)\n\n音声認識サービスとしてクラウドサービスとして提供されるGoogle、Azure、OpenAIをサポートしています。\n音声認識サービスを使用するには、`ChatdollKit/Scripts/SpeechListener`に含まれる各サービス名を冠した`SpeechListener`をAIAvatarオブジェクトにアタッチしてください。複数のSpeechListenerをアタッチした場合、複数のSpeechListenerが並行して動作してしまいますのでご注意ください。\n\nアタッチしたSpeechListnerには、APIキーやエンドポイントなどのパラメーターをインスペクター上で設定することができます。これらのパラメーターの意味や設定すべき値等については各STTサービス・製品のAPIリファレンスを参照してください。\n\n`Voice Recorder Settings`の各設定項目は、後述する`AIAvatar`コンポーネントから制御されるため、以下を除いてインスペクター上での設定は無視されます。\n\n|項目|説明|\n|----|----|\n|**Auto Start**|オンにすると、アプリケーションの起動時に音声認識を開始します|\n|**Print Result**|オンにすると、認識した音声を文字起こししたものをコンソールに出力します|\n\n\n### Settings on AIAvatar Inspector\n\nSpeechListnerに関連する設定の多くは、`AIAvatar`コンポーネントのインスペクター上で設定します。\n\n|項目|説明|\n|---|---|\n|**Conversation Timeout**|会話の終了とみなすまでの待機時間（秒）。この時間を過ぎるとIdleモードに移行し、メッセージウィンドウが非表示になります。再び会話するにはウェイクワードの認識が必要です|\n|**Idle Timeout**|アイドル状態を終了してスリープモードに入るまでの待機時間（秒）。デフォルトではアイドルモードとスリープモードに違いはありませんが、音声認識の方式やアイドルアニメーションなどをユーザー実装で切り替えるのに利用することができます|\n|**Voice Recognition Threshold DB**|音声認識のしきい値（デシベル）。この値以下の音声は認識されません|\n|**Voice Recognition Raised Threshold DB**|音声認識の強化されたしきい値（デシベル）。より高い音量での発話を認識するためのしきい値です。これは後述する`Microphone Mute By`の値を`Threshold`にした場合に利用されます|\n|**Conversation Silence Duration Threshold**|指定した時間以上の無音が検出されると録音が終了し、その時点で音声認識が実行されます|\n|**Conversation Min Recording Duration**|録音された音声が指定した時間以上の場合にのみ音声認識を実行します。これにより、短い物音などを無視して、誤認識を防ぎます|\n|**Conversation Max Recording Duration**|録音された音声が指定した時間を超えると音声認識を行わず、録音を無視します。これにより、長すぎる音声が音声認識に負担をかけることを防止します|\n|**Idle Silence Duration Threshold**|アイドルモード時の録音終了までの無音時間（秒）。ウェイクワードの待ち受け状態では、短い無音をスムーズに識別するため小さな値を設定します|\n|**Idle Min Recording Duration**|アイドルモード時の最低録音時間。短いフレーズをスムーズに識別できるように、会話中よりも小さな値を設定します|\n|**Idle Max Recording Duration**|アイドルモード時の最長録音時間。ウェイクワードは通常短いため、会話中よりも短い値を設定します|\n|**Microphone Mute By**|発話中にアバターの発話内容を音声認識させないための方式です。\u003cbr\u003e\u003cbr\u003e- None: 何もしません\u003cbr\u003e- Threshold: 音声認識の閾値を`Voice Recognition Raised Threshold DB`まで上昇させます\u003cbr\u003e- Mute: マイクからの入力音声を無視します\u003cbr\u003e- Stop Device: マイクデバイスを停止します\u003cbr\u003e- Stop Listener: リスナーを停止します。**AzureStreamSpeechListenerを使用する場合はこれを選択してください**|\n\n\n### Using AzureStreamSpeechListener\n\n`AzureStreamSpeechListener`を使用する場合は、他のSpeechListenerとは一部設定が異なります。これは`AzureStreamSpeechListener`がSDK内部でマイクを制御していることや、文字起こしが逐次行われることに起因します。\n\n1. **Microphone Mute Byの設定**: `Stop Listener`を選択してください。そうしないと、発話内容を聞き取ってしまい、会話が成立しません。\n1. **User Message Windowの設定**: `Is Text Animated`のチェックを外し、`Pre Gap`を`0`、`Post Gap`を`0.2`程度にしてください。\n1. **メインロジックのUpdate処理**: 認識した文言を逐次表示させるため、以下のようなコードを`Update()`の中に追加してください。\n\n```csharp\nif (aiAvatar.Mode == AIAvatar.AvatarMode.Conversation)\n{\n    if (!string.IsNullOrEmpty(azureStreamSpeechListener.RecognizedTextBuffer))\n    {\n        aiAvatar.UserMessageWindow.Show(azureStreamSpeechListener.RecognizedTextBuffer);\n    }\n}\n```\n\n\n## ⏰ Wake Word Detection\n\n会話の開始トリガーとして、ウェイクワードを検知することができます。\nまた、会話の終了トリガーとなるキャンセルワードや、フレーズではなく認識した音声の長さをトリガーにする設定など、AIAvatarコンポーネントのインスペクターで設定することができます。\n\n### Wake Words\n\nこのフレーズを認識したときに会話を開始します。複数のウェイクワードを登録することができます。以下の項目以外は、v0.8以降では無視されます。\n\n|項目|説明|\n|---|---|\n|**Text**|会話を開始するトリガーとなる文言|\n|**Prefix / Suffix Allowance**|ウェイクワードの前後に許容される追加文字の長さ。例えば、ウェイクワードが\"こんにちは\"で、許容値が4文字の場合、\"やあ、こんにちは！\"という語句もウェイクワードとして検出されます。|\n\n### Cancel Words\n\nこのフレーズを認識したときに会話を終了します。複数のキャンセルワードを登録することができます。\n\n### Interrupt Words\n\nキャラクターが発話を停止し、ユーザーのリクエストを聞き始めます。複数の割り込みワードを登録することができます。（例：「待って」）\n\n**NOTE:** この機能を使用するには、AIAvatarのインスペクターで `Microphone Mute By` の項目から `Threshold` を選択してください。キャラクターが話している間もChatdollKitがあなたの声を聞けるようになります。\n\n### Ignore Words\n\n認識した音声がウェイクワードやキャンセルワードかどうかの判定をする際に無視する文字列を登録します。たとえば句読点の有無を意識したくないときに利用します。\n\n### Wake Length\n\n特定の文言ではなく、認識した文字列の長さで会話を開始することができます。値が`0`のときこの機能は無効です。\nたとえば、アイドルモードではウェイクワードではなく文字列長で会話を再開し、スリープモードではウェイクワードで会話を再開することで、断続的に会話が続く場合に煩わしさを解決することができます。\n\n\n## ⚡️ AI Agent (Tool Call)\n\nLLMでTool Call（Function Calling）がサポートされている場合、その機能を利用して呼び出す処理を定義・実装することができます。\n`ITool`を実装または`ToolBase`を継承したコンポーネントを作成してAIAvatarオブジェクトにアタッチすることで、自動的にツールとして識別され、必要に応じて実行されるようになります。\n\n独自のスキルを作成するには、`FunctionName`、`FunctionDescription`を定義し、Functionの定義を返す`GetToolSpec`メソッド、Functionの処理そのものである`ExecuteFunction`メソッドを実装します。詳細は`ChatdollKit/Examples/WeatherTool`を参考にしてください。\n\n**NOTE**: プロジェクトにLLMFunctionSkillを使用している場合、[Migration from FunctionSkill to Tool](#migration-from-functionskill-to-tool)も参照してください。\n\n\n## 🎙️ Devices\n\nデバイス制御の仕組みを提供します。現時点ではマイクとカメラのみです。\n\n### Microphone\n\nマイクから音声を取得し、取得した音声の波形データを他のコンポーネントから利用するための`MicrophoneManager`コンポーネントを提供します。\n基本的にはSpeechListenerからの利用を想定していますが、任意のユーザー実装プログラムからでも`StartRecordingSession`を使用して録音セッションを登録し、利用することができます。\n\nインスペクターで設定できる項目は以下の通りです。\n\n|項目|説明|\n|----|----|\n|**Sample Rate**|サンプリングレートです。WebGLで使用する場合は44100としてください|\n|**Noise Gate Threshold DB**|ノイズゲートです。デシベルで指定します。AIAvatarコンポーネントと合わせて使用する場合は、AIAvatarコンポーネントからこの値を制御します|\n|**Auto Start**|アプリケーションの開始時にマイクからの音声取得をスタートします|\n|**Is Debug**|マイクの開始・終了やミュート・ミュート解除の際にログ出力します|\n\n\n### Camera\n\nカメラからの画像取得やプレビューの表示、カメラの切り替えなどをパッケージ化した`SimpleCamera`プレファブを提供します。\nデバイスによるカメラの仕様の吸収の仕方が完璧ではなく、試験的な提供となります。詳細は当該プレファブやアタッチされているスクリプトを参照してください。\n\n\n## 💃 ３D Model Control\n\n3Dモデルの身振り手振りや表情、発話を制御する`ModelController`コンポーネントを提供します。\n\n### Idle Animations\n\n待機中に相応しいモーションをループ実行します。実行したいモーションはAnimator Controllerのステートマシーンに登録して、`ModelController`のインスペクター上でその遷移の条件となるパラメーター名を`Idle Animation Key`、その値を`Idle Animation Value`として登録する方法が最も簡単です。\n\n複数のモーションを登録し、一定間隔でランダムに切り替えて実行するには、以下の通り任意の箇所でコードベースで`AddIdleAnimation`メソッドを使って登録してください。第一引数は実行する`Animation`オブジェクト、`weight`は出現確率の倍数、`mode`は特定のモデルの状態に表示させたい場合にのみ指定します。また、`Animation`のコンストラクターの第一引数はパラメーター名、第二引数が値、第三引数が継続時間（秒）です。\n\n```csharp\nmodelController.AddIdleAnimation(new Animation(\"BaseParam\", 2, 5f));\nmodelController.AddIdleAnimation(new Animation(\"BaseParam\", 6, 5f), weight: 2);\nmodelController.AddIdleAnimation(new Animation(\"BaseParam\", 99, 5f), mode: \"sleep\");\n```\n\n### Control by Script\n\n作成中です。基本的には`AnimatedVoiceRequest`オブジェクトを作成して、`ModelController.AnimatedSay`を呼び出します。\n`AIAvatar`の内部でアニメーション、表情、発話を組み合わせた要求をしていますので、参考にしてみて下さい。\n\n\n## 🎚️ UI Components\n\n音声対話型AIキャラクターアプリケーションでよく使用するUI部品をプレファブとして提供します。いずれもシーンに追加すれば使用できるようになります。設定項目等はデモを参考にしてください。\n\n- FPSManager: 現在のフレームレートを表示します。また、このコンポーネントでターゲットとするフレームレートを設定することもできます。\n- MicrophoneController: マイクのノイズゲートを設定するためのスライダーです。\n- RequestInput: リクエストを入力するテキストボックスです。ファイルシステムからの画像取得や、カメラの起動ボタンも提供します。\n- SimpleCamera: カメラからの画像取得やプレビュー画面などをまとめたものです。プレビュー非表示で画像取得することもできます。\n\n\n## 🎮 Control from External Programs\n\n外部プログラムからソケット通信やJavaScriptの関数呼び出しによりChatdollKitアプリケーションにメッセージを送信することができます。\nこれにより、AI Vtuberの配信やリモートでのアバター接客、AIと人とのハイブリッドなキャラクター運用など新たなユースケースに活用することができます。ソケット通信を使用するには`ChatdollKit/Scripts/Network/SocketServer`をAIAvatarオブジェクトにアタッチして任意のポート番号（8080等）を設定、またはJavaScriptから制御するには`ChatdollKit/Scripts/IO/JavaScriptMessageHandler`をアタッチしてしてください。\n\nまた、ネットワーク経由で対話リクエストを処理するには`ChatdollKit/Scripts/Dialog/DialogPriorityManager`を、AIによる応答の代わりに人が作成した任意の身振り手振り・表情・発話をキャラクターに実行させるためのリクエストを処理するには`ChatdollKit/Scripts/Model/ModelRequestBroker`をAIAvatarオブジェクトにアタッチしてください。\n\n以下は、上記の両方を使用するために任意の箇所に追加するコードベースの例です。\n\n\n```csharp\n// Configure message handler for remote control\n#pragma warning disable CS1998\n#if UNITY_WEBGL \u0026\u0026 !UNITY_EDITOR\ngameObject.GetComponent\u003cJavaScriptMessageHandler\u003e().OnDataReceived = async (message) =\u003e\n{\n    HandleExternalMessage(message, \"JavaScript\");\n};\n#else\ngameObject.GetComponent\u003cSocketServer\u003e().OnDataReceived = async (message) =\u003e\n{\n    HandleExternalMessage(message, \"SocketServer\");\n};\n#endif\n#pragma warning restore CS1998\n```\n\n```csharp\nprivate void HandleExternalMessage(ExternalInboundMessage message, string source)\n{\n    // Assign actions based on the request's Endpoint and Operation\n    if (message.Endpoint == \"dialog\")\n    {\n        if (message.Operation == \"start\")\n        {\n            if (source == \"JavaScript\")\n            {\n                dialogPriorityManager.SetRequest(message.Text, message.Payloads, 0);\n            }\n            else\n            {\n                dialogPriorityManager.SetRequest(message.Text, message.Payloads, message.Priority);\n            }\n        }\n        else if (message.Operation == \"clear\")\n        {\n            dialogPriorityManager.ClearDialogRequestQueue(message.Priority);\n        }\n    }\n    else if (message.Endpoint == \"model\")\n    {\n        modelRequestBroker.SetRequest(message.Text);\n    }            \n}\n```\n\n### ChatdollKit Remote Client\n\n`SocketServer`はソケット通信で任意の情報を受け取るようになっているだけで、公式としてサポートするクライアントプログラムは提供していませんが、Pythonのサンプルコードを提供しています。\n以下を参考に必要に応じて別の言語に読み替えたり他のプラットフォームに移植してみてください。\n\nhttps://gist.github.com/uezo/9e56a828bb5ea0387f90cc07f82b4c15\n\nまた、もしAITuber（AI VTuber）を開発したい場合は、AITuberのデモと [ChatdollKit AITuber Controller](https://github.com/uezo/chatdollkit-aituber) の組み合わせを試してみてください。内部的に`SocketServer`を使用しています。\n\n\n## 🌐 WebGLでの実行\n\nさしあたっては以下のTipsを参考にしてください。加えてWebGL用のデモを公開予定です。\n\n- ビルドに5-10分くらいかかる。（マシンスペックによる）\n- デバッグがとても大変。どこでエラーが起きたのか、ログには表示されない: `To use dlopen, you need to use Emscripten’s linking support, see https://github.com/kripken/emscripten/wiki/Linking` \n- C#標準の Async/Await が利用できない（そこでコードが止まる）。JavaScriptがシングルスレッドなことに依存していると思われる。かわりに [UniTask](https://github.com/Cysharp/UniTask) を利用しましょう\n- WebGLアプリのホスト先と異なるドメインとHTTP通信するにはCORSへの対応が必要\n- Unity標準のマイクは動作しない。ネイティブ・WebGL双方で意識せず利用できる`ChatdollMicrophone`を使いましょう\n- MP3などの圧縮音源の再生ができない。SpeechSynthesizerのフォーマットをWaveにしましょう\n- OVRLipSyncが動作しない。かわりに [uLipSync](https://github.com/hecomi/uLipSync) と [uLipSyncWebGL](https://github.com/uezo/uLipSyncWebGL) との組み合わせを使いましょう\n- 日本語等のマルチバイト文字を表示したいとき、それが含まれるフォントをプロジェクトに同梱する必要がある。メッセージウィンドウが標準でArialなので、これをM+など別のものに変更しましょう\n\n\n## 🔄 Migration from 0.7.x\n\n最も簡単な移行方法は、`Assets/ChatdollKit`をすべて削除して新たに最新のChatdollKitのunitypackageをインポートし直すことです。しかしながら何らかの事情でそれができない場合、以下の手順によりエラーを解消することができます。\n\n1. 最新のChatdollKitを上書きインポートします。この時点で、いくつかのエラーがコンソールに表示されます。\n\n1. ChatdollKit_0.7to084Migration.unitypackageをインポートします。\n\n1. `partial`キーワードを`ModelController`、`AnimatedVoiceRequest`、`Voice`のクラス宣言に追加します。\n\n1. `DialogController`に含まれる`OnSayStart`を`OnSayStartMigration`に置換します。\n\n**⚠️Note**: この手順は単にエラーを解消するだけであり、レガシーコンポーネントを利用できるようにするためのものではありません。もしプロジェクトのカスタムコードの中に`DialogController`、`LLMFunctionSkill`、`LLMContentSkill`、`ChatdollKit`を使用する箇所がある場合、以下の新しいコンポーネントを使用するようにしてください。\n\n- `DialogController`: `DialogProcessor`\n- `LLMFunctionSkill`: `Tool`\n- `LLMContentSkill`: `LLMContentProcessor`\n- `ChatdollKit`: `AIAvatar`\n\n\n### Migration from FunctionSkill to Tool\n\nコンポーネントが`LLMFunctionSkillBase`を継承している場合、以下の手順で簡単に`ToolBase`にマイグレーションできます。\n\n1. 継承元クラスの変更\n\n    `LLMFunctionSkillBase`から`ToolBase`に変更します。\n\n    ```md\n    // Before\n    public class MyFunctionSkill : LLMFunctionSkillBase\n\n    // After\n    public class MyFunctionSkill : ToolBase\n    ```\n\n1. `ExecuteFunction`メソッドのシグネチャの変更\n\n    `ExecuteFunction`メソッドの引数と戻り値の型を以下の通り変更します。\n\n    ```md\n    // Before\n    public UniTask\u003cFunctionResponse\u003e ExecuteFunction(string argumentsJsonString, Request request, State state, User user, CancellationToken token)\n\n    // After\n    public UniTask\u003cToolResponse\u003e ExecuteFunction(string argumentsJsonString, CancellationToken token)\n    ```\n\n1. `ExecuteFunction`の戻り値の型の変更\n\n    `FunctionResponse`から`ToolResponse`に変更します。\n\n\n# ❤️ 謝辞\n\nChatdollKitでは以下のすばらしい素材・ツールを利用させていただいており、心から感謝申し上げます。\n\n- [uLipSync](https://github.com/hecomi/uLipSync) (LipSync) (c)[hecomi](https://twitter.com/hecomi)\n- [UniTask](https://github.com/Cysharp/UniTask) (async/await integration) (c)[neuecc](https://x.com/neuecc)\n- [UniVRM](https://github.com/vrm-c/UniVRM/releases/tag/v0.89.0) (VRM) (c)[VRM Consortium](https://x.com/vrm_pr) / (c)[Masataka SUMI](https://x.com/santarh) for MToon\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuezo%2Fchatdollkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuezo%2Fchatdollkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuezo%2Fchatdollkit/lists"}