masalibの日記

システム開発、運用と猫の写真ブログです

Angular Cloud Functionsの翻訳機能を試してみた

Google Cloud Functions and Firebaseを使って
自動翻訳する機能ができるみたいですが
www.youtube.com

おお・・・すごいという所で止まっており
Angularでどうやってやるねん!!所が理解できなかったのですが
やっとサンプルも見つかったんで再現してみた
再現した内容は英語で入力した内容を
フランス語、スペイン語アラビア語に変換する仕組みだった

1・Google Translation APIの許可をおこなう

google デベロッパー コンソール
https://console.cloud.google.com/?hl=ja
に行ってプロジェクトを選択する

APIダッシュボードを表示する

f:id:masalib:20170820023516j:plain
f:id:masalib:20170820023606j:plain

APIとサービスの有効化の画面が表示されたら

Translation

と入力する
f:id:masalib:20170820023931j:plain

クリックするとAPIの許可の画面が表示されるので
「有効化にする」をクリックする
f:id:masalib:20170820024038j:plain

*1・googleのサービスのfirebaseで変換をおこなうためAPI キーなどはメモを取る必要はありません
*2・ちなみにプロジェクトは決済ができるようにしないとできない
無料で遊べる範囲あるので注意が必要

2・firebaseのdatabaseのルールを変更する

firebaseのコンソール画面にいく
datebaseのルールを開してtranslationsを追加する
f:id:masalib:20170820025929j:plain

"translations": {
      ".read": true,
      ".write": true
    } 

Angularのプロジェクト配下のdatabase.rules.jsonも修正する

*1・動画だとmessageというキーだったがサンプルだとtranslationsだったのでそちらに合わせている

3・angularのソースの修正

3-1・cliでベースをつくる

angularのプロジェクトのフォルダに移動して
angularのcliを使って
componetとserviceをつくる

ng g component text-translate
ng g service text-translate/translate

下記のような形になるはず
f:id:masalib:20170820033050j:plain

3-2・app.moduleの修正の確認(自動なので・・・)

cliで作っているので
src/app/app.module.ts

import { TextTranslateComponent } from './text-translate/text-translate.component';

が追加になっていることを確認する

f:id:masalib:20170820033139j:plain

自分のプロジェクトの場合はroutingを使っているので
src/app/app-routing.module.tsの修正もおこなう

import { TextTranslateComponent } from './text-translate/text-translate.component';
	・
	・
  { path: 'text-translate', component: TextTranslateComponent, },

f:id:masalib:20170820033201j:plain

3-3・サービスの修正

単純にfirebaseに保存しているだけ

src/app/text-translate/translate.service.ts

import { Injectable } from '@angular/core';
import { AngularFireDatabase, FirebaseObjectObservable } from 'angularfire2/database';

@Injectable()
export class TranslateService {
  constructor(private db: AngularFireDatabase) { }
  createTranslation(text: string): FirebaseObjectObservable<any> {
    // 翻訳するデータをjson形式で作成
    const data = { 'english': text }
    // firebaseのデータ保存する
    const key = this.db.list('/translations').push(data).key
    return this.db.object(`translations/${key}`)
  }
}
3-4・入力画面(テンプレート)の修正

src/app/text-translate/text-translate.component.html

<h1>翻訳機能テスト</h1>
<textarea rows="8" cols="40" class="input" [(ngmodel)]="userText"></textarea>
<button (click)="handleTranslation()" class="button is-primary">翻訳</button>
<h3>フランス語</h3>
{{ (currentTranslation | async)?.fr || defaultMessage() }}
<h3>スペイン語</h3>
{{ (currentTranslation | async)?.es || defaultMessage() }}
<h3>アラビア語</h3>
{{ (currentTranslation | async)?.ar || defaultMessage() }}
3-5・Componentの修正

src/app/text-translate/text-translate.component.html

import { Component } from '@angular/core';
import { TranslateService } from './translate.service';
@Component({
  selector: 'text-translate',
  providers: [TranslateService],
  templateUrl: './text-translate.component.html',
  styleUrls: ['./text-translate.component.scss']
})

export class TextTranslateComponent {

  userText: string;
  currentTranslation;

  constructor(private translateSvc: TranslateService) { }

  handleTranslation() {
    this.currentTranslation = this.translateSvc.createTranslation(this.userText)
  }

  defaultMessage() {
    if (!this.currentTranslation) return "英語で入力して翻訳のボタンを押してください"
    else return "翻訳中です・・・"
  }

}

参考にしたサイトだと

  providers: [TranslateService],

がなかった・・・
そのため、下記のようなエラーがでた

ERROR Error: Uncaught (in promise): Error: No provider for TranslateService!
Error: No provider for TranslateService!

このエラーっぽいので追加したら治った
https://stackoverflow.com/questions/36063823/angular2-no-provider-for-service-error
f:id:masalib:20170820035111j:plain
このエラーが意味がわからない所がまだ初心者を脱出していない証拠だな〜

4・firebaseのfunctionをつくる

angularのプロジェクトのフォルダに移動する

npm install -g firebase-tools
$ firebase login
#vagrant 
$ firebase login  --no-localhost

プロジェクトを選択してfunctionを選択する

$ firebase init

プロジェクトの配下に
functionsができるはず・・・できないなら
mkdir functionsでつくる

その配下に
index.jsとpackage.jsonがいるはず・・・
ないならつくって修正する

index.jsは
https://github.com/firebase/functions-samples/tree/master/message-translation
を参考にする
LANGUAGESの部分は変更した

functions/index.js

var functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const request = require('request-promise');
const _ = require('lodash');
// List of output languages.
const LANGUAGES = ['es', 'fr', 'ar', 'ja'];

exports.translate = functions.database.ref('/translations/{translationId}').onWrite(event => {
  const snapshot = event.data;
  const promises = [];
  _.each(LANGUAGES, (lang) => {
      console.log(lang)
      promises.push(createTranslationPromise(lang, snapshot));
   })
  return Promise.all(promises)
});
// URL to the Google Translate API.
function createTranslateUrl(lang, text) {
  return `https://www.googleapis.com/language/translate/v2?key=${functions.config().firebase.apiKey}&source=en&target=${lang}&q=${text}`;
}
function createTranslationPromise(lang, snapshot) {
  const key = snapshot.key;
  const text = snapshot.val().english;
  let translation = {}
  return request(createTranslateUrl(lang, text), {resolveWithFullResponse: true}).then(
      response => {
        if (response.statusCode === 200) {
          const resData = JSON.parse(response.body).data;
          translation[lang] = resData.translations[0].translatedText
          return admin.database().ref(`/translations/${key}`)
              .update(translation);
        }
        else throw response.body;
      });
}

functions.config().firebase.apiKey}はfirebaseのapiキーなので自動的にはいる



functions/package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "dependencies": {
    "firebase-admin": "^4.2.1",
    "firebase-functions": "^0.5.7",
    "request": "^2.81.0",
    "lodash": "^4.17.4",
    "request-promise": "^4.2.1"
  },
  "private": true
}


パッケージのインストール

$cd functions
$npm install

プロジェクトのフォルダに移動してデプロイする

$cd ..
$firebase deploy --only functions

=== Deploying to 'angular-study-chat'...

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
i  runtimeconfig: ensuring necessary APIs are enabled...
⚠  runtimeconfig: missing necessary APIs. Enabling now...
⚠  functions: missing necessary APIs. Enabling now...
✔  runtimeconfig: all necessary APIs are enabled
i  functions: waiting for APIs to activate...
i  functions: waiting for APIs to activate...
i  functions: waiting for APIs to activate...
i  functions: waiting for APIs to activate...
i  functions: waiting for APIs to activate...
i  functions: waiting for APIs to activate...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (1.34 KB) for uploading
✔  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: creating function translate...
✔  functions[translate]: Successful create operation. 
✔  functions: all functions deployed successfully!

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/angular-study-chat/overview

5・動作確認

入力画面

f:id:masalib:20170820044400j:plain

ボタンを押すと
翻訳中と表示される

f:id:masalib:20170820044411j:plain

翻訳が完了すると自動的に反映される

f:id:masalib:20170820044426j:plain

firebaseのdatabaseも反映されていることが確認できる

f:id:masalib:20170820044457j:plain

6・参考URL

動画を見ながら再現しました
Text Translation with Firebase Cloud Functions onWrite and Angular 4 - YouTube