ChatterBot はじめの一歩

オウム返しするチャットボット(英語)

ライブラリのインストール

$ pip install 'spacy<3'
$ python -m spacy download en

https://scrapbox.io/nikkie-memos/spaCy

プログラム

my_chatbot.py
 1from chatterbot import ChatBot
 2
 3if __name__ == "__main__":
 4    chatbot = ChatBot("Parrot bot", database_uri=None)
 5
 6    while True:
 7        try:
 8            user_input = input("You: ")
 9            response = chatbot.get_response(user_input)
10            print(f"Bot: {response}")
11        except (KeyboardInterrupt, EOFError, SystemExit):
12            break

プログラムの解説

スクリプトとして実行されたときの分岐

3行目の if 文で評価している __name__ == "__main__"python my_chatbot.py のようにスクリプトを実行したときに True となります。

詳しくは https://blog.pyq.jp/entry/Python_kaiketsu_180207 をどうぞ

ChatBot

chatterbot.ChatBot クラスをインスタンス化(4行目)

  • 第1引数はチャットボットの名前
  • database_uri はチャットボットが参照するデータベースの指定
    • None は「 インメモリ のSQLiteを使う」という指定になります
    • Pythonの標準ライブラリの中に sqlite3モジュール があるので、他のインストールは不要でSQLiteを利用できます
    • 発展:SQLite以外のデータベース(MySQLなど)に接続するにはライブラリをインストールします

ドキュメント:https://chatterbot.readthedocs.io/en/stable/chatterbot.html

Botとやり取りするための while ループ

6〜12行目の無限ループについて説明します。 無限ループは続くスクリプトでも共通です。

  • 8行目: input関数
    • 渡された引数 "You: " を画面に出力し、改行が入力されるまで待ちます
    • 改行が入力されたら、改行までの文字列を input 関数の返り値として返します
    • チャットボットに対する 人間の入力を処理 しています
  • 9行目: chatbotget_response メソッド
    • 入力に対してチャットボットの応答を返します
    • chatterbot ライブラリの中で定義されている Statement クラスのインスタンスです
  • 10行目:チャットボットの応答を f-string (変数の指す値を埋め込める文字列)を使って出力します

以上の3行により人間とチャットボットとでやり取りできます。

やり取りを終了するための try - except

11行目で指定している例外について

  • KeyboardInterruptCtrl + C を押したときに送出されます
  • EOFErrorinput 関数が何もデータを読まずに end-of-file (EOF) に達したときに送出されます
  • SystemExitCtrl + D を押したときに送出されます

これらの例外のいずれかが送出されると、12行目の break により、無限ループから抜けます。

実行例

$ python my_chatbot.py
You: Hello
Bot: Hello
You: Hi
Bot: Hello
You: How are you?
Bot: Hello  # Hiが返ることもあります
You: You seem to be fine, right?
Bot: Hello
# Ctrl+C または Ctrl+D で終了します
  • 人間の入力に対して自動応答しています!(これも立派なチャットボットです)
  • 人間の入力は chatterbot によりデータベースに保存されます(長くやり取りすれば Hello 以外が返ってくると思います)
  • 応答は要領を得ないですね → 訓練 していきます

訓練したチャットボット(英語)

プログラム

my_chatbot.py
 1from chatterbot import ChatBot
 2from chatterbot.trainers import ListTrainer
 3
 4conversation = [
 5    "Hello.",
 6    "Hi there!",
 7    "How are you doing?",
 8    "I'm doing great.",
 9    "That is good to hear.",
10    "Thank you.",
11    "You're welcome.",
12]
13
14if __name__ == "__main__":
15    chatbot = ChatBot("Training with list bot", database_uri=None)
16
17    trainer = ListTrainer(chatbot)
18    trainer.train(conversation)
19
20    while True:
21        try:
22            user_input = input("You: ")
23            response = chatbot.get_response(user_input)
24            print(f"Bot: {response}")
25        except (KeyboardInterrupt, EOFError, SystemExit):
26            break

プログラムの解説

チャットボットの「訓練」

conversation が指すリストは、2人のやり取りを表します。 奇数番目と偶数番目で2人いて、チャットボットはどちらも担当できるように「訓練」されます。

  • "Hello." と言われたら "Hi there!" と返す
  • "Hi there!" と言われたら "How are you doing?" と返す

chatterbot ライブラリで「訓練」を担当するのが Trainer です。 ここでは ListTrainer を使って、 conversation のようなリストから訓練します(17, 18行目)。

chatterbot における「訓練」(train)は、 scikit-learn などでの機械学習モデルの訓練(fit)とは異なります。 テキストを検索しやすくなるように前処理して、 データベースに保存しているだけ です。

実行例

$ python my_chatbot.py
List Trainer: [####################] 100%
You: Hello
Bot: Hi there!  # リストの次の文が返ります
You: How are you doing?
Bot: I'm doing great.
You: I'm doing great.
Bot: That is good to hear.
You: Good morning  # リストにない文
Bot: How are you doing?
  • リストにある文を入力すると、その次の文が返っています
  • リストにない文を入力したときも、それなりの応答が返っています
    • 「似ている」訓練した文への応答を返すことをしています
    • 訓練に使う文をもっと増やせばもっとよくなります(後述)
  • データベースを検索 して実現しています
    • 繰り返しますが、チャットボットへの入力は訓練されます(データベースに保存され、今後の応答に使われます)

次は英語から日本語に切り替えましょう。

訓練したチャットボット(日本語)

ライブラリのインストール

$ python -m spacy download ja_core_news_sm

https://scrapbox.io/nikkie-memos/ja_core_news_sm

プログラム

my_chatbot.py
 1from chatterbot import ChatBot
 2from chatterbot.languages import JPN
 3from chatterbot.trainers import ListTrainer
 4
 5conversation = [
 6    "こんにちは",
 7    "どうも!",
 8    "調子はどうですか?",
 9    "順調です",
10    "それはよかったですね。",
11    "ありがとうございます",
12    "どういたしまして",
13]
14
15
16class CustomJPN(JPN):
17    ISO_639_1 = "ja_core_news_sm"
18
19
20if __name__ == "__main__":
21    chatbot = ChatBot(
22        "Training with list bot", database_uri=None, tagger_language=CustomJPN
23    )
24
25    trainer = ListTrainer(chatbot)
26    trainer.train(conversation)
27
28    while True:
29        try:
30            user_input = input("You: ")
31            response = chatbot.get_response(user_input)
32            print(f"Bot: {response}")
33        except (KeyboardInterrupt, EOFError, SystemExit):
34            break

conversation が指すリストを日本語にしました。

プログラムの解説

CustomJPN

ChatBot インスタンスを作るとき(22行目)に tagger_language 引数に指定するクラスを用意します。 この引数に応じて、例えば spaCy のモデルが使われます。

chatterbot.languages.JPN クラスを継承して、カスタマイズしています(16行目)。 chatterbot が裏で spacy.load を呼び出す際に、 "ja_core_news_sm" が指定されるようにします。

カスタマイズする前(chatterbot.languages.JPN

https://github.com/gunthercox/ChatterBot/blob/181c69f2a44c2da88f9352d9c693773b09beb1f5/chatterbot/languages.py#L991 参照

  • ISO_639_1'ja'
  • ISO_639'jpn'
  • ENGLISH_NAME'Japanese'
カスタマイズ後
  • ISO_639_1"ja_core_news_sm" に変更
  • ISO_639 (変更なし)
  • ENGLISH_NAME (変更なし)

ISO_639_1 だけを変えています。 対話モードで from my_chatbot import CustomJPN をして各属性の指す値を確認できます。

実行例

$ python my_chatbot.py
List Trainer: [####################] 100%
You: こんにちは
Bot: どうも!
You: 元気ですか?
Bot: 順調です  # この実行例は非常にうまくいった例です
You: それはよかった
Bot: ありがとうございます

ファイルを使って訓練したチャットボット(日本語)

訓練に使う文をもっと増やせば、チャットボットの応答はもっとよくなりますが、リストだとプログラムが長くなってしまいます。 そこで訓練に使う文を別のファイル(YAML形式)に切り出すことを chatterbot はサポートしています。

ライブラリのインストール

$ pip install 'PyYAML<4'

YAML形式のファイルを解析するためのライブラリです。

会話のデータをファイルに用意

入力と応答の組は chatterbot がサポートするYAMLファイルでは、以下のように表します。

- - 入力
  - 応答

例: "こんにちは" と言われたら "どうも!" と返す

- - こんにちは
  - どうも!

conversation が指すリストをファイルで表すと次のようになります。

greetings_ja.yml
categories:
- greetings
conversations:
- - こんにちは
  - どうも!
- - どうも!
  - 調子はどうですか?
- - 調子はどうですか?
  - 順調です
- - 順調です
  - それはよかったですね。
- - それはよかったですね。
  - ありがとうございます
- - ありがとうございます
  - どういたしまして

ファイルの配置

.
├── env
├── greetings_ja.yml
└── my_chatbot.py

プログラム

my_chatbot.py
 1from pathlib import Path
 2
 3from chatterbot import ChatBot
 4from chatterbot.languages import JPN
 5from chatterbot.trainers import ChatterBotCorpusTrainer
 6
 7
 8class CustomJPN(JPN):
 9    ISO_639_1 = "ja_core_news_sm"
10
11
12if __name__ == "__main__":
13    cli_dir_path = Path(__file__).resolve().parent
14    data_yml_path = cli_dir_path / "greetings_ja.yml"
15
16    chatbot = ChatBot(
17        "Training from yaml bot", database_uri=None, tagger_language=CustomJPN
18    )
19
20    trainer = ChatterBotCorpusTrainer(chatbot)
21    trainer.train(str(data_yml_path))
22
23    while True:
24        try:
25            user_input = input("You: ")
26            response = chatbot.get_response(user_input)
27            print(f"Bot: {response}")
28        except (KeyboardInterrupt, EOFError, SystemExit):
29            break

プログラムの解説

ChatterBotCorpusTrainer

ファイルを使った訓練に使う Trainer です。

train メソッドにファイルのパスを表す文字列を指定しています(21行目)。

pathlib

chatterbot 関係のトピックというより、Pythonについてのトピックです

ファイルパスなどのパスを扱うモジュールです(標準ライブラリにあります)。

https://docs.python.org/ja/3/library/pathlib.html

str(data_yml_path) では、パスオブジェクトをパスを表す 文字列 に変えています。

>>> from pathlib import Path
>>> data_yml_path = Path("greetings_ja.yml")
>>> type(data_yml_path)
<class 'pathlib.PosixPath'>
>>> data_yml_path
PosixPath('greetings_ja.yml')
>>> str(data_yml_path)
'greetings_ja.yml'

訓練に使った文は前項と共通なので、実行例は省略します。

コーパスを使って訓練したチャットボット(日本語)

コーパスとは、言語の使用方法を蓄積した文書集合。

https://scrapbox.io/nikkie-memos/%E3%82%B3%E3%83%BC%E3%83%91%E3%82%B9

ライブラリのインストール

XXX: インストールがうまくいかない事象が発生中(👉Workaround追加)

$ pip install pypandoc  # Workaround
$ pip install git+https://github.com/gunthercox/chatterbot-corpus

2021/11時点では 1.2.0 が入ります。

プログラム

my_chatbot.py
 1from chatterbot import ChatBot
 2from chatterbot.languages import JPN
 3from chatterbot.trainers import ChatterBotCorpusTrainer
 4
 5
 6class CustomJPN(JPN):
 7    ISO_639_1 = "ja_core_news_sm"
 8
 9
10if __name__ == "__main__":
11    chatbot = ChatBot("Training from corpus bot", tagger_language=CustomJPN)
12
13    trainer = ChatterBotCorpusTrainer(chatbot)
14    trainer.train("chatterbot.corpus.japanese")
15
16    while True:
17        try:
18            user_input = input("You: ")
19            response = chatbot.get_response(user_input)
20            print(f"Bot: {response}")
21        except (KeyboardInterrupt, EOFError, SystemExit):
22            break

プログラムの解説

database_uri 引数を指定しない(11行目)

訓練や入力された文は (メモリ上ではなく) db.sqlite3 というファイルに保存されます。 ファイルに保存されるのでスクリプトを終了しても残ります。

trainメソッドの引数(14行目)

https://github.com/gunthercox/chatterbot-corpus/tree/master/chatterbot_corpus/data/japanese にあるYAMLファイル全部使って訓練するように指定しています。

発展: chatterbot.corpus を読み込んだときに chatterbot_corpus が読み込めるか試みます。 読み込めた場合は chatterbot_corpusdata 以下のディレクトリがコーパスとして指定できます。

スクリプトを実行してチャットボットとやり取りしてみてください!

ライブラリのインストールがうまくいかない場合

GitHubの代わりにPyPIからインストール

$ pip install chatterbot-corpus

このとき 日本語のコーパスはインストールされません。 なので、英語のコーパスを代わりに指定して動くことを確認してください(14行目)。

trainer.train("chatterbot.corpus.english")