PepperのQiChatスクリプトに外部データなどから動的な値を与えるには

　PepperのQiChatのスクリプトに外部データなどから動的に値を与えたいとった場合にどうすればいいか調べてみました。　動的に値を与えるにはALMemoryのメモリ変数と、ALDialogのsetConceptを使用するようです。

#注意事項
　ソフトバンクロボティクス株式会社のPepperを活用し、独自開発したものです。

参考
　 こちらの資料を参考にさせていただきました。

 　[タブレットの表示機能を駆使しながら会話をしてくれる Pepper アプリを作ってみる](http://qiita.com/tkawata1025/items/fa4649980e4b62920038)
　[ALDialog/QiChatメモ](http://qiita.com/G-angle/items/ef301e7869db25ed42d9)
　[個別のPepperちゃんの語彙を動的に増やす](http://qiita.com/chiwa/items/43a123b66a63a07e88df)

#環境について
今回使用した環境です。
MacOS Sierra 10.12.2
Choregraphe 2.4.3.28
Pepper

#サンプルについて
 作成したサンプルはこちらです。
 https://github.com/piroku/QiChatSample

![QiChat1.png](https://qiita-image-store.s3.amazonaws.com/0/131693/abbdbc8a-8015-9f34-5df7-34fba57b815a.png)

何回か実行した結果（人間のメッセージは直接入力しています）
![QiChat2.png](https://qiita-image-store.s3.amazonaws.com/0/131693/1e31d64f-9814-2142-37f1-d2d543c97f4a.png)

##QiChatスクリプト
　conceptのようなキーワードを動的に与えるには、conceptではなくdynamicで定義します。
　dynamicの設定名は、conceptと同じように(~ + 設定名)で記述できます。
　また、各発話のメッセージは変数で指定しています。

###解説
　onStartで\$QiChatSample/onStartMessageの内容を発話して、(~dy_ans_1)〜(~dy_ans_3)を待ちます。
　(~dy_ans_1)〜(~dy_ans_3)が聞き取れたら、対応するメッセージ\$QiChatSample/dyAns1Message〜\$QiChatSample/dyAns３Messageを発話し、終了メッセージ\$QiChatSample/endMessageを発話して終了します。
　聞き取れなかった時は、\$QiChatSample/stayMessageを発話し、聞き取りを継続します。
　また、頭(先頭)をタッチすると終了メッセージを発話して終了するようにしています。

```:QiChat.jpj.top
topic: ~QiChat()
language: jpj

dynamic:dy_ans_1
dynamic:dy_ans_2
dynamic:dy_ans_3

u:(e:onStart) ^mode(contextual) $QiChatSample/onStartMessage
    u1:(~dy_ans_1) $QiChatSample/dyAns1Message $output="dy_ans_1" \pau=200\ $QiChatSample/endMessage $onStopped=1
    u1:(~dy_ans_2) $QiChatSample/dyAns2Message $output="dy_ans_2" \pau=200\ $QiChatSample/endMessage $onStopped=1
    u1:(~dy_ans_3) $QiChatSample/dyAns3Message $output="dy_ans_3" \pau=200\ $QiChatSample/endMessage $onStopped=1
    u1:(e:Dialog/NotUnderstood) $QiChatSample/stayMessage ^stayInScope

u:(e:FrontTactilTouched) $QiChatSample/endMessage $onStopped=1
```

##bx_データ読み込みボックス
 JSONデータを読み込みます。実際にはREST API等で提供できる形にしておき、Pepperで取り込むといった形になるのではと思います。

```json:init_data.json
{
  "onStartMessage": "\\rspd=110\\\\vct=135\\今日の調子はどう？",
  "ans_1": {
    "concept": "元気,元気だよ,バッチリ,調子いい,調子良い,いいよ",
    "message": "\\rspd=110\\\\vct=135\\今日も1日\\rspd=120\\がんばろー"
  },
  "ans_2": {
    "concept": "悪い,調子悪い,良くない,だるい,眠い,帰りたい",
    "message": "\\rspd=110\\\\vct=135\\こんな日もあるよ|\\pau=200\\\\vct=140\\どんまい!"
  },
  "ans_3": {
    "concept": "まあまあ,いまいち,普通",
    "message": "\\rspd=110\\\\vct=135\\張り切っていこー"
  },
  "stayMessage": "\\rspd=110\\\\vct=130\\聞き取れなかった|もう一度お願い！",
  "endMessage": "\\rspd=110\\\\vct=135\\終了するね"
}
```

##bx_ダイアログ設定_日本語版ボックス
 ALDialogのsetConceptを使用して、QiChatスクリプトで定義したdynamicの定義名(例:dy_ans_1)に対して、キーワードのリストを設定します。サンプルプログラムでは、JSONデータでconceptキーに指定された値(例:"元気,元気だよ,バッチリ,調子いい,調子良い,いいよ")をリストに変換したものをsetConceptで使用します。


```py:bx_ダイアログ設定_日本語版ボックス(一部)
  #外部データの取得
  data = memory.getData("QiChatSample/InitData")
  initdata = json.loads(data)
            
  dy_ans_1=initdata["ans_1"]["concept"].encode("utf-8").split(",")
  dy_ans_2=initdata["ans_2"]["concept"].encode("utf-8").split(",")
  dy_ans_3=initdata["ans_3"]["concept"].encode("utf-8").split(",")
            
  #QiChatのスクリプトでdynamicで指定した名前でセットする
  dialog.setConcept("dy_ans_1", "jpj", dy_ans_1)
  dialog.setConcept("dy_ans_2", "jpj", dy_ans_2)
  dialog.setConcept("dy_ans_3", "jpj", dy_ans_3)
```

また、QiChatスクリプトで定義したALMemoryの変数も設定します。

```py:bx_ダイアログ設定_日本語版(一部)
　　　　#QiChatに定義したメッセージ変数のセット
  memory.insertData("QiChatSample/onStartMessage", initdata["onStartMessage"].encode("utf-8"))
  memory.insertData("QiChatSample/stayMessage", initdata["stayMessage"].encode("utf-8"))
  memory.insertData("QiChatSample/dyAns1Message", initdata["ans_1"]["message"].encode("utf-8"))
  memory.insertData("QiChatSample/dyAns2Message", initdata["ans_2"]["message"].encode("utf-8"))
  memory.insertData("QiChatSample/dyAns3Message", initdata["ans_3"]["message"].encode("utf-8"))
  memory.insertData("QiChatSample/endMessage", initdata["endMessage"].encode("utf-8"))　
```

#うまくいかないとき
　QiChatのスクリプトで、同じ定義名でconceptで定義して実行してしまうと、QiChatスクリプトを書き換えてもダメなようです。Pepperを再起動することで忘れてくれました。
　また、もし何度かプログラムをエラーなどで中断させてしまった場合で、その後思ったように動作しないとった場合は、Pepperのロボアプリ一覧から、「.lastUploadedChoregrapheBehavior」を消すか、Pepperを再起動してみてください。