サイト概要

暇だったのでパワハラ判定機を作った。
機能はシンプルで、文章をぶちこんだらそれがパワハラなのかそうでないのか分類してくれる。
あとSNSでシェアできる。

出来上がったものはこちら

教師データの準備

パワハラ教師データ調達

身の回りのやばいおじさんを適当に突っ込んだ。
時代の流れもあってか、あからさまなデータを探すのが大変だった。
今の職場環境は素晴らしく、やばいおじさんは絶滅寸前だった。
パワハラは1としてラベリングしていく。

パワハラ以外の教師データ調達

パワハラを判定するには、パワハラではない文章のデータを学習させる必要がある。
身の回りの素敵なおじさんの文章を適当にブレンドし、0としてラベリング。
素敵なおじさんばかりなのでデータはすぐに充実した。

学習

Tensorflow機械学習クックブック(サンプルコード)

ちょうど手元の書籍に似たような事例があったため参考にしながら実装した。
書籍ではRNNを利用したスパムの判別を行なっている。
書籍のコードをベースに、学習済みモデルをlambdaに乗っけて動かせるように改修した。
また、自分のmacでトレーニングを行うため重すぎて死なないようにepoch数を減らすなど、ハイパーパラメータを調整した。
サービスをとりあえず公開したいので精度は後回しにする。

評価

$ python lambda_function.py "ぶっ●すぞ"
result: 1

明らかなる暴言

$ python lambda_function.py "ありがとう"
result: 0

機械学習パートは終わり

API開発

以下2つのAPIを、API gateway + lambda + dynamoDBで実装した。

  • 評価&保存API

文章を投げたら学習済みモデルで評価する。

評価結果をDynamoDBに保存し、レコードのIDを返す

  • 結果取得API

IDを投げたらDynamoDBから評価結果をとってきて返す。

一度評価したことのある文章が来たら、DBから結果をとってきて返すようにしようかとも考えたが、精度は日々改良するつもりなので都度評価することに。

DB設計

DynamoDBで、評価結果を格納するEvalResultsテーブルと、IDをインクリメントするためのSequencesテーブルを作成する。

  • EvalResults
    • id: ユニークなID
    • result: 評価結果
    • message: 評価された文章
  • Sequences
    • name: テーブル名
    • current_number: テーブルのレコード数

評価結果を登録するとき、DynamoDBのアトミックカウンターを利用してSequencesのEvalResultsレコードのcurrent_numberをインクリメントしつつ現在の値を取得する。

取得した値をidにしてEvalResultsに登録すれば、DynamoDBでユニークなIDを使い続けることができる。

フロント開発

Nuxt.jsのSPAモードをNetlifyでホストすることにした。
デザインはVuetifyを使用。
3ページしかないが画面は以下

  • 判定したい文章を入力する画面
  • 判定結果を表示する画面
  • 利用規約(一応)

APIを叩く共通部分

const evaluate = async (message) => {
  const res = await axios.get(endpointEval + encodeURIComponent(message))
  if (res.status !== 200) {
    throw res
  }
  return JSON.parse(res.data.body).id
}

const result = async (id) => {
  const res = await axios.get(endpointGetResult + id)
  if (res.status !== 200) {
    throw res
  }
  return JSON.parse(res.data.body)
}

export default {
  evaluate,
  result
}

判定したい文章を入力する部分

export default {
  components: {
    Loading,
    TwitterButton,
    FacebookButton,
    LineButton
  },
  data () {
    return {
      message: '',
      loadingDialog: false,
    }
  },
  methods: {
    async evaluate () {
      const id = await api.evaluate(this.message)
      this.loadingDialog = true
      this.$router.push(`/result/${id}`)
    }
  }
}

評価結果を取得する部分

export default {
  components: {
    TwitterButton,
    FacebookButton,
    LineButton
  },
  async asyncData ({ env, params }) {
    const data = await api.result(params.id)
    return {
      result: data.result,
      analyzeData: data.data,
      message: data.message,
      id: params.id
    }
  }
}

デプロイ

Netlifyとgithubを連携させることで、masterが更新されたら勝手にデプロイしてくれるようになる。
他にもプルリクを作成したらNetlifyがあらかじめビルドを走らせて、デプロイして問題ないか検証してくれたりする。

完成

できたサイト

何より素晴らしいのがここまでやってインフラコストが無料ということ。
ジュース代ぐらいになればいいなと思いつつAdsenseを貼って見守っていきたいと思います。
次はもっとくだらないものを作る予定です。