簡単にWEB上でチャットボットを作るpipyライブラリ

# 概要

簡単にチャットボット風のインターフェースを作ることのできるpipyライブラリ(chatbotweb)を作成したので紹介します。
チャットボットを作るフレームワークではありません。
チャットのインターフェースを作るライブラリです。

# chatbotwebでできること


- 複数のユーザーが同時に利用できる（ユーザーごとにパラメータを保持できる）
- pythonコマンド数行でサーバーが起動できる
- LINE風のチャットボット対話が可能な画面
- クエリパラメータを受け取ってボットの挙動を変えることができる
- （firewallとルーターの設定をすれば）グローバルインターネットからアクセスできる

基本は対話システムの研究などに使うことを想定しています（クエリパラメータを使えるようにしているのは、URLをいじるだけで対話システムの挙動等を変えられるようにしているためです）

画面イメージは下記です。

![simplescreenrecorder-2021-07-07_20.04.57-_online-video-cutter.com_-_1_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163759/d50d3d00-808f-c743-32e9-db487a821a16.gif)

# 簡単にやってみる

## 環境

- Ubuntu 18.04
- python 3.6.7
- chatbotweb 0.1.3


## インストール
```
$ pip install chatbotweb
```

## 最小構成

```python
#!/usr/bin/env python
# coding:utf-8

from chatbotweb.chat_server import ChatServer

class MyChatClass():
    BOT_NAME = "BOT"
    html = None

class UserClass():
    def __init__(self, chat_obj):
        self.chat_obj = chat_obj

    def init_function(self, query_params):
        return "オウム返しします"

    def callback_method(self,text, response):
        return text, True

if __name__ == '__main__':
    address = "0.0.0.0"
    port = 49674
    chat_server = ChatServer(MyChatClass,UserClass)
    chat_server.start(address, port)
```

サーバー起動に伴い一回しかインスタンスを生成しなくてよいクラス（myChatClass）と、アクセスしてきたユーザーごとにインスタンスを生成するクラス（UserClass）の２つを作成してChatServerに渡します。詳細はGithubを見てください。
https://github.com/tennmoku71/chatbotweb

## 超簡単なチャットボットを作ってみる
URLのクエリに伴い挙動が変わるところまで確認したいので、名詞を叫ぶBotと風立ちぬ名言Botを作って、２つを切り替えるところまでやってみます。
名詞抽出にはjanomeを使わせていただきます。


```python:test.py
#!/usr/bin/env python
# coding:utf-8

from chatbotweb.chat_server import ChatServer
from janome.analyzer import Analyzer
from janome.tokenfilter import POSKeepFilter

class MyChatClass():

    BOT_NAME = "BOT"
    # override html file
    html = None

    # Run only once when the server starts
    def __init__(self):
        self.analyzer = Analyzer(token_filters=[POSKeepFilter(['名詞'])])

class UserClass():

    # Run only once when accessing from an unknown IP address
    def __init__(self, chat_obj):
        self.mode = None
        self.chat_obj = chat_obj

    # Run when the page is accessed
    # Return value : The first utterance spoken by the robot when accessing the site
    def init_function(self, query_params):
        if "mode" in query_params:
            self.mode = query_params["mode"][0]

        if self.mode == "風立ちぬ":
            return "風立ちぬの名言を何か言ってください"
        elif self.mode == "名詞":
            return "適当な名詞を叫びます"

    # Run when there is a user utterance
    # Return value : Robot replying to user utterance
    def callback_method(self,text):
        if self.mode == "風立ちぬ":
            if "飛行機は戦争の道具でも、商売の手立てでもない" in text:
                return "飛行機は美しい夢だ"
            elif "風が立つ" in text:
                return "生きようと試みなければならない"
        elif self.mode == "名詞":
            meisis = [ token.surface for token in self.chat_obj.analyzer.analyze(text) ]
            if len(meisis) != 0:
                return "%sですか！？" % meisis[0]
            else:
                return "名詞をちゃんと言ってください💢"
        return "ふむふむ"

if __name__ == '__main__':
    # どのIPアドレスも許可する
    address = "0.0.0.0"
    # 適当にポートを決める
    port = 49674
    chat_server = ChatServer(MyChatClass,UserClass)
    chat_server.start(address, port)
```

```
$ pip install janome chtbotweb
$ python test.py
```
ローカルで試したいだけならこれで終わりです。
もしグローバルアクセス可能にしたいなら一番下に書いておくので参考までに見てみてください。


# 試してみる

ブラウザから、まずは通常モード（名詞を叫ぶモード）でやってみます。
http://localhost:49674?mode=名詞

![Screenshot from 2021-07-07 22-22-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163759/c81441f5-af04-1e87-a8e2-b54206d5e32b.png)


次に風立ちぬモードでやってみます。
http://localhost:49674?mode=風立ちぬ

![Screenshot from 2021-07-07 22-18-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163759/3512b43a-d01c-e5da-900f-b15ac981cd93.png)


大丈夫そうですね。




# (おまけ) グローバルアクセスを可能にする

**（注意点）chatbotwebは内部でpythonの標準ライブラリhttp.serverを用いています。こちらは簡易的にサーバーを立てる目的で使わられるもので、外部からアクセス可能な形にすることはセキュリティ上のリスクがあります。身内で使う程度にしておくことをおすすめします（使用は自己責任でお願いします）**

上記を承知した上で進めてみます。
まずはfirewallに穴を開ける必要があります。
今回はUbuntuなので以下のコマンドです。他のOSの場合は別途調べてください。

```
$ sudo ufw activate
$ sudo ufw allow 49674/tcp
$ sudo ufw status

状態: アクティブ

To                         Action      From
--                         ------      ----
49674/tcp                  ALLOW       Anywhere
49674/tcp (v6)             ALLOW       Anywhere (v6) 
```
大丈夫そうですね。
VPSとかを使っているならそれぞれのクラウドサーバー提供業者（AWSとかsakuraとか）の方法に従ってインバウンドルール・アウトバウンドルールを設定する必要があります。
今回は自宅のルータ（Buffalo WSRシリーズ）でやってみようと思います。
ブラウザから http://192.168.11.1 (機種によって違いますがだいたいはこれ)にアクセスして設定画面を開きます。パスワードはほとんどの場合ルーターに貼り付けてあるシールに書いてあります。

![Screenshot from 2021-07-07 21-08-33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163759/3f061b08-ded4-c0db-431d-b3eaea64472d.png)

ポート変換からTCPのポートを開けます。LAN側IPアドレスはUbuntuなら、サーバーを実行するPC上で

```
$ ip a
```

と打つと出てきます。
ズラズラ出てくると思いますので、今回用いるネットワークデバイス選んでおけば良いと思います。（そのルーターに接続しているネットワークカードである必要はあります）
追加できたら終了です。自分のルーターに割り振られているIPアドレスでアクセスしてみてください。

# コメント

ログを保存する機能は必要なのですぐにつけたいと思います。
対話システムをちゃちゃっと作りたいけど、大手チャット型SNSサービスの開発者向けドキュメントとかを読み込むのが面倒くさいという人向けに、開発コストが低い選択肢の一つとなれば良いなと思います。