Pepper SDK入門(18) 仲良しこよしもChatから

#今回の目標
複数のChatbotを使って適切な返答ができる才能をPepperに実装する回です。具体的なクラスの説明などは後日別の記事で行いますので、まずはChatの概要を掴みましょう。
本記事の読了特典として会話ごっこが出来るようになるため、もうPepperと二人きりでも気まずい沈黙は訪れません。

```java

//ArrayList型でtopicsを宣言し、ChatTopic(ここでのファイル名はtopic_01）を入れる
ArrayList topics = ArrayList(TopicBuilder.with(qiContext).withResource(R.raw.topic_01).build());
// トピックリストからQiChatbotを作成
QiChatbot qiChatbot = QiChatbotBuilder.with(qiContext)
                                      .withTopics(topics)
                                      .build();

// Chatbotをカスタム
Chatbot myChatbot = new MyChatbot(qiContext);

//アクションをビルド
Chat chat = ChatBuilder.with(qiContext)
                       .withChatbot(qiChatbot, myChatbot)
                       .build();

// アクションを非同期に実行
chat.async().run();
```
**これが今回の学習内容になります。**
MyChatbotは独自に作ったChatbotクラスです。QiChatbotとMyChatbotを組み合わせることで、Pepperと難解だったり複雑だったりもしかすると怪奇だったりするダイアローグを成したい人は試してみてください。機械の奇怪って何だろう。

#Chatbotの優先順位と選択肢
QiChatは人声の検知とPepperの返答を処理するもので、一つもしくは複数のChatbotを組み合わせて利用することができます。
複数のChatbotを使った場合、先頭から順番に応答を確認して最初に取得できたNormal Priorityの返答を採用する、という仕組みです。すべてのChatbotがNormal Priorityを返さなかった時には、Fallback Priorityの返答を採用します。コンプライアントにプライムなリプライをしてくれるのです。

#Chatが複数の会話サービスをサポートしているのは何故?
入力された全ての事柄を理解し、最適な応答ができるChatbotはありません。
しかし、多くの人はPepperが何らかの応答をしてくれることを期待します。
そのためにどうするかというと、Pepperと既存の色々な会話サービスを繋げればいいのです。
Dialogflow、Botfuel、 MicrosoftBotFrameworkなど多くの会話サービスによって、QichatはPepperとの会話を上手に進めてくれます。<font color='red'>W</font><font color='orange'>i</font><font color='yellow'>k</font><font color='yellowgreen'>i</font><font color='green'>p</font><font color='lightblue'>e</font><font color='blue'>d</font><font color='purple'>i</font><font color='pink'>a</font>とか天気の会話とか、それらのサービスで簡単に作れます。
音声認識、テキストの読み上げ、その他の応答などを独自で実装すると煩雑になってしまうので、QiChatを使用しましょう。

#Chatの状態
Chatの状態を見てみましょう。

##Listening
Pepperに話しかけられるのは、Chatがリスニング状態の時です。
Chatのリスニング状態は、<code>getListening</code>メソッドから24時間365日いつでもアクセスできます。

```java

Boolean isListening = chat.getListening();

```
リスナー側は以下のようになります。

```java

chat.addOnListeningChangedListener(listening -> {
    // リスニングの状態が変更されたらコール
});
```
##Hearing
Pepperは<code>getHearing</code>メソッドで人声を検知します。

```java

Boolean isHearing = chat.getHearing();
```
リスナー側は以下のようになります。

```java

chat.addOnHearingChangedListener(hearing -> {
    // ヒアリングの状態が変更されたらコール
});
```

##Saying
Pepperの発話は<code>getSaying</code>メソッドで確認できます。[AITalkボイス](https://www.ai-j.jp/demonstration/)。

```java

Phrase saying = chat.getSaying();
```
リスナー側は以下のようになります。

```java

chat.addOnSayingChangedListener(sayingPhrase -> {
    // Pepperが話している時コール
});
```
#入力を見てみる
リスナーを通じてPepperが何を聞いたか、確認することができます。

```java

chat.addOnHeardListener(heardPhrase -> {
    // 人声が聞こえたらコール
});
```

Pepperは人声を検知できても、その内容を理解できない時があります。~~人間同士でも稀に発生する。~~

```java

chat.addOnNoPhraseRecognizedListener {
    // 内容が理解できなかったらコール
}
```

#答えは一つじゃないらしい
人声の検知に成功したPepperの返答には、三つの種類があります。

##一つ目、Normalの場合

Fallback以外の通常の返答です。
リスナーを通じて確認できます。

```java

chat.addOnNormalReplyFoundForListener(input -> {
    // Normalの返答を行う際にコール
});
```
##二つ目、Fallbackの場合
Pepperが上手く答えを用意できないフレーズを聞き取った場合の返答です。
例えばQiChatbotがe:Dialog/NotUnderstoodに当てはまる時です。
この場合Pepperがフレーズの内容を聞き取っていても、inputパラメーターは空になります。

```java

chat.addOnFallbackReplyFoundForListener(input -> {
    // Fallbackの返答を行う際にコール
});
```
##三つ目、返答しない場合
入力がFallbackでも拾えないルール外のものである場合は、返答が行われません。
ここでも同じく、Pepperがフレーズの内容を聞き取っていてもinputパラメーターは空になります。

```java

chat.addOnNoReplyFoundForListener(input -> {
    // 発話に対する返答が見つからない際にコール
});
```

#じっとしておいて欲しい

Pepperは聞き取り中や発話中に、上半身が微妙に動いています。生命体ムーブ。
そのBodyLanguageを止めるには、以下のような実装を行ってください。

```java

//ArrayList型でtopicsを宣言し、ChatTopic(ここでのファイル名はtopic_01）を入れる
ArrayList topics = ArrayList(TopicBuilder.with(qiContext).withResource(R.raw.topic_01).build());
// トピックリストからQiChatbotを作成
QiChatbot qiChatbot = QiChatbotBuilder.with(qiContext)
                                      .withTopics(topics)
                                      .build();

qiChatbot.setSpeakingBodyLanguage(BodyLanguageOption.DISABLED);     

//アクションをビルド
Chat chat = ChatBuilder.with(qiContext)
                       .withChatbot(qiChatbot, myChatbot)
                       .build();

chat.setListeningBodyLanguage(BodyLanguageOption.DISABLED);

// アクションを非同期に実行
chat.async().run();
```
<img width=1000" alt="k0038_0.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/b371027a-f9c3-fec0-4efd-54d1f15af7bd.png">
以上で、Pepperとの会話のキャッチボールを叶えるグローブとボールの準備が整いました。
穏やかな言葉の投球と捕球を楽しみましょう。　

P.S.
**Chatはあくまで関連性の高い会話をPepperと行うためのものです。**
**何か特定の発話や正確な音声認識をして欲しい場合には、SayやListenを使ってください。~~Chatの存在意義~~**

**また、DiscussやSay、Listenを実行している時にChatは機能しないので、注意してください。**