未経験から半年でAmazon Translate 触ってみた

こんにちは、入社して半年経ちました新米エンジニア、takoです。
地元は海ではなく山の中に住んでました。

学生時代はコンピュータ言語ではなく韓国語の勉強をしていました。
そこで今回のブログデビューは"外国語"に関するものを触ってみたいと思い、
Amazon Translateを触ってみることにしました。

何を翻訳するかというと、Amazon LexのBotを翻訳していこうと思います。

現在Amazon Lexは日本語対応されていないため全て英語です。(2020/10 時点)
そのため、我々日本人が何を言っているか分かるようにするため
Amazon Translateを使って日本語に翻訳していこうというのが今回の試みです。

Amazon Translateとは

Amazon Translate は、高速で高品質な言語翻訳を手ごろな価格で提供する
ニューラル機械翻訳サービスです。

Amazon Translate を使用すると、世界中の言語のユーザー向けにウェブサイトやアプリケーションなどのコンテンツをローカライズし、大量のテキストを効率的に簡単に翻訳できます。

特徴1:幅広い言語への対応

アラビア語、中国語(簡体字繁体字)、英語、フランス語、ドイツ語、インドネシア語、イタリア語、日本語、韓国語、ポルトガル語、ロシア語、スロベニア語、スペイン語タガログ語タイ語ベトナム語、など55 の言語の翻訳に対応しています。

また、英語から日本語、日本語から英語など相互変換が可能です。

特徴2:正確かつ自然な翻訳

ディープラーニング手法を使用し、より正確で流暢な翻訳を生成します。

そのおかげでユーザーがAmazon Translateを使えば使うほど、システムが言葉や文章のニュアンスを学習して使いやすくなっていきます。

特徴3:カスタム設定

特定の組織、分野、業界における独自の用語や名称をカスタムで設定することができるため誤訳が減り自然な翻訳になります。

ブランド名、製品名などの固有名詞を登録することができます。

 

Amazon Lexとは

Amazon Lex は、音声やテキストを使用して、任意のアプリケーションに

特徴1:高品質の音声認識自然言語理解

デベロッパーが入力する発話例に基づいて、話者が意図を表現するさまざまな方法を学習できます。

音声言語理解システムでは、自然言語の音声とテキストによる入力を受け取り、
その背景にある意図を理解し、適切な応答を呼び出すことによってユーザーの意図を実行します。

特徴2:複数回にわたる対話

Amazon Lex ボットでは、対話内容を保持してステートフルに対話を行うことができます。
インテントが特定されると、ユーザーは、そのインテントを実行するために必要な情報の入力を求められます。
(例えば、インテントが "ホテルの予約" である場合、ユーザーは場所、チェックインの日付、宿泊日数などの入力を求められます)

特徴3:AWS Lambda との統合

AWS Lambda との統合がネイティブでサポートされており、データ取得、更新、およびビジネスロジックの実行に活用できます。
サーバーレスのコンピューティング性能を生かして、ボットの開発に注力しながら、大規模なビジネスロジックを簡単に実行できます。

Amazon LexのBotを翻訳してみた

さて、本題に移っていきます。
以下のような流れで進めていきます。

1.ユーザーが日本語で入力した文章をAmazon Translateが英語に翻訳
2.Amazon Lex Botが英語で返答
3.Amazon Lex Botの返答をAmazon Translateが日本語に翻訳
4.日本語に翻訳したものをユーザーに返す

ということで、Amazon LexのBotを作成しLambda関数を作成していきます。

手順① Amazon LexのBotを作成

Amazon Lexコンソールを開きます。
https://ap-northeast-1.console.aws.amazon.com/lex/

Createを押下すると、「Custom Bot(カスタムボット)」またはサンプルのボットを選択することができます。

lex

今回はお手軽にサンプルのBotにあったBook Car(レンタルカー予約)を選択してみました。
中身の文章は特に変えずに翻訳ができるかどうかを試していきます。
Botの文章を変えてみたり、Botをカスタムで作成してちゃんと翻訳されるのかも試してみたいですね…)

手順② Lambda関数の作成

Lambda関数を作成してみました。

const Aws = require('aws-sdk');
const Translate = new Aws.Translate({region: 'us-east-1'});
const lexruntime = new Aws.LexRuntime();
let lex_response = ""

// メイン
exports.handler = async (event) => {
    console.log('event :' + JSON.stringify(event));
    let js = JSON.stringify(event);
    let body = JSON.parse(js);
 
    let js_body_text = body.body;
    //日本語→英語
    let rs = await getAwsTranslate(js_body_text,'ja','en');
    
    // lexに情報を渡す
    await postLex(rs.TranslatedText);
    console.log(lex_response);
    // 英語→日本語
    let rs2 = await getAwsTranslate(lex_response,'en','ja');
 
    return {statusCode: 200,message:rs2.TranslatedText};
};

// textを送信してlexからresponseを受け取るメソッド
async function postLex(inputText){
    var params = {
        botAlias:"initial",
        botName: "translate_bot",
        inputText: inputText,
        userId: "userId"
        // sessionAttributes: "sessionAttributes"
    };
    await lexruntime.postText(params,function(err,data){
        if(err){
            console.log(err);
        }else{
            console.log(data.message);
            lex_response = data.message;
        }
    });

}

// 翻訳するメソッド
function getAwsTranslate(js_text,in_Language,out_Language) {
    return new Promise(((resolve, reject) => {
        let params = {
            Text: js_text,
            SourceLanguageCode: in_Language,
            TargetLanguageCode: out_Language
        }
        Translate.translateText(params, function(err,data){
            if (err) {
                console.log(err);
                reject();
            } else {
                console.log(JSON.stringify(data));
                resolve(data);
            }
        });
    }));
};

テストデータはこちらです。
これが上記のユーザーがAmazon Lexに対して話す内容になります。

テスト

テスト結果

START RequestId: 8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d Version: $LATEST
2020-10-12T05:58:31.001Z    8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d    INFO    event :{"body":"車を予約したいです。"}
2020-10-12T05:58:32.069Z    8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d    INFO    {"TranslatedText":"I want to book a car.","SourceLanguageCode":"ja","TargetLanguageCode":"en"}
2020-10-12T05:58:32.149Z    8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d    INFO    Sorry, what can I help you with?
2020-10-12T05:58:32.515Z    8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d    INFO    Sorry, I am not able to assist at this time
2020-10-12T05:58:32.976Z    8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d    INFO    {"TranslatedText":"申し訳ありませんが、私はあなたを助けることができますか?","SourceLanguageCode":"en","TargetLanguageCode":"ja"}
END RequestId: 8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d
REPORT RequestId: 8b5cc7f8-c58d-4aa5-9e57-06b5c13a4b2d  Duration: 1975.99 ms    Billed Duration: 2000 ms    Memory Size: 128 MB Max Memory Used: 89 MB  

このようにユーザーの入力した内容に対して、Amazon Lexの返答が日本語で返ってきました!

 

困ったところ


async/awaitがうまく使えずに
値が空白のまま次の処理に行ってしまったためエラーが出ました。
↓もともと書いたasync/awaitのないコード
ログからも分かるように値が0だよというエラーが出ています

// textを送信してlexからresponseを受け取るメソッド
function postLex(inputText){
    var params = {
        botAlias:"initial",
        botName: "translate_bot",
        inputText: inputText,
        userId: "userId"
        // sessionAttributes: "sessionAttributes"
    };
    lexruntime.postText(params,function(err,data){
        if(err){
            console.log(err);
        }else{
            console.log(data.message);
            lex_response = data.message;
        }
    });

}
テスト2

START RequestId: 8aeccf8a-269a-453b-a141-74d72e0f2cac Version: $LATEST
2020-10-12T06:16:30.653Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    INFO    event{"body":"車を予約したいです。"}
2020-10-12T06:16:32.170Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    INFO    {"TranslatedText":"I want to book a car.","SourceLanguageCode":"ja","TargetLanguageCode":"en"}
2020-10-12T06:16:32.231Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    INFO    
2020-10-12T06:16:32.603Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    INFO    Sorry, what can I help you with?
2020-10-12T06:16:33.059Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    INFO    ValidationException: Text size cannot be zero.
    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:51:27)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18) {
  code: 'ValidationException',
  time: 2020-10-12T06:16:33.056Z,
  requestId: '044b2cb1-d12e-4c8c-bf97-acd27dfdeeac',
  statusCode: 400,
  retryable: false,
  retryDelay: 99.02595880869502
}
2020-10-12T06:16:33.109Z    8aeccf8a-269a-453b-a141-74d72e0f2cac    ERROR   Invoke Error    {"errorType":"Error","errorMessage":"handled","stack":["Error: handled","    at _homogeneousError (/var/runtime/CallbackContext.js:12:12)","    at postError (/var/runtime/CallbackContext.js:29:54)","    at done (/var/runtime/CallbackContext.js:56:7)","    at fail (/var/runtime/CallbackContext.js:66:7)","    at /var/runtime/CallbackContext.js:104:16","    at processTicksAndRejections (internal/process/task_queues.js:97:5)"]}
END RequestId: 8aeccf8a-269a-453b-a141-74d72e0f2cac
REPORT RequestId: 8aeccf8a-269a-453b-a141-74d72e0f2cac  Duration: 2477.05 ms    Billed Duration: 2500 ms    Memory Size: 128 MB Max Memory Used: 87 MB  Init Duration: 522.07 ms    
 

まとめ

上述しましたが、Botの文章を変えてみたり、Botをカスタムで作成してちゃんと翻訳されるのかも試してみたいと思いました。
また、Amazon Translateは多言語に対応しているため、英語以外の言語で試してみるのも面白いかもしれません。
是非皆さんもAmazon Translateを試してみてください!


参考サイト:Amazon Translate→(https://aws.amazon.com/jp/translate/
Amazon Lex→(https://aws.amazon.com/jp/lex/

aws.amazon.com

aws.amazon.com

 

ブログ著者

 

 

 

AWS相談会バナー