公開日:2021.12.21

チャットボットをC#で作る

テクログ

Windowsアプリでチャットボットつくる

WindowsのPCからいつでも起動できるアプリをVisualC#で作成しました。
C#自体初めて書いてみたのですがとても見やすい言語でした。
今回作ったチャットボットのソースコードは以下のリポジトリに置いているため、ぜひ参考にしてください。

https://github.com/jacoloves/GirlFriend

チャットボットとは

こちらのメッセージに対して何らかの応答を返すアプリケーションです。

画像のようにこちらが何か言葉を打ったら返答してくれます。

実装の方針

  • VisualC#でフォームの外見を作成します。
    始めにボタンやテキストエリアやピクチャーボックスなどを配置していきます。
  • ランダム辞書とパターン辞書を作成します。
    返信用の辞書を2つ用意します。ランダムな返答が書いてある辞書と単語のパターンで特定の返答をしてくれる辞書を作成します。
  • 動作に必要なクラスを作成します。
    二つの辞書を読み込むクラス、チャットボットの機嫌を更新するクラス、返信用のクラス、フォームの動作を操作するクラスの5つのクラスを作成します。

実装について

辞書について

ランダムな返答の辞書は下記のような記載の辞書にします。

いい天気だね
今日は暑いね
おなかすいた

挨拶や特定のワードに反応して正規表現でパターンマッチングさせる辞書は下記のします。

こん(ちは|にちは)$\tこんにちは|やほー|ハーイ|どうもー|まああなた?
おはよう|おはよー|オハヨウ\tおはよ!|まだ眠い…|さっき寝たばかりなんだー
こんばん(は|わ)\tこんばんわ|わんばんこ|今何時?

辞書を読み込む

ランダム辞書の場合は一行ずつListに加えていけばいいいですが、
パターン辞書を読み込む場合は1行読み込んだ後に\tが入ってるところで行を分割して「ユーザー側の発言」と「チャットボットの応答」に分けます。

foreach (string line in new_lines)
{
    // add code
    // line replace \\t -> \t
    string rep_line = line.Replace("\\t", "\t");
    string[] carveLine = rep_line.Split(new char[] { '\t' });
    _patternList.Add(
        new ParseItem(
            carveLine[0],
            carveLine[1])
        );
}

チャットボットの機嫌を更新する

パターン辞書に記載のある下記パターンの文字列があった場合、数値パターンを切り分けて 機嫌変動値 を更新します。
機嫌変動値が最大値と最小値を超えそうになったらその値を最大値か最小値のどちらか超えそうな方に設定します。

5##かわいい|かわいい|カワイイ|きれい|綺麗|キレイ\t%match%ってホント!?ホントに!?|わーい
private void Adjust_mood(int val)
{
    _mood += val;
    if (_mood > MOOD_MAX)
        _mood = MOOD_MAX;
    else if (_mood < MOOD_MIN)
        _mood = MOOD_MIN;
}

抽出したパターンから応答フレーズを返す

正規表現を使い応答フレーズのパターンを抽出します。
その過程で機嫌変動値が存在したら変数に代入します。
パターン抽出の際に応答フレーズに”|”が存在する場合、分割して応答フレーズのListに格納します。
ユーザ応答とパターン辞書がマッチした場合、Listからランダムに応答フレーズを返します。

public string Choice(int mood)
{ 
    List<String> choices = new();
    foreach (Dictionary<string, string> dic in _phrases)
    {
        if (Suitable(
            Convert.ToInt32(dic["need"]),
            mood
            ))
        {
            choices.Add(dic["phrase"]);
        }
    }
    if (choices.Count == 0)
        return null;
    else 
    {
        int seed = Environment.TickCount;
        Random rnd = new(seed);
        return choices[rnd.Next(0, choices.Count)];
    }
}

返信用の処理

ランダム辞書から返答を返す処理、パターン辞書から返答を返す処理、ユーザ発言をそのまま返答として返す処理の3つのバリエーションの返信用の処理を作成しました。
下記はパターン辞書から返答を返す処理のソースコードです。

foreach (ParseItem parseItem in Cdictionary.Pattern)
{
    string mtc = parseItem.Match(input);
    if (String.IsNullOrEmpty(mtc) == false)
    {
        string resp = parseItem.Choice(mood);
        if (resp != null)
            return resp.Replace("%match%", mtc);
    }
}

フォームの動作を操作する処理

ランダムで上述した返信用の処理を呼び出して、ダイアログに出力させています。

public string Dialogue(string input)
{
    _emotion.Update(input);
    Random rnd = new();
    int num = rnd.Next();
    if (num < 6)
        _responder = _res_pattern;
    else if(num < 9)
        _responder = _res_random;
    else
        _responder = _res_repeat;
    return _responder.Response(
        input,
        _emotion.Mood);
}

また、 機嫌変動値の数値によって保存してある写真を更新しています。

int em = _chan.Emotion.Mood;
if ((-5 <= em) && (em <= 5))
{
    this.pictureBox1.Image = Properties.Resources.normal;
}
else if (-10 <= em & em < -5)
{
    this.pictureBox1.Image = Properties.Resources.what;
}
else if (-15 <= em & em < -10)
{
    this.pictureBox1.Image = Properties.Resources.angry;
}
else if (5 <= em & em <= 15)
{
    this.pictureBox1.Image = Properties.Resources.smile;
}
label2.Text = Convert.ToString(_chan.Emotion.Mood);

今後の課題

ある程度の返答はできますがまだちょっとましな返答ができるチャットボットになっただけなので、今後は形態素解析を用いて曖昧なユーザの発言にも柔軟に対応できるようしていけたらなと思います。

・ 形態素解析による柔軟な応答
・ チャットボットからデスクトップマスコットへ変更
・ Grep機能などのその他機能の追加

まだまだ改修する箇所は多いので暇を見つけて作っていきたいです。

まとめ

C#で作るチャットボットはいかがでしたでしょうか?
VisualC#は最初はとっつきにくいですがオブジェクトに値を代入したり、変数にオブジェクトの値を代入する処理がわかれば意外と簡単にアプリを作ることができました。
皆さんもぜひVisualC#でアプリを作ってみてください!

この記事を書いた人

たなしょ

入社年2021年

出身地千葉県

業務内容webページのエンハンス

特技または趣味登山、ランニング、キャンプ、ベース

たなしょの記事一覧へ

テクログに関する記事一覧