【AWS初学者向け】翻訳WEB APIを作成してみた(ハンズオン)

Hands on beginners を参考に実装してみました

【AWS初学者向け】翻訳WEB APIを作成してみた(ハンズオン)
目次

1.はじめに


AWSハンズオン資料集の中から「サーバーレスアーキテクチャで翻訳 Web API を構築する」を試してみて結構楽しかったので

  1. AWS初学者向けに構築フロー
  2. つまずきポイント
  3. 個人的に修正してみた箇所

の3点を共有します。

https://pages.awscloud.com/event_JAPAN_Hands-on-for-Beginners-Serverless-2019_LP.html?trk=aws_introduction_page

上記、URLからAWS初学者の方はぜひトライしてみてください。

参考ドキュメント

2. 構成


スクリーンショット 2021-11-14 15.12.10.png(ハンズオン資料より抜粋)

ブラウザで翻訳語の文字列が返ってくれば完成 スクリーンショット 2021-11-28 12.25.55.png スクリーンショット 2021-11-28 12.26.00.png

3. LambdaからAWS Translateを呼び出す


LambdaからAWS Translateを呼び出すためには、python SDK のboto3を使用します。

https://boto3.amazonaws.com/v1/documentation/api/latest/index.html

公式ドキュメントからtranslateの項目を確認し、使い方を参照します。

スクリーンショット 2021-11-28 12.03.24.png

スクリーンショット 2021-11-28 12.04.18.png

必須パラメータは、下記の通り

response = client.translate_text(
    Text='string',
    SourceLanguageCode='string',
    TargetLanguageCode='string',
    }
)

レスポンスは下記のように返ってくるとのこと スクリーンショット 2021-11-28 12.54.37.png

sample code

import json
import boto3


translate = boto3.client('translate')


def lambda_handler(event, context):
    
    input_text = 'こんにちは'

#日本語→英語への変換
    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )
    output_text = response.get('TranslatedText')
    
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
    }

4. API Gatewayを設定し、Lambdaのソースコードを修正する


アクションからリソースの作成→メソッドの作成を行う スクリーンショット 2021-11-28 13.04.33.png

スクリーンショット 2021-11-28 13.06.04.png

クエリ文字列パラメータの設定 スクリーンショット 2021-11-28 13.10.43.png

API Gateway統合レスポンスで検索すると、 Lambda プロキシ統合で、Lambda 関数は以下の形式で出力を返す必要があることがわかります。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-integration-settings-integration-response.html

{
    statusCode: "...",            // a valid HTTP status code
    headers: { 
        custom-header: "..."      // any API-specific custom header
    },
    body: "...",                  // a JSON string.
    isBase64Encoded:  true|false  // for binary support
}

コード修正


import boto3

translate = boto3.client('translate')

input_text = event['queryStringParameters']['input_text']

response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )
    output_text = response.get('TranslatedText')
    

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

5. DynamoDBに入力テキストと変換後テキストを格納する


事前にテーブルを作成する必要あり

修正箇所

import datetime

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('tranlate-history')

translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )

6. Lambda関数全体


import json
import boto3
import datetime

translate = boto3.client('translate')

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('translate-history')

def lambda_handler(event, context):
    
    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )
    output_text = response.get('TranslatedText')
    
    translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

7. つまずきポイント


https://*******.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんにちは

スクリーンショット 2021-11-28 14.44.35.png

あれ、返ってこない、、、

結論:dynamoDBへの実行ロールを付与し忘れ

スクリーンショット 2021-11-28 14.51.58.png

余談

api gatewayは、作成するときに自動的にロール付与してくれたな。。 スクリーンショット 2021-11-28 14.54.52.png

8. 個人的に工夫した点


任意のステータスコードを返すようにLambda関数にエラーハンドリングを実装

import json
import boto3
import datetime
import logging

translate = boto3.client('translate')

dynamodb = boto3.resource('dynamodb')
translate_history_table = dynamodb.Table('tranlate-history')

def lambda_handler(event, context):
    
    input_text = event['queryStringParameters']['input_text']

# 追加箇所
    try:
        response = translate.translate_text(
            Text=input_text,
            SourceLanguageCode='ja',
            TargetLanguageCode='en'
        )
    except Exception :
        raise ExtendException(400, "Bad Request")

        
    output_text = response.get('TranslatedText')
    
    translate_history_table.put_item(
        Item = {
            'timestamp': datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            'input_text': input_text,
            'output_text': output_text
        }
    )
    
    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

# 追加箇所
class ExtendException(Exception):
    def __init__(self, statusCode, description):
        self.statusCode = statusCode
        self.description = description

    def __str__(self):
        obj = {
            "statusCode": self.statusCode,
            "description": self.description
        }
        return json.dumps(obj)

9. まとめ


SAA資格勉強程度の知識しかなかった私にはとても有用なハンズオンでした。
手を動かして構築してみることは大切ですね。何より楽しい!!
次は、SAMでデプロイの自動化を実装したいと思います。