ドコモAIエージェントAPIを使ってキャラクターと会話する

この記事は[VTuber Tech #1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vtuber) 21日目の記事です。

# はじめに
- 音声認識＆音声合成の機能を持ったドコモAIエージェントサービスを使ってアバターと会話ができるようにします
- サービスを使うにはGoogleアカウントまたはdアカウントが必要になります
- 今回はこちらの講演資料を参考に作成しています
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XR Kaigiの講演のスライドです！！<br>「音声対話エンジンを使った中の人がいないバーチャルキャラクターとその先の未来」<a href="https://twitter.com/hashtag/XRKaigi?src=hash&amp;ref_src=twsrc%5Etfw">#XRKaigi</a><a href="https://t.co/ilYDlldAvA">https://t.co/ilYDlldAvA</a></p>&mdash; AIセバスちゃん (@SebasAi) <a href="https://twitter.com/SebasAi/status/1202870099981422592?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# セットアップ
講演でも言ってましたが、サイトの導線が
くそ分かりづらい
難しい

## Unity側の準備
Unity Packageの取得
下記URLからUnity用SDKをダウンロードします
https://docs.sebastien.ai/step4/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/22471bcb-e808-3f47-c433-bc9366f26fed.png)


ZIPを展開し`sebastien_1.21.1.unitypackage`をUnityにインポートします

次に、Build Settingsに`login`シーンと`main`シーンを設定します
<img width="372" alt="スクリーンショット 2019-12-14 14.41.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/6938c55c-241b-5ea6-df94-feb20c2d67a7.png">

`login`シーンを実行してみてエラーが出ていなければとりあえずのセットアップはOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/3fb425c3-b4f3-656d-216c-fccce308024b.png)

もしエラーが出る場合はPlayer Settings->Scripting Runtime Versionを確認してみてください。
3.5になっているとコンパイルエラーが発生するようです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/f55df05c-8f73-5f4e-e5db-f2c162fedbed.png)



ここまでできたらUnity側の準備は完了です

## サービス側の準備
Agentcraftのサイトに行きログインします
https://agentcraft.sebastien.ai/
<img width="467" alt="スクリーンショット 2019-12-14 14.50.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/92a8079c-44a2-ffed-8acd-a42fab7a80f8.png">

ログインできるとこのような画面になります
<img width="1076" alt="スクリーンショット 2019-12-14 14.55.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/93302b1e-3038-6af1-67aa-460e3c724b96.png">

設定->デバイスIDの追加で`デバイスID`が表示されるので、これをコピーしておきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/deffa39a-c782-032b-8bf2-a4ded478ebd3.png)

次にSEBASTIENのUser Dashboard(UDS) にログインします
https://users-v2.sebastien.ai/login/login
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/9f60588d-efe0-b8f3-c5f8-a83e621c6b2b.png)

左上の＋ボタンを押して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/5018997d-74cd-2a0d-7c7a-627132d598b3.png)

先ほどコピーした`デバイスID`を貼り付け、登録を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/50f8c874-ff47-150a-d9da-a85da1667232.png)

これでサービス側の準備は完了です

## 実行してみる
Unityに戻り、`login`シーンを実行します
Inputfieldに`デバイスID`を入力して`Device Token取得`を押します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/022f9f1e-1381-114c-a4bb-5096640c3816.png)

うまくログインできると下記の画面になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/4799baff-35c2-c578-1051-f645326219f1.png)

デフォルト状態では「こんにちは」と打つと名前を聞いてきます
「名前は○○です」と打つと、その名前を認識して返してくれます
![api.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/177e4d23-473e-b308-cdcf-224bdab70b9b.gif)

# アバターに口パクさせる
- アバターはユニティちゃん https://unity-chan.com/download/index.php
- リップシンクにはOculus Lipsync　https://developer.oculus.com/downloads/package/oculus-lipsync-unity/
- の各アセットを使用します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/9be26f16-76f4-75e8-9b2e-ce6f144b732c.png)


の予定でしたが、Oculus Lipsyncが使えないことが判明しました。。。
どうやら音声を出力している`Speak`クラスが`OnAudioFilterRead`持つコンポーネントをアタッチされてしまうと動作しなくなってしまうようです。
仕方ないので、`AudioListener`から音声のボリュームを解析して口パクするスクリプトを作成しました

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class LipSync : MonoBehaviour 
{
	//ブレンドメッシュを持つSkinnedMeshRendererを設定
	public SkinnedMeshRenderer _skinnedMeshRenderer;

    //口パクに使うブレンドメッシュのIndex
	public int _index;

    //ゲイン
	public float _gain = 1000f;

	float[] _waveData = new float[1024];

	
	// Update is called once per frame
	void Update () 
	{
        //AudioListenerから音声データを取得
		AudioListener.GetOutputData(_waveData,1);

        //平均値にゲインをかけてブレンドメッシュを変化させる
		_skinnedMeshRenderer.SetBlendShapeWeight(_index, _waveData.Average() * _gain);
	}
}

```

これを任意のGameObjectにアタッチします
そしてSkinned Mesh Rendererにはブレンドシェイプを持つSkinned Mesh Rendererを設定し
Indexには口パクで使用するブレンドシェイプのIndexを設定します
今回は口パクに「あ」のブレンドシェイプを使用したので6を入力しています
そのままでは口が開かないのでGainに適当な値を入れて口が開くようにします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/66558c7c-33c1-1cc1-bbc4-6d74201917a2.png)

こんな感じで口パクさせることができます
![lip.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/3a2cc0af-2fac-36c1-512d-09f8f38e0f57.gif)



# エージェントをカスタマイズしてみる
- エージェントのカスタマイズは [Agentcraftのサイト](https://agentcraft.sebastien.ai/) で行います
- 例えばマッチング条件を増やすと、返答できるパターンが増えます
- 初期状態では「名前は～」と名乗らないと認識してくれません
- マッチング条件に`*です`を追加すると名前を聞かれたときに「～です」と答えた時も名前を言ったものとして認識してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/95d9ee0b-5493-3a35-19ae-93587abac8a1.png)

他にも声の種類を変更したりもできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/90afb790-a80c-9bfa-ce42-e404ae39ffb0.png)

かなり自由にカスタマイズできるので、ぜひドキュメントを見ながら挑戦してみてください
https://docs.sebastien.ai/step4/agentcraft-howtouse/