Dialogとメモリイベント (Dialog応用)

[会話入門 (Pepper TechFes技術セッション)](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038)では、QiChat Scriptの機能をいくつか見てきました。
QiChatが備える便利な機能として、[メモリイベント](http://qiita.com/Atelier-Akihabara/items/4162192129f366da1240#almemory%E3%82%92%E4%BB%8B%E3%81%97%E3%81%9F%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%80%A4%E3%81%AE%E5%8F%96%E5%BE%97)との連携があります。ここでは、その例についていくつか見ていきます。

なお、このサンプルのうち **ALFaceCharacteristics API(FaceCharacteristics/PersonSmilingイベントの処理)についてはバーチャルロボットでは動作確認手段はなく、Pepper実機が必要になります。** アルデバラン・アトリエ秋葉原などでPepper実機を使って実験などおこなってみていただければと思います。 (予約URL：http://pepper.doorkeeper.jp/events)


#プロジェクトファイルの入手方法

このチュートリアルに関するプロジェクトファイルはGitHub https://github.com/Atelier-Akihabara/pepper-dialog-example にて公開しています。
GitHubにあるコードの取得方法にはいくつかありますが、[Download ZIP]リンクからアーカイブを取得するのが簡単な方法のひとつです。他にもgit関連ツールを利用する方法などさまざまな方法がありますので、状況に応じて調べてみてください。


#QiChatでのメモリイベントの監視

Choregrapheのドキュメント NAOqi Developer guide > NAOqi Framework > NAOqi API > NAOqi Audio > ALDialog > QiChat - Table of Content > QiChat - Syntax を読むと、 **Robot events: e:eventName** という記述があります。
この `e:イベント名` の記述を用いると、以下のように、聞いたことに対する返答と全く同じ形式で、あるイベントが発火されたことに対する反応を実装することができます。

```
u:(こんにちは)こんにちは、お元気ですか？
u:(e:イベント名)イベントを検出しました。
```

この記述方法を利用することで、言われた言葉に対してだけでなく、Pepperのセンサーなどにより発火するイベントに対する反応をDialogで記述することができます。

##Face Characteristicsイベントの利用

`e:イベント名` の記述を用いることで、[笑顔認識](http://qiita.com/Atelier-Akihabara/items/c64bded014801bc6a103#%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88-facecharacteristicspersonsmiling-%E3%81%AE%E5%88%A9%E7%94%A8)で利用した `FaceCharacteristics/PersonSmiling` イベントに対する反応をDialog中で記述することが可能です。

この記述例がサンプルプロジェクト **handle-person-smiling** です。GitHubから取得したファイルのうち、 `handle-person-smiling` フォルダ内の `handle-person-smiling.pml` をダブルクリックするなどして開くことができます。
以下のような手順で作成しています。

1. [Dialogの作成手順](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038#%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B)を参考に、トピック `test` を作成します
2. トピック `test` に以下のようなQiChat Scriptを記述します

    ```
    topic: ~test()
    language: jpj

    u:(こんにちは) こんにちは、僕に向かって笑ってもらえますか？

    u:(e:FaceCharacteristics/PersonSmiling) 楽しそうですねー
    ```

3. トピック `test` を実行するボックスを作成し、接続します

    ![handle-person-smiling-dialog.png](https://qiita-image-store.s3.amazonaws.com/0/54394/823d3398-71bb-f303-7c21-ec37d8ab6482.png)

このサンプルを実行してみてください。これまでのDialogのサンプルと同様に、「こんにちは」としゃべると、「こんにちは、僕に向かって笑ってもらえますか？」と応答してきます。これに加えて、Pepperの前で笑顔を作ると「楽しそうですねー」としゃべります。
これは、`e:FaceCharacteristics/PersonSmiling`が発火されたことで、`u:(e:FaceCharacteristics/PersonSmiling)～`のルールが実行されるためです。

この記述では、任意のメモリイベントを処理することができますので、たとえば[タッチセンサー](http://qiita.com/Atelier-Akihabara/items/0a5826fb018a4d0e4268#3-3)によるやり取りを組み込むことも可能です。また、[サブルール](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038#%E3%82%B5%E3%83%96%E3%83%AB%E3%83%BC%E3%83%AB)と組み合わせることで、言葉だけでなく、カメラの処理などを複雑に組み合わせた会話の構成が可能です。

##Dialog/NotUnderstoodイベントの利用

Dialog自身もその状況に応じてイベントを発火させるため、これをDialog中で利用することで、より高度な制御が可能になります。
たとえば、Choregrapheのドキュメント NAOqi Developer guide > NAOqi Framework > NAOqi API > NAOqi Audio > ALDialog > ALDialog API をみると、`Dialog/NotUnderstood` というイベントが定義されていることがわかります。
これは、`u:`で定義したルールのいずれにもマッチしなかった場合に発火するイベントで、このイベントを活用することで、「Aに対する反応」「Bに対する反応」「AB以外に対する反応」といった記述をおこなうことが可能です。

この記述例が、サンプルプロジェクト **handle-not-understood** です。GitHubから取得したファイルのうち、 `handle-not-understood` フォルダ内の `handle-not-understood.pml` をダブルクリックするなどして開くことができます。
以下のような手順で作成しています。

1. [Dialogの作成手順](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038#%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B)を参考に、トピック `test` を作成します
2. トピック `test` に以下のようなQiChat Scriptを記述します

    ```
    topic: ~test()
    language: jpj

    u:(こんにちは)こんにちは、突然ですが、犬と猫、どちらが好きですか？
        u1:(犬)わん
        u1:(猫)にゃー
        u1:(e:Dialog/NotUnderstood)犬か猫でお願いします ^stayInScope
    ```
    今回は、[サブルール](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038#%E3%82%B5%E3%83%96%E3%83%AB%E3%83%BC%E3%83%AB)を取り入れた例になっています。「こんにちは」と言われると、質問を投げかけサブルールの処理に入ります。「犬」「猫」の場合は適当な反応を返してこのサブルールを終了し、それ以外の場合は `^stayInScope` によりこのサブルールにとどまることで、引き続き「犬」「猫」のいずれかを言われるのを待ちます。

3. トピック `test` を実行するボックスを作成し、接続します

    ![handle-not-understood.png](https://qiita-image-store.s3.amazonaws.com/0/54394/2c91a6ba-2b39-b149-6a59-1073e0af9360.png)

    このサンプルについては、バーチャルロボットでも動作するように、Set Languageボックスを追加しています。Pepper実機の場合はデフォルトが日本語になっているため不要です。

このサンプルを実行し、「こんにちは」と話しかけ、Pepperの質問に答えてみてください。「犬」「猫」に対する反応と、それ以外の言葉(たとえば、「ライオン」)に対する反応をみてください。
また、質問を受けた状態で「イルカ」などとしゃべると「犬」と解釈されるような現象も確認できるかと思います。これは、Dialogがルールに定義された言葉に対して反応しやすくなっているためと考えられます。

他にも、 `Dialog/NotSpeaking5` `Dialog/NotSpeaking10` イベントを用いて一定の時間話しかけられなかったら反応するようなDialogを記述することもできます(末尾の数字は秒数を示す)。ぜひ、試してみてください。

#ボックスでDialogのイベントを取得

Dialogにより発火されたイベントは、他のメモリイベントと同様、Dialogボックスの外側で利用することも可能です。
「Pepperに任意の言葉を聞き取らせることはできる？」と質問いただくことがありますが、実はPepperはDialog起動中、ルールに記述された以外の言葉もある程度聞き取っており、これは `Dialog/LastInput` イベントによって取得することができます。ここでは  `Dialog/LastInput` イベントを使って、Dialogが取得した任意のキーワードを取得するようなフローを**実験的に**記述してみましょう。

サンプルプロジェクトとして、**はじめに「僕が何でも答えてあげましょう。何か単語を言ってください。」としゃべり、話しかけられた言葉に対して、「(話しかけられた言葉)ですか。うーん、僕のデータベースにはありませんね。残念。」としゃべる**アプリケーションを作成してみます。

なお、サンプルプロジェクトは **subscribe-last-input** です。GitHubから取得したファイルのうち、 `subscribe-last-input` フォルダ内の `subscribe-last-input.pml` をダブルクリックするなどして開くことができます。
以下のような手順で作成しています。

1. ダミーのDialogを実行するためのトピックファイルとして、[Dialogの作成手順](http://qiita.com/Atelier-Akihabara/items/37f5e99058ec39307038#%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B)を参考に、トピック `dummy` を作成します。トピックファイルは、以下のように空のままにしておきます

    ```
    topic: ~dummy()
    language: jpj
    ```

2. 実験用ボックスは、わかりやすさのため、フローダイアグラムボックスとしてまとめます。以下のような空のSubscribe LastInputダイアグラムボックスを作成します

    ![subscribe-last-input-box.png](https://qiita-image-store.s3.amazonaws.com/0/54394/071f8c74-88b1-bebd-f7e4-b5e9f43d54d1.png)

3. Subscribe LastInputボックスの中のフローを以下のように構成します。ボックスは `dummy` ダイアログのほか、以下のものを利用しています
    * standardボックスライブラリ
        * Flow Control > Time > Wait
    * advancedボックスライブラリ
        * Memory > Subscribe to event

    ![inside-subscribe-last-input.png](https://qiita-image-store.s3.amazonaws.com/0/54394/6a5e10ef-86ac-12be-1a51-adcd4cb3d89b.png)

    ここでは、Subscribe LastInput開始時に`dummy`ダイアログを起動し、これと時間差でSubscribe to Eventボックスで `Dialog/LastInput` イベントの監視を開始しています。これにより、Dialogにより `Dialog/LastInput` イベントが発火されると、Subscribe to EventボックスのonEvent出力を通じて値がSubscribe LastInputボックスのlastInputとして出力される形にしてあります。

4. 実験用のフローを以下のように構成します

    ![subscribe-last-input-flow.png](https://qiita-image-store.s3.amazonaws.com/0/54394/6f60a083-b841-f663-54f1-968f28602e76.png)

    フローのポイントは以下の通りです。
    * 先の例と同様に、バーチャルロボットでも実行できるよう、Set Languageボックスを追加しています。
    * 自身が言ったことをLastInputで拾ってしまうことを防ぐため、LastInputで出力された内容をAnimated Say Textボックスに入力する前に、Subscribe LastInputボックスを停止しています。この際、Wait For Signalsボックスを改造したボックスを使い、Subscribe LastInputがonStoppedを出力してからAnimated Say Textボックスの実行を開始する形にしています。
    * デモとして、人間のほうを向き続けるように、Basic Awarenessボックスを配置しています。


このアプリケーションの実行例は以下の動画を参考にしてください。

[![Dialog/LastInputイベント動作例](http://img.youtube.com/vi/wsDiB2-B3aY/0.jpg)](http://www.youtube.com/watch?v=wsDiB2-B3aY)
(再生時間: 1分30秒)

動画中の「アトリエ」という言葉のように、この方法では、期待した結果が得られない場合が多いと思います。これは、Speech Reco.ボックスやDialogボックスが、あらかじめこれから聞き取ることになる言葉をリストアップしておくことで認識精度を高めているためです。

そこで、以下のようにトピックファイル `dummy_jpj.top` 中に空の(表面上は何もしない)ルールを記述することで単語の候補を与え、特定の単語について精度を高めることも可能です。ただし、列挙した言葉と類似した別の言葉は認識されにくくなる(候補として挙げたもののほうが優先されるようになる)可能性がある点に注意してください。

```
u:(アトリエ)$DummyVar=1
```

このようにして、Dialogについても、イベントを用いることでより応用範囲が広がり、深く理解することができると思います。ぜひ、ドキュメントを確認しながら色々な処理を実現してみてください。