flaskでチャットボットのサンプルアプリ作ってみた【管理画面編】

先日、「flaskでチャットボットのサンプルアプリ作ってみた【概要編】」という記事を書いたのですが、今回は管理画面の実装について触れてみたいと思います。

リポジトリ

ディレクトリ構成

chatbot
├── admin                        管理画面側アプリケーション
│   ├── controllers             コントローラー(flask的にはview function)
│   ├── domain                  ドメイン層
│   │   ├── repositories       リポジトリ(インフラ層のインターフェース)
│   │   ├── services           サービス層(ドメインロジック)
│   │   └── tasks              非同期処理(ボットの学習)
│   ├── helpers                 コントローラーで使用するヘルパー
│   │   └── forms              formヘルパー(バリデーションの実装)
│   └── infrastructure          インフラ層(リポジトリの実装)
├── api                          API側アプリケーション
│   ├── controllers
│   ├── domain
│   │   ├── repositories
│   │   └── services
│   ├── exceptions             独自例外の定義
│   ├── helpers
│   │   ├── forms
│   │   └── responses         レスポンス用ヘルパー
│   └── infrastructure
├── common                      共通利用するモジュール(機械学習など)
├── front                       フロント⇔バックのインターフェース(メモとして使用)
├── ml_vars                    機械学習で使用する変数の保存先
├── models                     モデル定義(sqlalchemyのmodel継承)
├── scss                       フロント画面用SCSS
├── static                     静的ファイル置き場
│   └── admin                 管理画面用
│       ├── bower_components  AdminLTE用ファイル置き場
│       ├── dist              同上
│       └── plugins           同上
├── templates                  HTMLファイル置き場
│   ├── admin                 管理画面用
│   │   ├── bot
│   │   ├── faq
│   │   ├── faq_list
│   │   ├── site
│   │   └── site_url_setting
│   └── front                フロント用
└── upload                    アップロードファイル置き場(FAQリスト)

DBへの接続

DBにはmsqlを使用しているのですが、DB操作のライブラリとしてflask公式サイトに記載があったので、SQLAlchemy を利用することにしました。
[参考] https://a2c.bitbucket.io/flask/patterns/sqlalchemy.html

ORMとして使っており、その定義を models 配下の各クラスに記述しています。定義はSQLAlchemyが提供するAPIを使っているので、今回は自分でSQLを記述するということはありませんでした。

リレーションの記述が直感と違っていたので期待するデータが取得できるようになるまで時間がかかってしまいましたが、1対多、多対1、多対多のリレーションが実現できたので、とりあえず良しとしています。

リレーションの実装箇所

  • 1対多
    • ボット 対 FAQリスト
      • BotModel.faq_lists に ボットに含まれるFAQリスト一覧を保持
    • FAQリスト 対 FAQ
      • FaqListModel.faqs にリストに含まれるFAQ一覧を保持
  • 多対1
    • FAQリスト 対 ボット
      • FaqListModel.bot に自身を保持しているボットデータを保持
    • FAQ 対 FAQリスト
      • FaqModel.faq_list に自身を保持しているFAQリストデータを保持
  • 多対多
    • FAQ 対 関連FAQ
      • FaqModel.related_faqs に自身と関連しているFAQ一覧を保持
      • 中間テーブルとして faqs_faqs テーブルを定義

ボット、FAQ、サイトといったデータのCRUD

SQLAlchemyを使ってデータの取得、追加、更新を行っているだけなので、詳細は割愛します。
バリデーションは、こちらも公式サイトで紹介されていたwfformsを使用しています。
[参考] https://a2c.bitbucket.io/flask/patterns/wtforms.html

ボットの学習について

FAQには質問と回答があるので、エンドユーザーから入力されたテキストが質問文に近ければその回答を返すというものにしています。

機械学習の手法なのですが tensorflow を使ってみたいこともありDeepLearningによる学習を行っています。また、テキストの形態素解析にはMeCabを使用しました。

学習時に気をつけたこと

学習時の入力データとしてFAQの質問を形態素解析し、そのまま特徴量として利用するだけだと柔軟性がなかったので、下記3つの学習データを作成し回答(ラベル)と紐づけました。

学習データ3パターン

  1. 質問を形態素解析した結果のうち、以下のものを抽出し学習データにする
    • 名詞
    • 動詞、形容詞の原形
      • 映ら → 映る
      • 新しく → 新しい
    • 助動詞で2文字以上の原形
      • 映らないの「ない」
  2. 1の単語リストをすべてひらがなに変換した単語を学習データにする
  3. 2のひらがな化した単語を改めて形態素解析し、2文字以上の単語を学習データにする

3パターンの目的

  1. 名詞以外は原形を利用する事で活用による表記ゆれを吸収
  2. ひらがな入力対応
  3. 同上

学習データを水増しすることで、より柔軟な入力に対応できるようになりました。

DeepLearningのレイヤーについて

レイヤーや次元を変えて何パターンか試してみたのですが、目に見えた改善がみられなかったので、中間レイヤー1つで次元数は入力次元の20%にしています。
学習データを増やしたり、良い検証方法の準備ができれば良かったかと思うのですが、現状の知識ではモデルの改善は十分にはできませんでした。

フロントからのAPI呼び出しで学習した内容を使うために

学習後のモデルや入力として想定している単語リストなどをAPIで使用可能にするため、以下のファイルを ml_vars/[bot_id] ディレクトリに保存しています。

  • 学習したモデル
  • 単語リスト
    • id_to_word
      • キーが単語ID、値が単語となってる辞書
    • word_to_id
      • キーが単語、値が単語IDとなっている辞書
  • FAQリスト
    • 予測結果からFAQデータを導くためのリスト

これらのデータをAPIでどのように使っているかは別の記事で説明する予定です。

以上、flaskでチャットボットのサンプルアプリ作ってみた【管理画面編】でした。