Pepper上にSlackBotのサービスを作成する

# Pepper内でSlackBotを実行したかった。
今までSlackとPepperの連動はSlackのIncoming WebHookを使用して行っていました。
お仕事アプリからrequestモジュールを使って投稿していましたが、
Slack側からの通知を受け取れるようにしたいと思い、SlackBotのPepperへの搭載を考えました。

## 全お仕事アプリで横断的に使用したい。
SlackBotを使用してやりたかったこと。

 - PepperのBotを集めたチャンネルを作る。
  - Bot宛てのメッセージでPepperに各種イベントを送信する。
  - @Channel宛てのメッセージで全Pepperに各種イベントを送信する。
  - Pepperの各種センサ情報をSlackに収集する。


また、お仕事アプリによらず横断的に使用したかったため、こちら方の記事を参考にサービスとして実装してみました。
http://qiita.com/yacchin1205/items/11301d79380d08d2dbf6

# 開発環境
Mac OS Sierra
Python 2.7.10

# SlackでBotを有効にする

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/134694/ccc1e4aa-64c8-12ea-9323-7af5ebccc4fa.png)

# 環境構築
## QiBuildのインストール

```
pip install qibuild
```

## PythonSDKのインストール

最新版ではなく以下のバージョンを落としてきてください。
最新版（執筆時点では2.5.5）はどうやら変更点が多いようで、参考になる情報も少なかったので、2.4.3をダウンロードしました。

```
pynaoqi-python2.7-2.4.3.28-mac64
```

pathを通しておきます。
また、.bash_profileに追記しておきます。

```
$ export PYTHONPATH=${PYTHONPATH}:/path/to/pynaoqi-python2.7-2.4.3.28-mac64
$ export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/path/to/pynaoqi-python2.7-2.4.3.28-mac64
```

パスが通っていれば以下のコマンドが使用できます。

```
$ python

>> import qi
>> import naoqi
```

## ワークツリーの準備
最終的に必要になる環境は以下の通りです。

```
SlackBotService
　qiproject.xml
　manifest.xml
　slackbotservice.py
　slackbotservice.pml
　bot_settings.py
　lib
　　backports
　　slackbot
　　slacker
　　websocket
　　six.py
　　plugins
　　　__init__.py
　　　mention.py
　　　proxy.py
```

プロジェクトのディレクトリと同階層で以下のコマンドを実行します。
下の階層で各種ビルド、パッケージングができるようになります。

```
$ pwd
/path/to/SlackBotService
$ qibuild init
$ qipy bootstrap
```

# slackbotモジュールをインストール

```
$ pip install slackbot
```

必要なモジュールがまとめてインストールされます。
インストールされた以下のモジュールをSlackBotService/lib配下にコピーします。

```
$ pwd
/path/to/SlackBotService/lib
$ ls
backports/
slackbot/
slacker/
websocket/
six.py

```

websocket/cacert.pemをSlackBotService/lib配下にコピーします。

```
$ pwd
/path/to/SlackBotService/lib
$ ls
backports/
slackbot/
slacker/
websocket/
six.py
cacert.pem
```

# SlackBotを実装する

## 設定を記述

SlackBotの設定を記述します。

```
SlackBotService/bot_settings.py
```

```
# -*- coding: utf-8 -*-

import os
from slackbot import settings

settings.API_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
settings.DEFAULT_REPLY = u"よくわかりません。"
settings.PLUGINS = [
    'plugins',
]

os.environ['WEBSOCKET_CLIENT_CA_BUNDLE'] = os.path.join('./bin', 'cacert.pem')
```

以下の部分は、パッケージング時にバンドルされない上述の鍵ファイルを読み込ませています。
当然警告は出ますが、Pepper本体の環境を汚したくなかったので一旦こうしました。

```
os.environ['WEBSOCKET_CLIENT_CA_BUNDLE'] = os.path.join('./bin', 'cacert.pem')
```




## サービスとして起動されるメインスクリプトを実装

スクリプトの実行時にSlackBotをrunします。

```
SlackBotService/slackbotservice.py
```

```
# -*- coding: utf-8 -*-

from slackbot.bot import Bot
from bot_settings import *


class SlackBotService:
    def __init__(self):
        self.bot = Bot()
        self.bot.run()


def main():
    slackbotservice = SlackBotService()


if __name__ == "__main__":
    main()

```

## SlackBotのプラグインを実装
何か話かけられたら、Pepperが発話するようにしてみます。

```
SlackBotService/lib/plugins/mention.py
```

```
# -*- coding: utf-8 -*-

from slackbot.bot import respond_to, listen_to
from slacker import Slacker
from plugins import proxy
from bot_settings import settings

slack = Slacker(settings.API_TOKEN)


@respond_to(u'')
def respond_any_word(message):
    """
    任意の文字を受け取る。
    :param message: 受け取ったメッセージオブジェクト
    """
    _text = message.body.get('text', '')
    _ts = message.body.get('ts', '')
    _user = message.body.get('user', '')
    _team = message.body.get('team', '')
    _type = message.body.get('type', '')
    _channel = message.body.get('channel', '')
    proxy.animated_speech(_text)
    message.reply("done")
```

## Pepperに発話させるためのプロキシーを実装

```
SlackBotService/lib/plugins/proxy.py
```

```
# -*- coding: utf-8 -*-

from naoqi import ALProxy

animatedSpeechProxy = ALProxy("ALAnimatedSpeech", "127.0.0.1", 9559)


def animated_speech(text):
    _text = text if isinstance(text, str) else text.encode("utf-8")
    configuration = {"bodyLanguageMode": "contextual"}
    animatedSpeechProxy.say(_text, configuration)

```

# アプリをパッケージングする

## qiproject.xml
バンドルするモジュールを定義します。
ライブラリや、スクリプトなど必要なモジュールはもれなく定義します。

```
<project version="3">
    <qipython name="slackbotservice">
        <package name="backports" src="lib" />
        <package name="slackbot" src="lib" />
        <package name="slacker" src="lib" />
        <package name="websocket" src="lib" />
        <package name="plugins" src="lib" />
        <script src="lib/six.py" />
        <script src="lib/cacert.pem" />
        <script src="slackbotservice.py" />
        <script src="bot_settings.py" />
    </qipython>
</project>
```

## manifest.xml
サービスの定義をします。
\<service />タグではPepper内で認識されるサービスとしての情報を定義します。

 - name
  - サービスの物理名を定義します。ここで定義した名前で各種qicliコマンドやアプリからサービスの呼び出しが可能です。
 - autorun
  - 自動的に起動するようにtrueを指定しておきます。
 - execStart
  - サービスとして実行するスクリプトを定義します。アプリケーションにバンドルされたpythonを使用するようにします。


```
<package uuid="slackbotservice" version="0.1.0">
    <services>
        <service name="SlackBotService" autorun="true"
            execStart="/bin/bash ./python bin/slackbotservice.py" />
        <executableFiles>
            <file path="python" />
        </executableFiles>
    </services>
    <requirements>
        <naoqiRequirement minVersion="2.3"/>
        <robotRequirement model="JULIETTE"/>
    </requirements>
</package>
```

## .pmlファイル
パッケージの定義を行います。

```
<?xml version="1.0" encoding="UTF-8" ?>
<Package name="slackbotservice" format_version="4">
    <Manifest src="manifest.xml" />
    <qipython name="slackbotservice" />
</Package>
```

## プロジェクトのパッケージング

```
$ qipy install slackbotservice
$ qipkg make-package slackbotservice.pml
```

## パッケージのデプロイ

```
$ qipkg deploy-package slackbotservice-0.1.0.pkg --url nao@<PepperのIP>
```

## 動作確認してみる


![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/134694/110a54d4-9d15-63a4-5fca-c3e8fbe0b791.png)

Slack経由でPepperに発話させることができるようになりました！


## 今後
各種AL系のモジュールの呼び出しがSlack経由でできるようになるので、非常に便利でした。
現時点ではサービスとしてレジストしていないので各種お仕事アプリからSlackBotを操作することはできません。
サービスとしてレジストすることでSlackBot自体の起動、停止、お仕事アプリとのメッセージのやり取りなどができるようになります。

SlackBotをうまく使えば、お仕事アプリ間の連携や、Pepper間のやり取りなんかにも使えるのではないかと思っています。