会話エンジンにWatson Conversationを使ったSlack botを作ってみた

最近githubに公開された[botkit-middleware](https://github.com/watson-developer-cloud/botkit-middleware "botkit-middleware")を使って会話エンジンにWatson Conversationを使用したSlack botを作成してみました。
この投稿では、その作成手順を紹介します。

手順は以下の3ステップになります。
1. Watson ConversationのWorkspace作成
2. SlackにBotを追加 
3. サンプルコード実行
## botkit-middlewareとは
会話エンジンにWatson Conversationを使用したSlack botを簡単に作れるBotkitプラグインです。
Slack以外にもFacebookメッセンジャーやTwilioにも対応しているようです。

[botkit-middleware](https://github.com/watson-developer-cloud/botkit-middleware "botkit-middleware")から引用
>This middleware plugin for Botkit allows developers to easily integrate a Watson Conversation workspace with multiple social channels like Slack, Facebook, and Twilio. Customers can have simultaneous, independent conversations with a single workspace through different channels.

## Watson Conversationとは
以下のQiitaの記事が参考になります。
[BluemixのWatson Conversation(beta)を触ってみた](http://qiita.com/ishida330/items/f2bb85788815e183e29b "BluemixのWatson Conversation(beta)を触ってみた")
[チャットボットを簡単に作れる！Watson Conversationの色々なTips（メモ）](http://qiita.com/ishida330/items/ae7277598cd3e08fc3a2 "チャットボットを簡単に作れる！Watson Conversationの色々なTips（メモ）")

# 作成ステップ

## 1. Watson ConversationのWorkspace作成
この投稿では、会話定義は行わず作成済みの会話をImportしてWorkspaceを作成します。
以下の会話定義をコピーして、任意の名前（例：conversation_test.json）で保存します。（注意！！**文字コードはUTF-8**で保存してください。**拡張子はjson**にしてください）

```text:会話定義
{"name":"天気","created":"2016-10-30T12:38:45.878Z","intents":[{"intent":"天気予報","created":"2016-10-30T12:38:45.878Z","examples":[{"text":"てんき","created":"2016-10-30T15:44:30.406Z"},{"text":"てんきは？","created":"2016-10-30T15:44:38.904Z"},{"text":"今日の天気は","created":"2016-10-30T12:38:45.878Z"},{"text":"天候は","created":"2016-10-30T12:38:45.878Z"},{"text":"天気","created":"2016-10-30T12:38:45.878Z"},{"text":"天気は？","created":"2016-10-30T12:38:45.878Z"}],"description":null},{"intent":"挨拶","created":"2016-10-30T12:38:45.878Z","examples":[{"text":"おはよう","created":"2016-10-30T12:38:45.878Z"},{"text":"こんにちは","created":"2016-10-30T12:38:45.878Z"},{"text":"こんばんは","created":"2016-10-30T12:38:45.878Z"},{"text":"Hello","created":"2016-10-30T12:38:45.878Z"},{"text":"Hi","created":"2016-10-30T12:38:45.878Z"},{"text":"今日は","created":"2016-10-30T12:38:45.878Z"},{"text":"今晩は","created":"2016-10-30T12:38:45.878Z"}],"description":null}],"updated":"2016-10-30T15:44:38.904Z","entities":[{"type":null,"entity":"place","source":null,"values":[{"value":"三重","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["三重県"]},{"value":"京都","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["京都府"]},{"value":"佐賀","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["佐賀県"]},{"value":"兵庫","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["兵庫県"]},{"value":"北海道","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":[]},{"value":"千葉","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["千葉県"]},{"value":"和歌山","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["和歌山県"]},{"value":"埼玉","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["埼玉県"]},{"value":"大分","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["大分県"]},{"value":"大阪","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["大阪府"]},{"value":"奈良","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["奈良県"]},{"value":"宮城","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["宮城県"]},{"value":"宮崎","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["宮崎県"]},{"value":"富山","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["富山県"]},{"value":"山口","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["山口県"]},{"value":"山形","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["山形県"]},{"value":"山梨","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["山梨県"]},{"value":"岐阜","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["岐阜県"]},{"value":"岡山","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["岡山県"]},{"value":"岩手","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["岩手県"]},{"value":"島根","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["島根県"]},{"value":"広島","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["広島県"]},{"value":"徳島","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["徳島県"]},{"value":"愛媛","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["愛媛県"]},{"value":"愛知","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["愛知県"]},{"value":"新潟","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["新潟県"]},{"value":"東京","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["東京都"]},{"value":"栃木","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["栃木県"]},{"value":"沖縄","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["沖縄県"]},{"value":"滋賀","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["滋賀県"]},{"value":"熊本","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["熊本県"]},{"value":"石川","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["石川県"]},{"value":"神奈川","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["神奈川県"]},{"value":"福井","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["福井県"]},{"value":"福岡","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["福岡県"]},{"value":"福島","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["福島県"]},{"value":"秋田","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["秋田県"]},{"value":"群馬","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["群馬県"]},{"value":"茨城","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["茨城県"]},{"value":"長崎","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["長崎県"]},{"value":"長野","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["長野県"]},{"value":"青森","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["青森県"]},{"value":"静岡","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["静岡県"]},{"value":"香川","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["香川県"]},{"value":"高知","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["高知県"]},{"value":"鳥取","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["鳥取県"]},{"value":"鹿児島","created":"2016-10-30T12:38:45.878Z","metadata":null,"synonyms":["鹿児島県"]}],"created":"2016-10-30T12:38:45.87881","open_list":false,"description":null}],"language":"ja","metadata":null,"description":null,"dialog_nodes":[{"go_to":null,"output":{"text":"よくわかりません"},"parent":null,"context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"node_2_1476582875665","previous_sibling":"node_8_1476583489944"},{"go_to":null,"output":{"text":"<? input.text ?>！ 挨拶以外に 天気予報ができます。（質問例：東京の天気は？、天気）"},"parent":null,"context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"#挨拶","description":null,"dialog_node":"node_8_1476583489944","previous_sibling":"node_3_1476582879459"},{"go_to":null,"output":{"text":"何かごようですか。挨拶と天気予報ができます。\n（質問例：おはよう、東京の天気は？、天気）"},"parent":null,"context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"conversation_start","description":null,"dialog_node":"node_1_1476582847892","previous_sibling":null},{"go_to":null,"output":{"text":{"values":["@place の天気は晴れです。","@place の天気は曇りです。","@place の天気は雨です。"],"selection_policy":"random"}},"parent":"node_3_1476582879459","context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"@place","description":null,"dialog_node":"node_11_1476583928468","previous_sibling":null},{"go_to":{"return":null,"selector":"condition","dialog_node":"node_11_1476583928468"},"output":{},"parent":null,"context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"#天気予報","description":null,"dialog_node":"node_3_1476582879459","previous_sibling":"node_1_1476582847892"},{"go_to":{"return":null,"selector":"user_input","dialog_node":"node_11_1476583928468"},"output":{"text":"どこの天気ですか？\n（回答例：東京、千葉）"},"parent":"node_3_1476582879459","context":null,"created":"2016-10-30T12:38:45.878Z","metadata":null,"conditions":"true","description":null,"dialog_node":"node_7_1476583055016","previous_sibling":"node_11_1476583928468"}],"workspace_id":"eda1c0ef-53ae-43c6-924a-5bbdc7eeccdd"}

```
保存したファイルをImportするため、Conversation toolを起動します。
Watson Conversationの「管理」タブの「Launch tool」ボタンから、起動します。

![キャプチャ1111.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/5d43deee-924d-43b1-e7af-30a325a06610.png)

「Create」ボタンの右にある、「Import」ボタンを押します。
![キャプチャ6.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/9b79bb08-cbb9-583a-f6a3-bbb906408620.png)

先ほど保存した会話定義をImportします。
ImportのタイプはEverythingを選択します。「Import」ボタンを押します。
![キャプチャ7.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/72da2a17-2762-6df9-5585-88d7bad2d4a6.png)

Importが完了すると「天気」という名前のWorkspaceが出来るので、右上にあるメニューから「View details」を選択します。

![キャプチャ8.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/f614d3f5-feef-0f80-3a27-8e069f7837a0.png)

詳細画面では、WorkspaceIDが表示されます。
**こちらのIDは後ほど使用しますので控えておいてください。**
![キャプチャ9.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/bfddfcd0-7af6-c15f-f278-050090135ecd.png)

また、Watson Conversationの「サービス資格情報」タブに表示されるusername、passwordも**後ほど使用しますので控えておいてください。**
![キャプチャ10.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/52b6b312-fa08-5d1d-4e62-3c0448551e69.png)



## 2. SlackにBotを追加 

Slack App DirectoryのManageのCustom Integrationsの画面（以下のリンクで飛べます）からBotを追加します。「Bots」をクリックします。
https://my.slack.com/apps/manage/custom-integrations

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/0b179f94-530d-419b-556a-6320b22c8d55.png)

「Add Configuration」ボタンを押します。
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/15b2d99b-4caa-0fcb-55aa-7627cd153e68.png)

Usernameに任意の名前を付けます。ここではwatson-conversationとしています。
名前を付けたら、「Add bot integration」ボタンを押します。
![キャプチャ3.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/8d33fec6-d764-e7b5-621f-16144096f472.png)

作成後、API Tokenが生成されます。**後ほど使いますので控えておいてください。**
![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/d5fc2d0a-2443-ca41-f8ce-0d1a32d8f7f7.png)



Slackのチームの画面に戻り（以下のリンクで飛べます）Botが追加されていることを確認します。Botがいない場合には、DIRECT MESSAGESから探してみてください。
https://my.slack.com/messages

![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/c5f22f02-79ec-d0ca-3a9c-ac2045ecabaa.png)

## 3. サンプルコード実行

botkit-middlewareのサンプルコードをダウンロードし、今回使用するsimple-botディレクトリに移動します。

```text
git clone https://github.com/watson-developer-cloud/botkit-middleware.git
cd botkit-middleware\examples\simple-bot
```
この投稿作成時には、simple-botディレクトリのpackage.jsonの"botkit-middleware-watson"のバージョン指定が"^0.0.1"のままでは動かなかったため、"^1.0.0"に変更しています。

```text:package.json（修正後）
{
  "name": "botkit-middleware-watson-simple-example",
  "version": "0.0.1",
  "description": "Simple Slack bot example using botkit-middleware-watson with Botkit.",
  "main": "simple-bot-slack.js",
  "scripts": {
    "start": "node simple-bot-slack.js"
  },
  "license": "Apache-2.0",
  "dependencies": {
    "botkit": "^0.2.2",
    "dotenv": "^2.0.0",
    "express": "^4.13.4",
    "botkit-middleware-watson": "^1.0.0"
  }
}
```
以下のコマンドで依存ライブラリを導入します。

```
npm install
```

simple-botディレクトリにある.envファイルの内容を前のステップで控えておいたIDやパスワードに変更します。

```text:.env
#WATSON
CONVERSATION_USERNAME=username
CONVERSATION_PASSWORD=password
WORKSPACE_ID=your_workspace_id

#SLACK
SLACK_TOKEN=your_slack_bot_token
```

以下のコマンドでアプリケーションを起動します。

```
npm start

上記コマンド実行時の出力
> botkit-middleware-watson-simple-example@0.0.1 start C:\work\test\botkit-middleware\examples\simple-bot
> node simple-bot-slack.js

info: ** No persistent storage method specified! Data may be lost when process shuts down.
info: ** Setting up custom handlers for processing Slack messages
info: ** API CALL: https://slack.com/api/rtm.start
Client server listening on port 5000
notice: ** BOT ID: watson-conversation ...attempting to connect to RTM!
notice: RTM websocket opened
```

起動後、SlackのBotがactiveになります。

![キャプチャ12.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/a1d55497-8845-ae88-7662-313ecf4ee5ef.png)

DIRECT MESSAGESで何か話しかけると以下のような会話ができます。

![キャプチャ11.PNG](https://qiita-image-store.s3.amazonaws.com/0/103795/15674e97-ea85-626b-fccf-bc7a943a1539.png)

これで、会話エンジンにWatson Conversationを使ったSlack botが完成しました。