AWS EC2インスタンスからFirebaseの環境をセットアップして、Google Cloud FunctionsからGoogle Cloud Translationにアクセスしてみます。
前回はローカルのNode.js環境からGoogle Cloud TranslationのAPIにアクセスしましたが、今回はGoogle Cloud Functionsの環境からです。
firebaseインストールと認証設定
Node.jsはインストール済みとします。
$sudo npm install-g firebase-tools
$firebase --version9.8.0
インストール後、認証設定が必要です。
$firebase login
これは対話型のコマンドです。
Google認証用のURLが表示されますので、同じようにブラウザでアクセスします。
ブラウザ上で承認すると、gcloudの認証設定と違って http://localhost:9005/?...にリダイレクトされます。firebase loginコマンドをローカルで実行している場合は、コマンドが9005番ポートを一時的に待ち受けているので、ブラウザからコマンドに承認の情報が伝わって、勝手にコマンドが完了します。
firebase loginコマンドをリモートで実行し、ブラウザだけローカルの場合には、これができません。ブラウザに表示されているURLをコピーして、リモートに別ターミナルで接続して curl "http://localhost:9005/?..."を実行します。curlコマンドは以下のようなHTMLを出力します。これで認証設定が完了です。
<h1>Firebase CLI Login Successful</h1><p>You are logged in to the Firebase Command-Line interface. You can immediately close this window and continue using the CLI.</p>firebaseプロジェクト作成
まず空のディレクトリに移ります。
$mkdir sample
$cd sample
プロジェクト設定。
$firebase init
また対話型のコマンドです。
Which Firebase CLI features do you want to set up for this folder?に対して Functions を選択。
Please select an optionに対しては、Google CloudのプロジェクトですでにFirebaseを使ったことがあれば Use an existing projectを選択します。Firebaseを使うのが初めてのGoogle Cloudプロジェクトであれば Create a new projectを選択します。いずれもGoogle Cloudのプロジェクトはすでに存在する前提です。
あとは、 JavaScript or TypeScript の言語選択など、聞かれたことを答えます。
すると、ディレクトリの中にソースコードなどが生成されています。 .gitignoreも生成されていますので、せっかくなので、
$git init
$git add -A$git ls-files
.firebaserc
.gitignore
firebase.json
functions/.gitignore
functions/index.js
functions/package-lock.json
functions/package.json
生成されたソースコードはこの7ファイルのようです。
Cloud Translation APIを有効化
Google Cloudのコンソールにブラウザでアクセスして、使用するプロジェクトのCloud Translation APIを有効化します。
ソースコード編集
functions/index.jsに以下のコードを書きました。
constfunctions=require("firebase-functions");const{TranslationServiceClient}=require("@google-cloud/translate").v3;constprojectId="xxxxxxxx";constlocation="us-central1";// 言語判定asyncfunctiondetectLanguage(text){consttranslationClient=newTranslationServiceClient();constreq={parent:translationClient.locationPath(projectId,location),content:text,mimeType:"text/plain"};constres=awaittranslationClient.detectLanguage(req);letsourceLang=null;for(constelemofres){if(elem==null)// なぜかnullがレスポンスに含まれるcontinue;returnelem["languages"][0]["languageCode"];}}// 翻訳asyncfunctiontranslate(text,sourceLang,targetLang){consttranslationClient=newTranslationServiceClient();constreq={parent:translationClient.locationPath(projectId,location),contents:[text],mimeType:"text/plain",sourceLanguageCode:sourceLang,targetLanguageCode:targetLang,};constres=awaittranslationClient.translateText(req);for(constelemofres){if(elem==null)// なぜかnullがレスポンスに含まれるcontinue;returnelem["translations"][0]["translatedText"];}}asyncfunctionsample(text){constresult={};result["original"]=text;// 言語判定constsourceLang=awaitdetectLanguage(text);// 翻訳for(consttargetLangof["en","ja","zh-TW","zh-CN","ko"]){if(targetLang==sourceLang)// Target language can't be equal to source language. というエラーを防ぐためcontinue;consttargetText=awaittranslate(text,sourceLang,targetLang);result[targetLang]=targetText;}returnresult;}exports.translation_demo=functions.https.onRequest(async(request,response)=>{letquery=request.query["q"];if(!query)query="";sample(query).then(result=>{functions.logger.info(result);response.send(result);}).catch(err=>{functions.logger.info(err);});});functions/package.jsonにはGoogle Cloud Translation用のライブライを追記します。
"dependencies": {
"firebase-admin": "^9.2.0",
- "firebase-functions": "^3.11.0"
+ "firebase-functions": "^3.11.0",
+ "@google-cloud/translate": "*"
},
デプロイ
デプロイ前に npm installが必要みたいです。
$(cd functions; npm install)firebase deployします。これでGoogle Cloud Functionsが作成されます。JavaScriptのソースコード中に exports.translation_demoと書いていますので、 translation_demoという名前のFunctionが作られます。
$firebase deploy
(デプロイに時間がかかるのはどうにかならないだろうか・・・)
実行
$curl -Ssf'https://us-central1-xxxxxxxx.cloudfunctions.net/translation_demo?q=%E5%8F%91%E7%94%9F%E5%9C%A82021%E5%B9%B43%E6%9C%8823%E6%97%A5%E5%9F%83%E5%8F%8A%E6%A0%87%E5%87%86%E6%97%B6%E9%97%B4%E4%B8%8A%E5%8D%887%E6%97%B640%E5%88%86%EF%BC%8C400%E7%B1%B3%E9%95%BF%E7%9A%84%E9%95%BF%E8%8D%A3%E6%B5%B7%E8%BF%90%E9%9B%86%E8%A3%85%E7%AE%B1%E8%88%B9%E9%95%BF%E8%B5%90%E8%BD%AE%E5%9C%A8%E5%9F%83%E5%8F%8A%E8%8B%8F%E4%BC%8A%E5%A3%AB%E8%BF%90%E6%B2%B3%E6%90%81%E6%B5%85%E3%80%82' | jq .{
"original": "发生在2021年3月23日埃及标准时间上午7时40分,400米长的长荣海运集装箱船长赐轮在埃及苏伊士运河搁浅。",
"en": "At 7:40 am Egypt Standard Time on March 23, 2021, the 400-meter-long Evergreen container ship Captain Ci was stranded on the Suez Canal in Egypt.",
"ja": "2021年3月23日のエジプト標準時午前7時40分、長さ400メートルのエバーグリーンコンテナ船のキャプテンCiがエジプトのスエズ運河で立ち往生しました。",
"zh-TW": "發生在2021年3月23日埃及標準時間上午7時40分,400米長的長榮海運集裝箱船長賜輪在埃及蘇伊士運河擱淺。",
"ko": "2021 년 3 월 23 일 이집트 표준시 오전 7시 40 분, 400 미터 길이의 에버그린 컨테이너 선 선장 Ci가 이집트의 수에즈 운하에 좌초했습니다."
}
(固有名詞の翻訳がうまくできてなさそうだけど、まあいいか・・・)
