2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

表情筋を鍛えるアプリをリリースした【Next.jsでの多言語対応+動的OGP+face-api.jsで表情認識】

Last updated at Posted at 2021-09-15

先週表情を鍛えることができるアプリを作ったという記事を書きましたが、今週はそのときのアプリを大幅に改善してリリースしたのでその紹介をします。

アップデート内容は主に以下です。

  • 多言語化対応
  • 難しさを選択できるように
  • 動的OGP対応
  • 成功したら次に進めるように
  • 全体的なデザインのアップデート

全体のコードは以下にあるので興味のある方は見てください。
https://github.com/yuikoito/face-expression-challenge

アプリのURL→https://face-expression-challenge.vercel.app/

難しさを選択できるようにした

毎回同じ難しさだと好ましくないなと思ったので、難しさを選べるようにしました。
簡単、普通、難しい、鬼で選べます。
それぞれで時間を変えた他、スレッショルドの値も変更して、判定自体厳しくしています。

表情を取得してる部分で以下のようにスレッショルドを利用。(今回からdetectSingleFaceにしました)

      const detectionsWithExpression = await faceapi
        .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())
        .withFaceExpressions();
      if (detectionsWithExpression) {
        const Array = Object.entries(detectionsWithExpression.expressions);
        const scoresArray = Array.map((i) => i[1]);
        const expressionsArray = Array.map((i) => i[0]);
        const max = Math.max.apply(null, scoresArray);
        const index = scoresArray.findIndex((score) => score === max);
        const expression = expressionsArray[index];
        if (
          expression === subject &&
          // ここで指定のスレッショルド以上でないと判定しないようにしてる
          Array[index][1] >= levelConfig[level].threshold
        ) {
          clearInterval(intervalHandler);
          setIsMatch(true);
          setStage("result");
        }
      }

成功したら次にすすめるようにした

もともと、1.5秒間お題をだして、その後1.5秒後に判定としてましたが、寿司打を見習って、全体で決められた秒数の中でどれだけすすめるかをテーマにすることにしました。
そこで、1.5秒間お題を出したあとは3秒間の制限時間を加えて、その中でうまく表情が一致した場合は次のお題にどんどんすすめる感じです。

stageという単位で状態管理してるので、上記コードでsetStage("result")を指定することで、結果を出して次に進めるようにしています。

また、一致しなかった場合でも3秒以内に一致させることができなければ次に進むようにしています。

動的OGP対応

そして結果に関しては動的OGP化したので、シェアされた場合にわかりやすくなりました。
背景画像に文字を載せただけの簡単構成です。
背景画像の表示のためにcanvasの中からloadImageをインポートして使っています。

  const backgroundImage = await loadImage(
    path.resolve("./images/background.jpg")
  );
  ctx.drawImage(backgroundImage, 0, 0, WIDTH, HEIGHT);

多言語化対応

また、これはだいたい毎回やってるのですが多言語化しました。
Next.jsではv10からi18nが組み込まれたので何もインポートすることなく多言語化できます。

辞書ファイルはtsファイルで用意して、useTranslate.tsというファイルを作ってその中で言語によってどちらを読み込むかを判定しています。

import { useRouter } from "next/router";
import { JaTexts } from "../locales/ja";
import { EnTexts } from "../locales/en";

const useTranlate = () => {
  const { locale } = useRouter();
  return locale === "ja" ? JaTexts : EnTexts;
};

export default useTranlate;

next.config.js内で認識する言語とデフォルト言語の設定もします。

  i18n: {
    locales: ["en", "ja"],
    defaultLocale: "en",
  },

今回初めて気がついたのですが自動でその言語のファイルにロールバックされるのはトップページのみなんですね..
シェアURLから英語か日本語かによってOGP部分も多言語化したかったので、シェアする場合にロケールの文字を残した状態でシェアURLに飛ばすようにしました。(日本語ならシェアURLが/ja/share...になる)

あとは全体的にデザインを整えてリリースしました。

あとがき

これで17週目の週イチ発信となりました。
もはや2週に一個のアプリを作るになってますが、楽しいので良しとしておきます。

良ければこれまでの週イチ発信も見て下さい!
ではでは〜。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?