Live2Dモデル + AI で感情表現してもらう(Function Calling, ローカルLLM)

AI

前回の記事でVue.js + Cubism SDK for Webを使って、Live2Dモデルをブラウザ上で表示しました。

今回はFucntion Callingを用いることでAIにLive2Dモデルの表情を制御してもらいます。

Function Calling とは

an abstract image of a sphere with dots and lines

Function Callingとは、ChatGPTが外部のAPIや関数を呼び出し、その結果を基に回答を生成する仕組みです。例えば、ユーザーが「今日の天気を教えて」と尋ねると、ChatGPTは天気情報を取得するAPIを実行し、その結果を元に回答します。

この機能を活用すると、ChatGPTはリアルタイム情報の取得や、カレンダーへの予定追加、ニュースの取得など、さまざまな操作が可能になります。

Ollamaもこの機能に対応しており、Toolsに対応したモデルを使うことでローカルLLMでもFunction Callingを利用できます。

Toolsを使用できるモデル

実行環境

a close up of a graphics card on a table

動作を確認した環境は以下のとおりです。今回はローカルLLMを動かすのでNVIDIAのGPUはほぼ必須。

  • Windows 11
  • Nvidia RTX4080 16GB
  • デスクトップ版のOllama
  • デスクトップ版のVOICEVOX
  • Node.js v22.14.0 (64-bit)
  • Cubism SDK for Web 5-r.3

LLMモデルはLlama3.1を使用しました。

モデルのダウンロードは次のコマンドで行えます。

PowerShell
ollama pull llama3.1

コードと解説

photo of computer monitor displaying program

Function Callingで表情の制御する部分について解説します。

Function Callingの実行

OllamaはOpenAI API互換のエンドポイントを提供しているので、openaiパッケージを使ってリクエストを投げることができます。

openai.chat.completions.create() メソッドに tools パラメータを渡すことで、Function Callingを利用できます。

TypeScript
// CharacterChatWithExpression.ts の一部抜粋

const tools: ChatCompletionTool[] = [
    {
      type: 'function',
      function: {
        name: 'change_character_expression',
        description: "Change the character's expression",
        parameters: {
          type: 'object',
          properties: {
            expressionType: {
              type: 'string',
              enum: ['normal', 'happy', 'sad', 'angry', 'surprised', 'blush'],
              description: 'Expression',
            },
          },
          required: ['expressionType'],
        },
      },
    },
]

// APIリクエストに関数定義を含める
const response = await openai.chat.completions.create({
    model,
    messages: [...systemMessages, ...this.conversationHistory],
    tools: this.tools,
    tool_choice: 'auto', // AIに関数呼び出しの判断を委ねる
    temperature: 0.7,
})

// AIの応答を取得
const message = response.choices[0].message

関数が呼び出されると、message.tool_calls に関数の呼び出し情報が格納されて返ってきます。

TypeScript
// 関数呼び出しを処理
if (message.tool_calls) {
    const functionCall = message.tool_calls[0]

    if (functionCall.function.name === 'change_character_expression') {
        // 関数の引数をJSONとしてパース
        const args = JSON.parse(functionCall.function.arguments) as ChangeCharacterExpressionArgs

        // ... 関数呼び出しの処理等 ...
    }
}

今回の場合、message.tool_calls[0] には以下のような情報が格納されていました。

JSON
{
  "id": "...",
  "index": 0,
  "type": "function",
  "function": {
    "name": "change_character_expression",
    "arguments": "{\"expressionType\":\"happy\"}"
  }
}

argumentsexpressionType: "happy" という情報が含まれています。これを基にLive2Dモデルを制御できますね。

Live2Dモデルの表情制御

Vue.jsのコンポーネント内では、Function Callingの結果を元にLive2Dモデルの表情を制御します。

respoinse.expression を基にLive2Dモデルの表情・モーションをセットしています。

Vue
<script setup lang="ts">
// LlmChatView.vue の一部抜粋

function onSubmit(){
// ... 省略 ...

    // APIからの応答を取得
    logger.debug('Sending message to LLM:', userMessage);
    const response = await characterChat.value.completion(userMessage);
    logger.debug('Received response:', response);

    if (response.text) {
      speechText.value = response.text;
      // キャラクターの応答を追加
      chatMessages.value.push({ text: response.text, isUser: false });
      // 表情とモーションを設定
      switch (response.expression) {
        case 'happy':
          expressionIndex.value = 1;
          motionGroupName.value = 'TapBody';
          motionIndex.value = 2;
          break;

        case 'sad':
          expressionIndex.value = 4;
          motionGroupName.value = 'TapBody';
          motionIndex.value = 1;
          break;

        case 'angry':
          expressionIndex.value = 7;
          motionGroupName.value = 'TapBody';
          motionIndex.value = 0;
          break;

          // ...

// ... 省略 ...
}

デモ動画

下記の動画は、Function CallingによってLive2Dモデルの表情を制御するデモです。

簡単なチャット画面を作成し、会話してみました。自然言語による指示で表情が変化しているのがわかると思います。

まとめ

今回はFunction Callingを使って、Live2Dモデルの表情を制御してみました。
AIに感情を選択させることで、より生きたキャラクターらしく感じられるのではないかと思います。

Function Callingは色々おもしろい使い方ができそうですね。
たとえば、

  • 好感度を上げ下げする関数を作成し、LLMに好感度を操作させる
  • システムプロンプトに好感度を含めることで、AIの反応を変化させる

というようにすれば、ゲームっぽく作れるのではないでしょうか。

コメント

タイトルとURLをコピーしました