Pepper SDK入門(29)  BaseChatbotReactionでちょっと自発的なPepperに生まれ変わってもらう

#まずはBaseChatbotReactionがどこの馬の骨かを知る🐎
BaseChatbotReactionとは、ChatbotReactionの親クラスです。[前回のサンプルアプリ](https://qiita.com/kskrin/items/1b2baa8a087e6fd39eb4#%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E3%82%92%E5%9B%9E%E5%8F%8E%E3%81%99%E3%82%8B)に登場しましたね！
Chatbotが実行された場合のリアクションを実装するには、このBaseChatbotReactionを継承しなくてはならないのです。
✨$\huge{✨✨}$⭐️⭐️$\huge{✨}$⭐️⭐️$\huge{✨}$<img width="60px" alt="lampのコピー.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/4f4036ff-91dc-5a1e-f0b7-12b1a1908def.png">
<img width="200px" alt="key_kagi_tabaのコピー.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/b7539f7e-c752-5fe7-9998-c6b43f5eb05c.png">$\tiny{ランプの阿修羅}$

啓請はしなくて大丈夫です。

#BaseChatbotReactionを継承して、runWithメソッドとstopメソッドで何かをメイクする✊✌🖐

BasechatbotReactionを継承したカスタムリアクションクラスは、runwithメソッドとstopメソッドを実装しましょう。

Chatはユーザの音声を認識した時に各ChatbotのreplyToを呼び、認識した音声に対する応答があるかの確認を行います。Chatbotは、応答があった場合にStandardReplyReactionもしくはStandardAutonomousReactionを返します。

StandardReplyReactionもしくはStandardAutonomousReactionのコンストラクタの最初の引数には、BaseChatbotReactionを継承したリアクションオブジェクトを渡してください🕊🕊🕊🕊🕊🕊🕊🕊

```java
return new StandardReplyReaction(
                new MyChatbotReaction(getQiContext(), "百年待っていて下さい"),
                ReplyPriority.NORMAL);
```

Chatは各Chatbotの応答内容から実行するリアクションを選択します。Chatが複数のリアクションを受け取った場合は、優先順位などから一つのリアクションを選択して実行します。
その実行時にリアクションオブジェクトのrunWithメソッドが呼ばれ、Pepperに動作させることができるのです。ちなみに、Pepperに礬水を塗ってはいけません✖️🖌
●●●●●$\huge{●●}$●●●●●●●$\huge{●●}$<img width="60px" alt="k0675_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/116fc481-0759-203a-b8b6-ed3f84d62688.png">
<img width="160px" alt="【Pepper】両手広げのコピー.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/a0662a52-da34-d6db-dac9-d1c739ce08f6.png">$\tiny{イカ墨でボディーペイントされるPepper}$

stopメソッドはrunWithメソッド動作中に、runWithメソッドの内容を中断する必要がある場合に呼ばれます。具体的にはより優先順位の高いAutonomousReactionを実行する必要がある場合や、Chatがキャンセルされた場合などです。

<img width="500px" alt="dish.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/a70816f8-4a0b-62f9-62f1-1d18610c8fea.gif">

これは特に何もお届けしない、光速未満の超高速で飛んでくるスカイフィッシュです。


#コンストラクタを実に装う
BaseChatReactionを継承したクラスのコンストラクタはQiContextを受け取り、親クラスのコンストラクタを引き継がなくてはいけません。
第2引数で、発話内容など応答に必要な情報を渡すことが可能です。

```java
public class MyChatbotReaction extends BaseChatbotReaction {

    private String answer;

    protected MyChatbotReaction(QiContext context, String answer) {
        super(context);
        this.answer = answer;
    }

}
```
BaseChatbotReactionが聞き取った台詞に応じて返答を選ぶ場合には、その聞き取った台詞を渡すような使い方が出来ます。~~ボトルメールの中身が遠い海岸の潮騒だった、というようなシチュエーションです~~
*･｡..｡.･*:.｡. .｡.:*･゜ﾟ･**･｡..｡.･*:.｡. .｡.:*･゜ﾟ･*
*･｡..｡.･*:.｡. .｡.:*･゜ﾟ･**･｡..｡.･*:.｡. .｡.:*･゜ﾟ.･**<img width="80px" alt="ミルクラウン.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/dcf297dc-2995-7d8b-4df3-d5a4582295f7.png">👈$\tiny{ミルククラウンが添付されたボトル　(牛乳瓶)メール}$

#runWith再び
runWithメソッドはSayアクション、AnimationアクションなどChat以外の様々なアクションが実行可能です。

❗️重要❗️
runWithでアクションを実行する際はonRobotFocusGainedなどで渡されたQiContextを使用せず、runWithの引数で渡されるSpeechEngineをQiContextとして使ってください。

runWithメソッド内で実行されるアクションはキャンセルできる必要があるので、非同期で実行しなければいけません🚨
キャンセル可能にするため、アクション実行時に生成されるFutureオブジェクトを保持しておきましょう。

❗️❗️重要❗️❗️
runWithメソッドは以下のように実装されます。

```java
@Override
public void runWith(SpeechEngine speechEngine) {

    //Sayアクションをビルド
    Say say = SayBuilder.with(speechEngine)
                        .withText(answer)
                        .build();

    //アクションを非同期に実行し、Futureにリファレンスを保存
    fSay = say.async().run();

    //アクションが実行されるまでこのメソッドはそのまま
    try {
        fSay.get();
    } catch (ExecutionException e) {
        Log.e(TAG, "Error during Say", e);
    } catch (CancellationException e) {
        Log.i(TAG, "Interruption during Say");
    }
}
```

ここで、前回のサンプルアプリで説明していなかった部分を見てみましょう👁‍🗨以下のコードについてです。

```java
fSay.get();
```

```java
fAnima.get();
```

まず、アクションは非同期で実行しています。しかしそのままだとrunWithメソッドの処理は一瞬で終わり、Chatアクションが次の聞き取りを開始してしまうので意図した動作になりません。

しかしFutureのget関数を使えば、非同期で実行したアクションの終了をrunWithメソッド内で待つことができます。

同期処理でアクションを実行すればこの問題は解決できますが、同期処理の場合はキャンセルが出来ないのでこのようなイレギュラーなつくりとなる、というわけなのです💭

#stop⛔️
ChatbotReactionに必須のメソッドで、runWithメソッド内で実行中のアクションをキャンセルします。森羅万象に取り返しがついてもらいたいですね。

サンプルのChatbotReactionでは、クラスのプロパティでアクションのFutureオブジェクトを保持し、stopメソッド内でそれを利用できるようにしています。

```java
@Override
public void stop() {
    if (fSay != null) {
        fSay.cancel(true);
    }
}
```
さて、次の章からはStandardReplyReactionとStandardAutonomousReactionの二種類のリアクションをご紹介します。是非とも両者を攻略して二兎を得ましょう🐇🐇🛸

<img width="200px" alt="キララ.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/7222e0f6-5d78-406f-fb76-c109b8130462.gif">$\tiny{アブダクションされる雪兎たち}$

#💡StandardReplyReactionのメイキング💫
StandardReplyReactionはReplyReactionの標準の実装です。これは[前回](https://qiita.com/kskrin/items/1b2baa8a087e6fd39eb4#%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E3%82%92%E5%9B%9E%E5%8F%8E%E3%81%99%E3%82%8B)も登場していましたね！
Chatが何かを聞き取った時のChatbotのリアクションを定義して、Chatbotに返答をお願いする役目があります。
先述の章で登場したものと同じですが、サンプルコードは以下のとおりです⬇️

```java
return new StandardReplyReaction(
                new MyChatbotReaction(getQiContext(), "千年待っていて下さい"),
                ReplyPriority.NORMAL);
```

StandardReplyReactionは、BaseChatbotReactionを継承したクラスです。
BaseChatbotを継承した独自のChatbotクラスのreplyToが呼ばれた時、Chatbotの応答を返すために使われます。

* BaseChatbotReactionは、先ほど説明したrunWithやstopメソッドを実装したクラスです。
* ReplyPriorityで返答にNORMALかFALLBACKとして優先順位を設定します。FALLBACKの返答はNORMALの返答よりも優先順位が低いです。

#💡StandardAutonomousReactionのメイキング💫
StandardAutonomousReactionはAutonomousReactionの標準の実装です。
こちらは今回が初めての登場で、記事のタイトルにあるようにちょっと自発的なPepperを作ってくれます。なんとReplyReactionとは対照的にユーザーからの入力を必要としないので、無人島でもひとり言を言わせたりエアギターをさせたりエア動物をしてもらったりすることが可能なのです。
<img width="200px" alt="animal_zou.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/8ee1ed35-b198-9f0b-ffa2-4e813278f2ff.png">$\tiny{エア象}$

```java
 public void setAutonomous() {
//BaseChatbotReactionを継承するインスタンスを作成
  MyAutonomousChatbotReaction myAutonomousChatbotReaction = new MyAutonomousChatbotReaction(getQiContext());
//AutonomousReactionを作成
  StandardAutonomousReaction autonomousReaction = new StandardAutonomousReaction(
    myAutonomousChatbotReaction,
    AutonomousReactionImportance.LOW,
    AutonomousReactionValidity.DELAYABLE);

  oddChat.setAutonomousReaction(autonomousReaction);
        }
```

StandardAutonomousReactionもStandardReplyReaction同様、BaseChatbotReactionを継承したリアクションオブジェクトを引数として受け取ります。 

* StandardAutonomousReactionに渡すリアクションオブジェクトは、runWithメソッド内でSayやAnimationなどを実行します。
* AutonomousReactionImportanceで、返答にHIGHかLOWかの優先順位を設定します。
* AutonomousReactionValidityで、返答にIMMEDIATEかDELAYABLEかの時間的な優先順位を設定します。


AutonomousReactionValidityがDELAYABLEの場合はキューにデータを入れることができますが、IMMEDIATEの場合はすぐに実行されないと棄却される点に注意しましょう🔦

つまり、StandardReplyReactionのリアクション中にStandardAutonomousReactionのリアクションを実行しようとすると、DELAYABLEではStandardReplyReactionのリアクションの終了後にStandardAutonomousReactionのリアクションが実行されますが、IMMEDIATEではStandardReplyReactionのリアクションの終了後もStandardAutonomousReactionのリアクションは実行されません。

また、複数のStandardAutonomousReactionがありいずれもAutonomousReactionValidityがIMMEDIATEの場合、AutonomousReactionImportanceがLOWのリアクションはHIGHのリアクション中に実行しようとするとHIGHのリアクションが終了しても実行されませんが、HIGHのリアクションはLOWのリアクション中に実行しようとするとLOWのリアクション終了後に実行されます。

AutonomousReactionは、ChatbotのsetAutonomousメソッドで渡すことで実行可能です🟢

#あとがき
今回も[PepperSDKforAndroid](https://android.aldebaran.com/sdk/doc/pepper-sdk/ch4_api/conversation/reference/basechatbotreaction.html)を参考に書かせていただきました。
さらに詳しい情報は[BaseChatbotReactionのAPIリファレンス](https://android.aldebaran.com/sdk/doc/javadoc/qisdk/com.aldebaran.qi.sdk.object.conversation/-base-chatbot-reaction/index.html)、[StandardReplyReactionのAPIリファレンス](https://android.aldebaran.com/sdk/doc/javadoc/qisdk/com.aldebaran.qi.sdk.object.conversation/-standard-reply-reaction/index.html)、[StandardAutonomousReactionのAPIリファレンス](https://android.aldebaran.com/sdk/doc/javadoc/qisdk/com.aldebaran.qi.sdk.object.conversation/-standard-autonomous-reaction/index.html)などを参照してみてください。

次回はText To Speechエンジンのタグについてです📛
鬼ごっこ(tag)は始まらないので逃げないでください。

それでは〜👹👏
![onipe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574697/fd0ed63c-3b13-3bd2-5e59-edfe41c85d59.png)