ChatterBot はじめの一歩¶
オウム返しするチャットボット(英語)¶
ライブラリのインストール¶
$ pip install 'spacy<3'
$ python -m spacy download en
プログラム¶
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
となります。
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行目:
chatbot
のget_response
メソッド- 入力に対してチャットボットの応答を返します
chatterbot
ライブラリの中で定義されているStatement
クラスのインスタンスです
- 10行目:チャットボットの応答を f-string (変数の指す値を埋め込める文字列)を使って出力します
以上の3行により人間とチャットボットとでやり取りできます。
やり取りを終了するための try
- except
¶
11行目で指定している例外について
- KeyboardInterrupt :Ctrl + C を押したときに送出されます
- EOFError :
input
関数が何もデータを読まずに end-of-file (EOF) に達したときに送出されます - SystemExit :Ctrl + 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 以外が返ってくると思います) - 応答は要領を得ないですね → 訓練 していきます
訓練したチャットボット(英語)¶
プログラム¶
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
プログラム¶
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
)¶
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
はサポートしています。
会話のデータをファイルに用意¶
入力と応答の組は chatterbot
がサポートするYAMLファイルでは、以下のように表します。
- - 入力
- 応答
例: "こんにちは"
と言われたら "どうも!"
と返す
- - こんにちは
- どうも!
conversation
が指すリストをファイルで表すと次のようになります。
categories:
- greetings
conversations:
- - こんにちは
- どうも!
- - どうも!
- 調子はどうですか?
- - 調子はどうですか?
- 順調です
- - 順調です
- それはよかったですね。
- - それはよかったですね。
- ありがとうございます
- - ありがとうございます
- どういたしまして
ファイルの配置
.
├── env
├── greetings_ja.yml
└── 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
プログラムの解説¶
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
が入ります。
プログラム¶
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_corpus
の data
以下のディレクトリがコーパスとして指定できます。
スクリプトを実行してチャットボットとやり取りしてみてください!
ライブラリのインストールがうまくいかない場合¶
GitHubの代わりにPyPIからインストール
$ pip install chatterbot-corpus
このとき 日本語のコーパスはインストールされません。 なので、英語のコーパスを代わりに指定して動くことを確認してください(14行目)。
trainer.train("chatterbot.corpus.english")