
今回はプログラミング初心者向けに、簡単なチャットボットの作り方を解説していきます。
という僕も初心者なんですがね。
まあ、あれですよ。大学の授業でそういう課題があったんです。
チャットボットとは
チャットボットとは、人間と会話するコンピュータです。
最近では宅急便のラインでの問い合わせなんかも、チャットボットになっています。
つまるところ、人間が何かしら入力するとコンピュータが返答してくれる、プログラムです。
この「チャットボット」には大きく分けて2種類あります。
ルール型と機械学習型です。
ルール型は「こういう文章に対してはこう返答する」みたいな感じで、あらかじめ解答を用意しておくタイプです。
人工無脳なんて呼ばれたりする。
機械学習型はその名の通り、学習しながら解答をします。
一時期話題になった、りんなは機械学習型です。膨大な会話データからそれっぽい返事をするやつです。
とまあ、ルール型と機械学習型があるわけですが、なんとなく機械学習型の方が高性能そうですよね?
用途にもよりますが、一般的には機械学習型の方が自然?な会話ができます。(家電の音声操作ではルール型で十分だったり)
でもごめんね。今から紹介するのはルール型です。
僕も初心者なんです。機械学習は環境が色々と面倒なんです。
プログラムの説明
というわけでプログラムの説明です。
このチャットボットがルール型だというのはさっき言った通りです。
入力した文章はまず形態素解析によって要素ごとに区切られます。
そしてあらかじめ用意しておいた、質問と回答のデータベースの中から、一番似ているものを選んで、その解答を出力するという感じです。
例えば、「今日の天気は?」という文章を入力すると、今日、の、天気、は、という感じで分けられます。
そして、分割した要素と一番被っている要素が多いデータベースを参照する、という仕組みです。
もしデータベース(質問:解答)が
明日の天気は?:自分で調べろや、アホ。
こんにちは:イェ―――――――――イ!!!!
好きな食べ物は?:ガソリンです。もちろんハイオクですよ。
こんな感じなら「今日の天気は?」という質問に対して、「明日の天気は?」が一番近い文章になるので、「自分で調べろや、アホ。」と出力されるわけです。
この例からも分かるように、データベースに無い質問をされると詰みます。変な解答を返します。
そこがデータベース型の欠点ですね。
環境構築
このプログラムはC#で書きます。
なので、開発にはVisual Studioを使います。
Visual Studioの導入方法はこちらの記事をどうぞ!
今回はC#なので.NETデスクトップ開発が必要です。
新しいプロジェクトの作成をして、テンプレートはコンソールアプリ(.NET Framework)を使います!
そしたら、MeCabという形態素解析するライブラリを導入していきます。
上のタブの、
ツール→NuGetパッケージマネージャー→ソリューションのNuGetパッケージの管理を選択します。

そしたら、参照で「mecab」を検索します。そしてチェックボックスにチェックをつけて、NMeCabをインストールします。

同意は適当にしといてください。これでMeCabがインストールできたはず。
コード解説
はあ、ここまで長かった。ではコードを解説していきます。
以下のusingディレクティブを使います。
using System;
using System.Collections.Generic;
using System.IO;
using NMeCab;
プラグラムの最初につけておいてください。
public static void Main(string[] args)
{
while (true)
{
var words = Console.ReadLine();
Recog(words);
}
}
ここで言うwordsは入力です。Recogはメソッドです。次で解説するよ。
まあ、入力に対して返答する、というプログラムを1セットとして無限ループします。
static void Recog(string words)
{
var tagger = NMeCab.MeCabTagger.Create();
var db = new QADatabase(@"E:\daigo\Desktop\Programing\C#\QAlist.txt", tagger);
var sentence = ToArray(tagger.ParseToNode(words));
string answer = db.NearestAnswer(sentence);
Console.WriteLine(answer);
}
これがRecogの中身です。
QADatabaseの中身の@以下は質問文と解答分のデータをtxtファイルにしたものの場所を指定してください。
QADatabaseも後で説明します。
sentenceのところでは、入力した文字列をToArrayメソッドで要素ごとにぶった切っています。
answerではそのsentenceをNearestAnswerで読み込むことで、一番似ているデータベースの回答を返します。
public static string[] ToArray(MeCabNode node)
{
var words = new List<string>();
while (node != null)
{
if (node.Stat != MeCabNodeStat.Bos && node.Stat != MeCabNodeStat.Eos)
{
words.Add(node.Surface);
}
node = node.Next;
}
return words.ToArray();
}
ここがMeCabのややこしいところです。
文章を形態素で分けたnodeのまま比べればいいじゃないか、と。
僕もそう思ってましたよ!
でもMeCabの形態素解析は配列とかリストで出力されないんですよねー。
ちゃんと説明すると、MeCabのnodeは鎖みたいなイメージです。nodeに次のnodeは何かという情報が含まれているんですねー。
なので、文字列が終了するまでnodeの名前をリストに入れて、node.Nextで次のnodeに移って、を無限ループで繰り返しているわけです。
ちなみに、ifの中のBosとEosは文字列の最初と最後につけられているラベルみたいなものです。これに到達したらループから抜けます。
返す時は配列にして返します。words.ToArray()はこのToArrayメソッドとは関係ないです!
public class QADatabase
{
List<string[]> question;
List<string> answer;
public QADatabase(string filename, MeCabTagger tagger)
{
question = new List<string[]>();
answer = new List<string>();
using (var infile = new StreamReader(filename, System.Text.Encoding.GetEncoding("shift_jis")))
{
while (infile.Peek() != -1)
{
var x = infile.ReadLine().Split(':');
question.Add(ToArray(tagger.ParseToNode(x[0])));
answer.Add(x[1]);
}
infile.Close();
}
}
static double similarity(string[] x, string[] y)
{
var words = new HashSet<string>();
foreach (string s in x)
{
words.Add(s);
}
int count = 0;
foreach (string s in y)
{
if (words.Contains(s)) { count++; }
}
return (double)count / (Math.Sqrt((double)x.Length * y.Length));
}
public string NearestAnswer(string[] q)
{
double maxsim = -1;
int maxind = -1;
for (int i = 0; i < question.Count; i++)
{
double sim = similarity(question[i], q);
if (sim > maxsim)
{
maxsim = sim;
maxind = i;
}
}
return answer[maxind];
}
}
はい、QADatabaseメソッドです。長いね、ごめんね。
最初で、txtファイルを読み込んで質問文と回答文に分けます。
質問文は例によって形態素に分けておきます。入力文と比べるためだよ!
でSimilarityで入力文と出力分を比べます。
まあつまり、文字列のnode数に対して、重複しているnodeがどれだけあるかで判定してます。
その類似度が一番大きいやつの回答をNearestAnswerで返します。
データベースの作り方
このデータベースですべてが決まると言っても過言ではありません。
データが多い方が回答の精度は上がります。
データベースの作り方は、適当なtxtファイルに1行ずつ
[質問]:[回答]
と入力していきます。
このデータベースの回答をアニメキャラのセリフにすれば、アニメキャラと会話しているかのような気分を味わえます。
僕の場合は、ヴァイオレット・エヴァーガーデンの回答を入れまくりました。
まあ、公開したい気持ちはあるんですが、著作権的にまずいのでね。
あなたの好きなキャラを召喚してください。
データ集めは手作業なのでめっちゃ大変です。
まとめ
こんな感じでプログラミングは完成です。
打ち込みじゃなくて、音声入力で音声で返すこともクラウドを使えばできるんですが、色々と面倒なのでまた別の機会に。