Electronで言語判定をしたい
趣味で開発しているElectronアプリで、入力された文字列が英語か日本語かはたまたそれ以外の言語かを判別して処理を切り替える機能を設けることにしました。
少し調べると、2010年ごろにサイボウズの方が作られた language-detection というライブラリがあることがわかりました。
しかし、これはJavaで作られており、Electronで使うことは難しそうです。
そこで、さらに色々と調べたところ、Chromeで動くGoogle謹製のツールがオープンソースで公開されていることがわかりました。
その名をCompact Language Detector v3と言います。
Chromeで動くならElectronでも、それ以外でも非常に幅広く使えますね。
そんな便利なライブラリですが、どうも日本語での情報は皆無のようです。
そこで、本記事ではこの概要と利用方法を説明します。
Compact Language Detector v3(CLD3)とは
Compact Language Detector v3は、Google製の言語判定ライブラリで、ニューラルネットワークを利用して入力された文字列が何語かを推測します。
107か国語という膨大な数の言語に対応しています。
以下のリポジトリに技術的な説明や詳しい対応言語が載っています。
このツールで「これは言語判定のテストです。」を判定させると、以下のような結果が得られます。
language: "ja"
probability: 1
is_reliable: true
proportion: 1
probability
は信頼度で、0~1の範囲を取ります。ちゃんと日本語だと判定されています。
こんどは、英語と中国語を混ぜて「Hello, World! 你好世界」を判定させてみます。
language: "zh"
probability: 0.4412570893764496
is_reliable: false
proportion: 1
中国語と判定されましたが、信頼度が0.5以下に下がり、is_reliable
がfalse
になっています。
CLD3
には、多言語が混ざっている文章について、どれくらいの割合でどの言語が含まれているかを判別することもできます。「This is a pen. これはペンです。C'est un livre.」という文章で試してみます。
0:
language: "ja"
probability: 1
is_reliable: true
proportion: 0.42592594027519226
1:
language: "fr"
probability: 0.9999618530273438
is_reliable: true
proportion: 0.29629629850387573
2:
language: "en"
probability: 0.9999408721923828
is_reliable: true
proportion: 0.2777777910232544
このように、日本語、英語、フランス語と判定されたうえで、proportion
の値でそれぞれの割合が示されています。
以上でこのライブラリの機能がお分かりいただけたと思います。
利用方法
利用方法は二つあります。簡単な方法と、正攻法です。
簡単な方法ではライブラリをラップしてくれるモジュールを利用します。正攻法は、ライブラリ本体をビルドします。
簡単な方法
Googleとは別の方が開発したcld3-asmというモジュールを使います。
まずnpm installします。
npm install cld3-asm
そのうえでモジュールを読み込みます。
import { loadModule } from 'cld3-asm'
const cldFactory = await loadModule();
const langIdentifier = cldFactory.create()
const result = langIdentifier.findLanguage("判定させたい文字列")
const num = 3 //複数の候補を出させる場合の数
const result2 = langIdentifier.findMostFrequentLanguages("判定させたい文字列", num)
console.log(result, result2)
create()
はcreate(minBytes, maxBytes)
と二つ引数を取れます。これで判定に使う文字列の長さを指定できます。短文を判定させたいときはminBytes
に小さな数字を指定してください。
たったこれだけで、上で挙げたような結果が得られます!
正攻法
このライブラリはChromiumベースで作られています。なので、ビルドするにはまずChromiumの開発環境を用意する必要があります。
注意点
先に断っておきますが、私自身この方法を試し、起動できる実行ファイルの作成には成功したものの、まともに動かせていません。
「私はここまでできた」という報告として紹介します。
なお、Windows 10での環境を想定しています。
Chromiumの用意
Chromiumの用意方法は以下のページに記載されています(英語)
このページではChromium本体をビルドする手順まで説明されています(めちゃくちゃ時間かかるらしい)。ですが、CLDを使うだけならそこまで必要はありません。
私は"Get the code"のセクションまでやりました。
かなり複雑で環境変数を特定の仕方でいじるような手順を要求されますが、CLDをビルドするためにどれが必要でどれは必要でないのか判断がつかないので、ここでの説明は控えます。やりたい方はご自分で解読してください。
ともかく、無事Chromiumのリポジトリのフェッチに成功したら、cd src
として//リポジトリのディレクトリ/src/
に移動します。
CLD3のビルド
CLD3のgithubページの説明には、コードを//third_party/cld_3/
にコピーしろとありますが、フェッチしてきたChromiumの中に最初から入っているので必要ありません。
//third_party/cld_3/src/src/BUILD.gn
を開き、executable("language_identifier_main")
の部分のコメントを解除します。
そして、コマンドプロンプトで以下を実行します。
gn gen out/Default
ninja -C out/Default third_party/cld_3/src/src:language_identifier_main
そうすると、//out/
ディレクトリに実行ファイルが生成されます。
これを実行すると、以下のようなデモが表示されます!
(文字化けする方はchcp 65001
として文字コードをUTF-8に変えてください)
text: This text is written in English.
language: en
probability: 0.999636
reliable: 1
proportion: 1
text: Text in deutscher Sprache verfasst.
language: de
probability: 0.999535
reliable: 1
proportion: 1
text: This piece of text is in English. Този текст е на Български.
language: bg
probability: 0.917389
reliable: 1
proportion: 0.585366
language: en
probability: 0.999979
reliable: 1
proportion: 0.414634
language: und
probability: 0
reliable: 0
proportion: 0
同じフォルダの中にあるlibc++.dll
とprotobuf_lite.dll
と一緒にコピーすれば他の場所でも動きます。
しかし・・・
これはあくまでデモで、この実行ファイルは標準入力からの入力を受け付けてくれません!
それそそのはず、ソースを見ると以下のようになっています。
int main(int argc, char **argv) {
NNetLanguageIdentifier lang_id(/*min_num_bytes=*/0,
/*max_num_bytes=*/1000);
const std::vector<std::string> texts{"This text is written in English.",
"Text in deutscher Sprache verfasst."};
for (const std::string &text : texts) {
const NNetLanguageIdentifier::Result result = lang_id.FindLanguage(text);
std::cout << "text: " << text << std::endl
<< " language: " << result.language << std::endl
<< " probability: " << result.probability << std::endl
<< " reliable: " << result.is_reliable << std::endl
<< " proportion: " << result.proportion << std::endl
<< std::endl;
}
const std::string &text =
"This piece of text is in English. Този текст е на Български.";
std::cout << "text: " << text << std::endl;
const std::vector<NNetLanguageIdentifier::Result> results =
lang_id.FindTopNMostFreqLangs(text, /*num_langs*/ 3);
for (const NNetLanguageIdentifier::Result &result : results) {
std::cout << " language: " << result.language << std::endl
<< " probability: " << result.probability << std::endl
<< " reliable: " << result.is_reliable << std::endl
<< " proportion: " << result.proportion << std::endl
<< std::endl;
}
return 0;
}
なぜか、入力文字列がハードコーディングされています・・・
私はこのコードを書き換えて標準入力から受け付けるように改造しようとしましたが、C++素人の自分では無理でした。
それが、「まともに動かせていない」と書いた理由です。
ここまで読ませておいてそれかよ!と思った方、申し訳ありません。
C++やChromiumに詳しい方がこの記事を見ていたらどうやったら使えるようになるのか教えていただけると嬉しいです。
まとめ
Google謹製のCompact Language Detector v3を使えばChromeでニューラルネットワークによる言語判定ができる。
cld3-asm
モジュールを使えば簡単に利用できる。
本格的にビルドして使う方法もあるけどまだできていない。