GoogleのCloud Translation API v3を触ってみる

自然言語の翻訳APIに興味が出てきたのでちょっと触ってみることにします。ここではすでにテキスト情報になっており、日本語から英語など別の言語に自動的に変換してくれる物を想定しています。

Google Cloud Translate
Google Cloud Translateサイトより

すでに様々なサービスが世に出ていますが、今回はGoogleの翻訳APIを試してみます。新しいバージョン3(以降v3)ではJava、Python、Node.jsから利用できますが、今回はNode.jsで利用します。

主要な開発者向け翻訳サービス

現在API形式で提供されており、個人でも触れる物は以下でしょうか。

  1. Google Cloud Translation API
  2. AWS Amazon Translate
  3. Microsoft Azure Translator Text
  4. IBM Watson Language Translator
  5. Yondex Translate API ※ロシアの検索ポータル

法人利用であれば次のような物もあります。

  1. みらい翻訳 Mirai Translator ※NTT系列が主要株主

Google Cloud Translation API概要

料金

詳しくは料金ページに記載してありますが、ざっくり言うとv2はすべて有料、無料枠を使いたいならβ版のv3を利用する必要があります。つまり人柱になれば無料ですw!←

バージョン 機能 料金
v2 翻訳 $20/100万文字
v3β 翻訳 50万文字まで無料、以降は$20/100 万文字

いずれも1ヶ月間の料金です。 100万文字に達しない場合、例えば10万文字使った場合は$2が請求されます。無料にはなりませんのでご注意を。つまり1文字あたりの単価は0.0022円(12月1日時点)となります。 注意点としてv3には翻訳モードがPBMT、NMT、AutoMLの3種類ありPBMTを利用する場合はv2と同様の課金がされます。

まぁ…v2とv3のどちらを使っても個人がお試しで使う分にはよほどヤンチャなことをしなければ無料の範囲内か、料金を支払う場合でもコーヒー1杯分にもならないでしょう。

v2とv3の違い

v3には様々な新機能が追加されているようです。

  1. 用語集」が追加。固有名詞などを予め登録しておくことが出来る。
  2. 一括リクエスト」が追加。大量の文章をバッチ処理で翻訳。
  3. AutoMLモデル」が追加。機械学習で独自に作成したモデルを利用可能に。
  4. 「API KEY」が廃止され「IAM役割」に変更

「IAM役割」はAWSでいうIAMとロールみたいな物ですね。呼び出し方が変わっていることを考えると、将来的に確実に移行する日がやってくるでしょうから、今回はv3で試してみたいと思います。下位互換してくれるなら良いのですがいずれかのタイミングで廃止でしょうかね。

Google Cloud Translation APIを試してみる

クイックスタートの内容に沿って実行してみます。

Googleアカウントを作成、GCPへの登録は事前に済ませています。今回はお試しですが、課金が行える状態にしておく必要があります。クレジットカード情報も事前に登録してあります。

またNode.jsを利用しますので、事前にインストールしておいてください。

プロジェクトの作成

GCPにお試し用のプロジェクトを作成します。 先ほどのクイックスタートのページにある「プロジェクトをセットアップする」ボタンをクリックします。(GCPのコンソールからでも行なえます)

プロジェクト選択画面になりますので、既存のプロジェクトを選択するか、新しいプロジェクト名を入力し「NEXT」ボタンをクリック。

課金の設定が必要だと言われました。文中のリンクをクリックすると新しいウィンドウが開き設定画面が表示されます。

されました。 今回はすでに設定済みだったので、ボタンを押すだけ。まだの方はこのタイミングで行ってください。完了したらウィンドウを閉じて先ほどの画面に戻ります。

先ほどのウィンドウです。「CONTINUE」ボタンをクリック。

このあと利用する「プライベートキー」が記載されたファイルをダウンロードするよう促されますので、ボタンをクリックして保存します。

環境変数の設定

GOOGLE_APPLICATION_CREDENTIALSという名前の環境変数を作成し、先ほどダウンロードしたファイルのパスを設定します。

今回は一時的に利用するだけなので、Terminalに直接コマンドを打ちました。今後も引き続き利用する場合には.bashrc.bash_profileなどに記載します。あ、ここでは横着しましたが基本的に絶対パスで書いてくださいね。

$ export GOOGLE_APPLICATION_CREDENTIALS=~/test-translate-katsube.json

printenvなどで念の為確認を。

$ printenv | grep GOOGLE
GOOGLE_APPLICATION_CREDENTIALS=/Users/katsube/test-translate-katsube.json

Node側を準備

まずはプロジェクトの準備をします。ひとまずnpm initの選択肢はすべてエンターでOKです。package.jsonが生成されたか確認をしておきます。

$ mkdir trans && cd trans
$ npm init
$ ls
package.json

では最後にCloud Translateのモジュールをインストールします。

$ npm install --save @google-cloud/translate

サンプルコードを試してみる…がエラーになる

掲載されていたサンプルほぼそのままです。これで日本語で入力された内容を英語で返してくれるハズ。

//-----------------------------------------------
// 設定
//-----------------------------------------------
const projectId = 'test-translate-k';
const location  = 'global'; // 現在は"global"か"us-central1"のみ
const text      = 'こんにちは!今日も良い天気ですね。';

// いじるのはここまで。以降はサンプルコードのままで動作します。

//-----------------------------------------------
// 実際の処理
//-----------------------------------------------
const {TranslationServiceClient} = require('@google-cloud/translate').v3beta1;

// Instantiates a client
const translationClient = new TranslationServiceClient();
async function translateText() {
  // Construct request
  const request = {
    parent: translationClient.locationPath(projectId, location),
    contents: [text],
    mimeType: 'text/plain', // mime types: text/plain, text/html
    sourceLanguageCode: 'ja-JP',
    targetLanguageCode: 'en-US',
  };

  // Run request
  const [response] = await translationClient.translateText(request);

  for (const translation of response.translations) {
    console.log(`Translation: ${translation.translatedText}`);
  }
}

translateText();

適当なファイルに保存して実行すると、見事にエラーになりました\(^o^)/

$ node index.js
(node:23271) UnhandledPromiseRejectionWarning: Error: 7 PERMISSION_DENIED: Cloud IAM permission 'cloudtranslate.generalModels.predict' denied.
    at Object.callErrorFromStatus (/Users/katsube/Desktop/trans/node_modules/@grpc/grpc-js/build/src/call.js:30:26)
    at Http2CallStream.<anonymous> (/Users/katsube/Desktop/trans/node_modules/@grpc/grpc-js/build/src/client.js:96:33)
    at Http2CallStream.emit (events.js:208:15)
    at /Users/katsube/Desktop/trans/node_modules/@grpc/grpc-js/build/src/call-stream.js:75:22
    at processTicksAndRejections (internal/process/task_queues.js:75:11)
(node:23271) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:23271) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

クイックスタートには掲載されてないのですが、エラー内容から鑑みるにIAMの設定が必要みたいですねw

サービスアカウントにIAM役割を付与する

プロジェクトを作成した際に「サービスアカウント」と呼ばれるプログラムをGCP上で動作させる専用のアカウントが自動的に作成されています。JSONファイルをダウンロードしたと思いますが、あの中身はこのサービスアカウントの認証情報というわけです。で、デフォルトだとこのサービスアカウントに権限が一切付与されていないため、先ほど実行したら弾かれてしまったということのようです。

はい、というわけでドキュメントの内容に従って、サービスアカウントさんに権限を付与していきます。今回はWebの管理画面(コンソール)からサクッといきます。

GCPのコンソールにログインし、プロジェクトを選択したら左側のメニューから「IAMと管理」→「アービスアカウント」とたどります。

サービスアカウントの一覧が表示されるので「メールアドレス」の部分をクリップボードへコピーします。このメールアドレスはGoogleが機械的に作成した物です。

左メニューの「IAM」をクリックし、ユーザー一覧を表示します。上部にある「追加」ボタンをクリック。

先ほどのサービスアカウントのメールアドレスをペーストし、権限(役割)を選択します。ここでは「CloudTranslationAPIユーザー」を選択。最後に「保存」ボタンをクリック。

先ほどのユーザー一覧にサービスアカウントが加わっていれば成功です。

再び実行する

・::・:┣¨キ(゚Д゚)┣¨キ:・::・

$ node index.js
Translation: Hello! It ’s good weather today.

キタ━(゚∀゚)━!

翻訳モデル

3つの翻訳モデル

v3では次の3つの翻訳モデルから1つを選び処理にかけることができます。

モデル名 概要 精度
ニューラル機械翻訳(NMT)モデル 機械学習を利用して作成された翻訳モデル 高い
フレーズベース機械翻訳(PBMT)モデル フレーズを翻訳し並べ替える旧来からの方式 ぼちぼち
AutoML Translation モデル 自分で機械学習のモデルを作成し翻訳を行う (状況によっては)高い

※詳しくは公式ドキュメントをご覧ください。

翻訳モデルが未指定の場合、デフォルトでNMTモデルが利用されます。単に機械的に翻訳にかけたいといった場合には何もする必要はありませんが、何らかの事情でPBMTを利用する場合は指定を行う必要があります。なおNMTは50万文字まで無料ですが、PBMTを利用するとすべて有料となります。

翻訳モデルを指定する

先ほどのコードを書き換えて実行します。冒頭の変数を定義してい箇所にmodelIdを追加、値がbaseであればPBMT、nmtならNMTになります。またlocationは現在はus-central1固定にする必要があるようです(globalにしていると怒られます)

const projectId = 'test-translate-k-1234567890';
const location  = 'us-central1';
const text      = 'こんにちは!今日も良い天気ですね。';
const modelId   = 'base';    //nmt:NMT, base:PBMT

連想配列requestmodelの項目を追加します。

  const request = {
    parent: translationClient.locationPath(projectId, location),
    contents: [text],
    mimeType: 'text/plain',
    sourceLanguageCode: 'ja-JP',
    targetLanguageCode: 'en-US',

    //↓追加
    model: `projects/${projectId}/locations/${location}/models/general/${modelId}`
  };

NMTとPBMTを比較する

ではこの2つの翻訳モデルにどの程度の差があるのか比較してみたいと思います。サンプルとして使うのは、ジョブスの伝説的なスタンフォード大学の卒業式のスピーチの一部分を英語から日本語に翻訳してみます。私、英語は堪能でないというかむしろ苦手なので、和英だと判断できないんですよねw


www.youtube.com

余談ですが、スタンフォード大学が公開しているこの動画、日本語訳がなぜか大阪弁なんですよねw 誰の仕業だw

閑話休題。さて今回は「connecting the dots」の箇所にしました。これに影響された人多いのでは。

Again, you can't connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something - your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.

※日本経済新聞「ハングリーであれ。愚か者であれ」ジョブズ氏スピーチ全訳」より

日経新聞での日本語訳は以下の通りです。

繰り返しですが、将来をあらかじめ見据えて、点と点をつなぎあわせることなどできません。できるのは、後からつなぎ合わせることだけです。だから、我々はいまやっていることがいずれ人生のどこかでつながって実を結ぶだろうと信じるしかない。運命、カルマ…、何にせよ我々は何かを信じないとやっていけないのです。私はこのやり方で後悔したことはありません。むしろ、今になって大きな差をもたらしてくれたと思います。

※日本経済新聞「ハングリーであれ。愚か者であれ」ジョブズ氏スピーチ全訳より

翻訳者の方の名前の記載がないのですが、おそらく生きた人間が訳されていると思われます。

PBMT

この感じ懐かしいなw 昔ながらの機械翻訳を感じますねw

ここでも、あなたは楽しみにしてドットを接続することはできません。あなただけ後方探してそれらを接続することができます。ドットは何とか自分の将来に接続することを信頼する必要がありますので。あなたの腸、運命、人生、カルマ、何でも - あなたは何かに信頼する必要があります。このアプローチは、私を失望させたことがない、それは私の生活の中ですべての違いをしました。

大雑把な意味は十分伝わってきますね。

NMT

PBMTと比較すれば圧倒的なクオリティ(゚д゚)! と言っても所々怪しいですがw

繰り返しになりますが、将来のドットを接続することはできません。後ろ向きにしか接続できません。そのため、将来的にドットが何らかの形でつながることを信頼する必要があります。あなたは何かに信頼しなければなりません-あなたの腸、運命、人生、カルマ、何でも。このアプローチは決して私を失望させたことがなく、私の人生に大きな違いをもたらしました。

原文のtypoだと思うのですが、PBMTもNMTも「your gut, destiny, life, karma, whateve.」を「あなたの腸、運命、人生、カルマ、何でも」と訳しているのですが、唐突に『』が出てくるの笑いましたw gutじゃなくてgetなのかな?

英語に詳しい方教えてくださいw

HTMLをまるっと翻訳する

長くなったので別の記事にしました。 blog.katsubemakito.net

ちょっと罠があるので注意が必要ですが、mimeTypeをtext/htmlにしてHTMLをそのまま渡すだけで非常にお手軽です。

Web上に掲載する場合はライセンス表示が必要

概要

訳した文章をWeb上に公開することもライセンス的に問題無いようですが、その場合にはライセンス表示が必要となるようです。詳細は公式ドキュメントを参照ください。

ざっくり言うと要件としては次の4つ。

  1. Google翻訳で作成された文章であることをユーザーに明示する
  2. 翻訳された文章の近くにロゴとリンクを設置
  3. 利用規約に指定の免責事項を追加
  4. 検索エンジンに登録されるページの場合は特定のタグを追加

ロゴとリンク

ロゴ画像は以下からダウンロードできます。
https://cloud.google.com/translate/images/google-translate-attribution.zip?hl=ja

このロゴ画像のリンク先は以下のURL固定だそうです。
http://translate.google.com/

免責事項

次の項目の掲載は必須のようです。

このサービスには、Google により提供される翻訳が含まれる場合があります。Google は、明示的か黙示的かを問わず、翻訳に関するすべての保証(精度、信頼性に関するあらゆる保証、および商品性、特定目的への適合性、第三者の権利の非侵害性に関するあらゆる黙示的保証を含みます)を放棄します。

また必要に応じて以下の追記も可能とのこと。こちらは法律家に相談し改変してもOKのようです。

<会社名>のウェブサイトは、便宜を図るために、Google 翻訳が提供する翻訳ソフトウェアを使用して翻訳されています。正確な翻訳を提供できるよう相応の努力を尽くしておりますが、機械翻訳は完璧ではなく、また機械翻訳は人間による翻訳の代わりになることを目的としたものではありません。翻訳は、<会社名>のウェブサイトのユーザーへのサービスとして提供されるものであり、「現状有姿で」提供されます。<原文の言語>から別の言語への翻訳の精度、信頼性または正確性に関して、明示的か黙示的かを問わず、いかなる種類の保証も行われません。翻訳ソフトウェアには限界があるため、一部のコンテンツ(例: 画像、動画、Flash)は正確に翻訳されない場合があります。 正式なテキストは、ウェブサイトの<原文の言語>バージョンです。翻訳に生じる矛盾または差異には、準拠または実施について拘束力はなく、いかなる法的効力もありません。翻訳されたウェブサイトに含まれる情報の精度に関してご不明な点がありましたら、正式なバージョンである<原文の言語>バージョンをご覧ください。

検索エンジン用のタグを追加

最後にGoogleなどの検索エンジンが翻訳した文章であること、翻訳元のURLを参照出来るようにする必要があるようです。詳しくは公式ドキュメントを参照してください。

部分的に翻訳した内容を公開する場合

一部だけを機械翻訳した場合はその箇所にlang属性で印を付けてあげます。

<span lang="en-x-mtfrom-jp">I am a cat</span> 

lang属性で指定する値の書式は(翻訳後の言語)-x-mtfrom-(翻訳元の言語)となり、ここでは日本語から英語に機械翻訳したしたことを意味します。

1ページ丸ごと翻訳した内容を公開する場合

翻訳したページのhtmlタグのlang属性と、headタグ内にlinkタグを追加します。

<DOCTYPE HTML>
<html lang="en-x-mtfrom-jp">
<head>
  <title>I am a cat</title>
  <link rel="alternate machine-translated-from" hreflang="jp"
            href="http://example.com/nekodearu">
</head>
  • htmlタグ
    • lang属性は(翻訳後の言語)-x-mtfrom-(翻訳元の言語)
  • linkタグ
    • rel属性は機械翻訳されたページであることを意味します
    • hreflang属性は翻訳元の言語
    • href属性は翻訳元ページのURL

その他

トラブルシューティング

アカウント情報が見つからない

以下のエラーが出る場合は、冒頭でご紹介した環境変数GOOGLE_APPLICATION_CREDENTIALSの設定がうまく行ってないか、そもそも実行していない可能性があります。また.bashrcなどに書かずCLIで直接exportコマンドを実行した場合はTerminalを起動する度に打ち直す必要があります。

$ node index.js
UnhandledPromiseRejectionWarning: Error: Unable to detect a Project Id in the current environment. 
To learn more about authentication and Google APIs, visit: 
https://cloud.google.com/docs/authentication/getting-started

以下のように必ず絶対パスで指定してください。

$ export GOOGLE_APPLICATION_CREDENTIALS=/home/katsube/test-translate-katsube-1234567890.json

課金設定が正しくない

何度かAPI叩いていると突然以下のようなエラーが。クレジットカードの情報が古くすでに解約した物が登録されていました。与信が通らなかったので弾かれたっぽいです。

$ node index.js
UnhandledPromiseRejectionWarning: Error: 8 RESOURCE_EXHAUSTED: Check Error: RESOURCE_EXHAUSTED Quota exceeded for quota group 'billable_default' and limit 'General model characters per day' of service 'translate.googleapis.com' for consumer 'project_number:1234567890'.

というわけで新しいクレカに更新したら無事解決。

開始ボタンを押してない

どうもGCPではWebの管理画面上で「開始」ボタンを押さないと利用することができない場合があるようです。

$ node index.js
UnhandledPromiseRejectionWarning: Error: 9 FAILED_PRECONDITION: Service automl.googleapis.com is not activated for project 1234567890.; The model projects/1234567890/locations/us-central1/models/TRL1111111111111111 is not found or is deleted.; codes = [SERVICE_NOT_ACTIVATED (3)

というわけで、左側のメニューをひたすら下の方にスクロールしていき、「翻訳」からの「ダッシュボード」をクリック。

「APIを有効化する」をクリックしてしばらく待てば完了です。

参考ページ