🗾

不適切な言葉をシステムに登録させないように頑張ってみた話

2022/06/10に公開約4,100字

こんにちは、地図パズル製作所の都島です。地図パズル製作所では、現在ログイン機能を絶賛開発中です。その中でシステムへの印象を悪くしないようにするためにも、ユーザから不適切な言葉を登録させないようにすることになりました。ということで、今日はユーザから不適切な言葉を登録させないようにするようにする仕組みを作ってみた話をしたいと思います。まだできあがってはいないので、これまでの進捗のお話です。

とその前に地図パズル製作所の宣伝をさせていただきます。地図パズル製作所では大人も子供も楽しめる地図パズルを作っています。都道府県の地図パズルはすべて制覇しています。きっと、お住いの都道府県であれば、簡単にできてしまうはず??ということで、挑戦してみてください。

https://chizu-puzzle.com
  • 東京都の地図パズル(地理院地図を加工して利用しています)
    東京都の地図パズル

  • 神奈川県の地図パズル(地理院地図を加工して利用しています)
    神奈川県の地図パズル

  • 大阪府の地図パズル(地理院地図を加工して利用しています)
    大阪府の地図パズル

他にも観光地の地図パズルなど、たくさん地図パズルがありますので、ぜひ一度見てみてください。

では、本題に入りましょう!

不適切な言葉を登録させないようにするには?

不適切な言葉を登録させないようにするには、Azure の Content Moderator を使ってみました。Content Moderator はテキスト以外にも、不適切な画像を認識したり、いろいろなことができます。十分な無料枠もあります。でも、残念ながらこの Content Moderator、あまりインターネット上に情報がありません。ということで、私が頑張って調べて、できあがったソースコードを載せていきたいと思います!!

Firesotre 登録時に Cloud Functions を動かして、OK か NG かチェックするようにしています。キー "COGNITIVE_SERVICES_KEY" は Firebase のシークレットに登録してあります。

import { ContentModeratorClient } from "@azure/cognitiveservices-contentmoderator";
import { CognitiveServicesCredentials } from "@azure/ms-rest-azure-js";
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";

admin.initializeApp();

const db = admin.firestore();

export const onCreateUserProfile = functions
  .region("asia-northeast1")
  .runWith({ secrets: ["COGNITIVE_SERVICES_KEY"] })
  .firestore.document("userProfiles/{userId}")
  .onCreate(async (snap) => {
    if (
      process.env.COGNITIVE_SERVICES_KEY == null
    ) {
      return;
    }

    const credentials = new CognitiveServicesCredentials(
      process.env.COGNITIVE_SERVICES_KEY
    );
    const client = new ContentModeratorClient(
      credentials,
      "https://endpoint.com"
    );
    const data = snap.data();
    if (data.tmpHandle == null) {
      return;
    }
    const response = await client.textModeration.screenText(
      "text/plain",
      data.tmpHandle,
      {
        classify: true
      }
    );

    functions.logger.debug(response);

    let ok = false;
    if (response.classification != null) {
      ok=true;
      if (
        response.classification.category1 != null &&
        response.classification.category1.score != null &&
        response.classification.category1.score >= 0.3
      ) {
        ok = false;
      }
      if (
        response.classification.category2 != null &&
        response.classification.category2.score != null &&
        response.classification.category2.score >= 0.3
      ) {
        ok = false;
      }
      if (
        response.classification.category3 != null &&
        response.classification.category3.score != null &&
        response.classification.category3.score >= 0.3
      ) {
        ok = false;
      }
    }
    if (ok) {
      await db
        .collection("userProfiles")
        .doc(snap.id)
        .update({ status: "Success", handle: data.tmpHandle });
    } else {
      await db
        .collection("userProfiles")
        .doc(snap.id)
        .update({ status: "Fail" });
    }
  });

一旦 tmpHandle にユーザが入力してきたハンドルネームを登録して、Content Moderator で問題ない言葉か調べて、問題なければ、handle に再登録するという仕組みです。

でも、ここまで作り上げて、大問題に気づきました。不適切な言葉が含まれていると、category1.score category2.score category3.score の値が増えていくわけですが、なんとこれは日本語には対応していないようなのでした。。日本語でできることは、NGワードを検出することぐらいなようです。

でも、英語が認識できるならここではハンドルネームだけなので、英語にすればいいか、と思ったわけですが、それも微妙なようです。例えば、日本語の NG ワードをローマ字で入れられてしまうと、それは検出できないようです。

ということで、何日もかかって作り上げたこの機能ですが、使うか使わないか、再検討中です。

終わりに

ということで、残念ながら Content Moderator は不採用となるかもしれません。でも、そのおかげで Zenn の記事が書けたと、前向きにとらえていきたいと思います!!(え、前の記事でも同じこと言ってたって??)さて、地図パズル製作所のログイン機能はいつできあがるのでしょうか。。

※2022/06/17 追記
onCreate 関数でチェックして、チェック結果を同じコレクションに格納していますが、onUpdate 関数で同じことをすると無限ループに陥る危険があります。気を付けましょう。

ツイッターもよろしくお願いします!

https://twitter.com/chizu_puzzle_as

アメブロもやってます!

https://ameblo.jp/chizu-puzzle

Discussion

ログインするとコメントできます