Amazon Translateを使ってSlackで翻訳コマンドを作成

Amazon Translateを用いて、日本語<->英語を相互翻訳するSlackコマンドを作成してみます。

構成

仕様

slackの対象の部屋で「/translate」と打つと、そこから先の文章をAmazon Translateで翻訳し、翻訳前と後を両方とも表示してくれる。

作成手順

  1. Lambda関数の作成
  2. API Gatewayの作成とLambda関数の紐づけ
  3. Slack Slash CommandとAPI Gatewayの紐づけ


Lambda関数の作成

翻訳用のLambda関数を作成します。

まず、Lambda関数に適応するロールを作成します。
今回はTranslate周りだけなので以下のようにすれば大丈夫です。

[サービス] > [Lambda] を選択。


Translateで検索し、[TranslateReadOnly] を選択。


ロール名と説明を適当に設定し作成。


ロールが作成できたら、Lambda関数を作成します。

名前、ランタイム、ロールを設定し作成。


Lambda関数はこちら。

import boto3
import os
import json
import unicodedata
from urllib.parse import parse_qs

def is_ja(string):
    for char in string:
        name = unicodedata.name(char) 
        if "CJK UNIFIED" in name or "HIRAGANA" in name or "KATAKANA" in name:
            return True
    return False

def lambda_handler(event, context):

    # トークン確認
    token = os.environ['SLACK_TOKEN']
    query = parse_qs(event.get('body') or '')
    if query.get('token', [''])[0] != token:
        return { 'statusCode': 400 }

    # 引数を取得
    text = query.get('text', [''])[0]

    # 翻訳
    translate = boto3.client(service_name='translate', region_name='us-east-1', use_ssl=True)

    if (is_ja(text)):
        result = translate.translate_text(Text=text, 
                    SourceLanguageCode="ja", TargetLanguageCode="en")
        translate = "日本語 -> 英語"
    else:
        result = translate.translate_text(Text=text, 
                    SourceLanguageCode="en", TargetLanguageCode="ja")
        translate = "英語 -> 日本語"


    return {'statusCode': 200,
            'body': json.dumps({
                'text': translate + "\n翻訳前:\n" + text + "\n\n\n翻訳後:\n" + result.get('TranslatedText')
            })}

上のプログラムだと自分しか見れなく、更新すると消えてしまします。

もし、特定のチャンネルに投稿したい場合は以下のようにすると良いです。

import boto3
import os
import json
import unicodedata
from urllib.parse import parse_qs
import urllib.request

def is_ja(string):
    for char in string:
        name = unicodedata.name(char) 
        if "CJK UNIFIED" in name or "HIRAGANA" in name or "KATAKANA" in name:
            return True
    return False

def lambda_handler(event, context):

    # トークン確認
    token = os.environ['SLACK_TOKEN']
    query = parse_qs(event.get('body') or '')
    if query.get('token', [''])[0] != token:
        return { 'statusCode': 400 }

    # 引数を取得
    text = query.get('text', [''])[0]

    # 翻訳
    translate = boto3.client(service_name='translate', region_name='us-east-1', use_ssl=True)

    if (is_ja(text)):
        result = translate.translate_text(Text=text, 
                    SourceLanguageCode="ja", TargetLanguageCode="en")
        translate = "JA -> EN"
    else:
        result = translate.translate_text(Text=text, 
                    SourceLanguageCode="en", TargetLanguageCode="ja")
        translate = "EN -> JA"

    # 投稿
    userID = query.get('user_id', [''])[0]
    hook = ""
    headers = {"Content-Type" : "application/json"}
    method = "POST"
    json_data = {'text': "<@" + userID + "> の翻訳\n" + translate + "\n翻訳前:\n" + text + "\n\n\n翻訳後:\n" + result.get('TranslatedText')}
    json_data = json.dumps(json_data).encode("utf-8")

    request = urllib.request.Request(hook,
                            data=json_data,
                            method=method, headers=headers)

    urllib.request.urlopen(request)

    return {'statusCode': 200}

この場合は[Incoming Webhook]でWebhook用のURLを作成し、hook変数に代入してあげると、コマンドを入力した際に投稿されるようになります。


API Gatewayの作成とLambda関数の紐づけ

[API Gateway] > [APIの作成] と進み、以下のように設定します。
API名と説明は適当です。


APIが作成できたら、[アクション] > [メソッドの作成] > [POST] を選択し、チェックをクリック。
以下のように、項目を設定し保存。


[アクション] > [APIのデプロイ] と進み、以下のように設定しデプロイ。

URLの呼び出し:URLはSlack Appsに設定するので、控えておきましょう。(あとからでも確認できます)

これで、API GatewayとLambdaの紐づけは完了です。


Slack Slash CommandとAPI Gatewayの紐づけ

こちらでSlack Appsを作成します。

中央の[Start Building]をクリックします。

アプリの名前とWordkspaceを設定し作成。


[Slash Commands] > [Create New Command] と進み、以下のように項目を設定しSave。
Request URLはAPI GatewayのメモったURLになります。


[Basic Information] > [App Credentials][Signing Secret]を、先程作成したLambdaの環境変数に設定し保存。

これで完成。

こんな感じで、コマンドを実行すると翻訳できます。

実際にチャットしている感じは以下のようになります。

少し読みづらいですが、リアルタイムのチャットが翻訳されて表示されます。

投稿ボタンを押してから1.2秒程度時間がかかっていますが、そこまで気になるレベルの投稿遅延ではありませんでした。

実用的、かどうかは翻訳の精度がいまいちなので微妙ですが、精度が上がればかなりいい使い方ができそうです。