flaskでチャットボットのサンプルアプリ作ってみた【応答API編】

前回の記事では管理画面の説明を行いました。
今回は管理画面で設定・学習した内容を使って応答するAPIの実装について振り返ってみたいと思います。

リポジトリ

リクエスト種別

APIが受け取るリクエストには下記3種別があり、種別に応じた処理を行い応答しています。

  • フリーテキスト
    • ユーザーが入力した内容をもとにFAQを検索します。
  • FAQ_ID指定
    • FAQ_IDをもとにFAQを取得します。
  • 固定回答
    • 以下の場合に設定されたFAQを取得します。
      • 会話開始時のAPI呼び出し
      • FAQが見つからなかった場合

FAQ_ID指定、固定回答についてはFAQを取得しているだけです。
特別な処理をしているわけではないのでここでは割愛し、フリーテキスト時の応答について少し書いておこうと思います。

フリーテキスト時の処理

1. テキストをパース

パースとは形態素解析+ふさわしい単語のみにする処理の事をそう呼んでいます。

学習時はFAQの質問に対して、同じ処理を施しています。

2. 学習済みモデルに入力するデータに変換

パース後の単語と学習時に作成した変数 word_to_idを使って入力データを作成しています。

パース同様、学習時と同じ処理を使っています。

3. モデルにデータを投入し予測結果を取得

モデル(ニューラルネットワーク)の出力層にはソフトマックス関数を使っており、予測結果を確率として扱っています。
なお、予測結果は 0 〜 1.0 の小数が並んだ配列となっており、その要素数=学習対象のFAQ数となっています。

イメージ:予測結果[i] = 入力に対してi番目の回答がふさわしい確率

4. 予測結果をスコア順に並べ変える

予測結果のうちスコア(確率)が高いものを利用したいので、並び替える必要があります。

ここでは予測結果の配列そのものを並び替えることはせず、配列のインデックスがスコア順になっている別の配列を用意しています。

 rank = np.argsort(-result)  // 引数を -result にする事で高いスコア順に並び替えます

# 例
result = [0.1, 0.5, 0.2, 0.25, 0.05] # type numpy.ndarray
rank = [1, 3, 2, 0, 4]               # type numpy.ndarray

5. 上位5位までのFAQデータを作成

予測結果の配列のインデックスは 0 〜 FAQリストの質問数-1 となっています。
FAQデータを取得するのにインデックスはそのまま使えないので、学習時に使用したFAQリストを使ってFAQデータを作成しています。

対象のFAQデータ = 学習時のFAQリスト[予測結果インデックス]

6. 1位のスコアとしきい値を比べ応答内容を確定する

1位のスコアがしきい値より高い場合、そのFAQが最適と判断し回答しています。

予測結果が1位だとしてもスコアが低い場合、ボットは自信を持って回答できない状況となります。その場合は最適なFAQが見つからなかったと判断し、上位5位までのFAQデータをユーザーに提示し、選択してもらうようにしています。

レスポンス形式

諸々の処理が終わって応答するレスポンスは下記形式のJSON文字列となります。

{
  "answer": {                   ユーザー入力に対する回答(必須)
    "answer": "回答文", 
    "faq_id": 1, 
    "question": "質問1"
  }, 
  "questionList": [             ユーザーに提示したいFAQリスト(任意)
    {
      "faq_id": 2, 
      "question": "質問2"
    }, 
    {
      "faq_id": 3, 
      "question": "質問3"
    }, 
    {
      "faq_id": 4, 
      "question": "質問4"
    }
  ]
}

answerについて

ユーザー入力に対する回答内容が返します。
会話開始場合、FAQが見当たらない場合は管理画面で設定されたFAQを返します。

questionListについて

FAQに関連するFAQが設定されている場合はその一覧を返します。
FAQが見当たらなければ

ざっくりとしている部分もありますが、以上がflaskでチャットボットのサンプルアプリ作ってみた【応答API編】でした。