1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

作ったゲームのキャラと喋りたい

Posted at

背景

以下で作ったゲームキャラをAIアバター化して会話してみる試み
今や何番煎じかわかりませんが、やっぱりゲームや漫画のキャラと会話したいよね

作る

構成

こんな感じです。
ローカルにFastAPIで作った簡易APIサーバーと、Dify(Docker)を立てます。

image.png

実装

Realtime API

公式ドキュメントのほぼコピペで動きます。

本当はinputが音声でoutputがテキストにしたかったのですが、現在はできないのかも?(実装間違ってただけかもしれませんが)
/sessionmodalities: [ "text" ]を指定しても話しかけたら音声が返ってきました。

ということで、とりあえずoutputはテキストだけにしたかったので公式サンプルのこの部分を実装しないようにします。
(outputの音声は作られていると思うので無駄なトークンを消費してますが・・・)

image.png

音声合成

にじボイスのAPIを呼び出します。
2024年の年末に試した感じだと同時に1件しか音声を作れないようなので(音声を生成中にもう1件投げたらエラーになった)、1件ずつAPIを投げるようにキューイングしながら処理してあげます。

待ち時間軽減のため、ChatGPTの応答内容全文を一気に音声合成するのではなく、ストリーミング的に文節単位で音声合成をした方が良いのですが今回はその部分は未実装です。

ナレッジ検索

Difyを使った簡易実装です。
「ナレッジを作成」からお手製の原作シナリオと設定を書いたテキストを登録してナレッジを作ります。
使えるRerankのモデルを持ってないので単純なハイブリット検索です。
何も考えずにとりあえずデータ突っ込んだだけなの、正直このままだとプロダクションで使える精度ではなさそうという感想です。

image.png

Difyで作ったナレッジはAPI公開できます。

image.png

表情やモーション

これは以下で開発したものをそのまま利用。

Toolsの設定

Toolsの設定はsession作成時のパラメータで与えることができます。

Toolの呼び出しはresponse.function_call_arguments.doneで処理します。

  switch (message.type) {
    case "response.function_call_arguments.done":
      if (message.name === "retrieve_knowledge") { // Toolの種類を判定
        const obj = JSON.parse(message.arguments); // Toolの引数を取得
        const result = await fetchKnowledgeContent(obj.query); // ナレッジ取得のAPI呼び出し
        dc.send( // 結果を返す
          JSON.stringify({
            type: "conversation.item.create",
            item: {
              type: "function_call_output",
              call_id: message.call_id,
              output: JSON.stringify(result),
            },
          })
        );
        dc.send(JSON.stringify({ type: "response.create" })); // 処理完了

結果

表情とモーションのサンプル

RAGのサンプル

気づいたことなど

(2024年1月初旬)

  • 弱小OpenAIユーザーなのでRealtime APIのRate limitにすぐに引っかかりました。テストで動かす程度であれば金額自体はたいした額にはならないです。
  • OpenAIの音声は日本語がちょいちょい間違っていて、スクリプトとは違うことをけっこう喋る。にじボイスの方が日本語は良かった。
  • にじボイスのクレジットはどんどん消費しちゃいます。
  • Tool呼び出し中の待ち時間、なんか喋っていて欲しいのだけど無口なことが多い(たまに喋ってくれるけど)。conversation.item.createで「実行中」とか送ってみたけど効果あるのか不明だった。
  • OpenAIとAOAIとでRealtime APIのイベントオブジェクトの構造が微妙に違う。

Gemini nanoのようなプラットフォーム同梱のSLMで動かせるようになるともっとワクワクしそう。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?