RSSで取得した英語をAmazon Translateで日本語に翻訳してSlackに通知してみた

AWS

2024.3.18

Topics

はじめに

どうも。英語苦手勢代表のnt1です。
みなさんは英語得意ですか。私は苦手です。
なのでRSSで取得した英語を日本語に翻訳するアプリケーションを作成することにしました。
本記事ではその作成方法・手順についてご紹介できればと思います。

構成概要

構成図については下記になります。

実装イメージとしてはLambda関数にてPython3.8を使用してWhat’s New with AWS?からRSSフィードを取得します。
feedparserという外部ライブラリを使用してフィードのフォーマットの差異を吸収して扱いやすくしています。
試しにRSSフィードを取得してみると以下のような形式で出力されています。

{
    "links": [
        {
            "rel": "alternate",
            "type": "text/html",
            "href": "https://aws.amazon.com/about-aws/whats-new/2024/02/amazon-cloudfront-availability-embedded-pops/"
        }
    ],
    "link": "https://aws.amazon.com/about-aws/whats-new/2024/02/amazon-cloudfront-availability-embedded-pops/",
    "id": "5c68127f3511b9d7e5316e365e5195db62eaedde",
    "guidislink": false,
    "title": "Amazon CloudFront announces availability of Embedded Points of Presence",
    "title_detail": {
        "type": "text/plain",
        "language": null,
        "base": "https://aws.amazon.com/about-aws/whats-new/recent/feed/",
        "value": "Amazon CloudFront announces availability of Embedded Points of Presence"
    },
    "summary": "<p>Amazon CloudFront embedded Points of Presence (POPs) are a new type of CloudFront infrastructure deployed closest to end viewers, within internet service provider (ISP) and mobile network operator (MNO) networks. Embedded POPs are custom built to deliver large scale live-stream video, video-on-demand (VOD), and game downloads. Today, CloudFront has 600+ embedded POPs deployed across 200+ cities globally.<br /> </p>",
    "summary_detail": {
        "type": "text/html",
        "language": null,
        "base": "https://aws.amazon.com/about-aws/whats-new/recent/feed/",
        "value": "<p>Amazon CloudFront embedded Points of Presence (POPs) are a new type of CloudFront infrastructure deployed closest to end viewers, within internet service provider (ISP) and mobile network operator (MNO) networks. Embedded POPs are custom built to deliver large scale live-stream video, video-on-demand (VOD), and game downloads. Today, CloudFront has 600+ embedded POPs deployed across 200+ cities globally.<br /> </p>"
    },
    "published": "Mon, 26 Feb 2024 21:04:06 +0000",
    "published_parsed": {
        "tm_year": 2024,
        "tm_mon": 2,
        "tm_mday": 26,
        "tm_hour": 21,
        "tm_min": 4,
        "tm_sec": 6,
        "tm_wday": 0,
        "tm_yday": 57,
        "tm_isdst": 0
    },
:
:
:

今回は概要が分かればよいのでこの中からtitlelinksummaryを取得します。
publishedの時間と現在の時間を比較して1日前までに更新されたものだけ翻訳処理をかけるようにしています。
翻訳処理はtitlesummaryAmazon Translateに渡して日本語訳にしてもらっています。
そのあとSlack APPを使用してSlackチャンネルに日本語に翻訳したタイトル(リンク)、概要を通知します。
イメージとしては以下のようなSlackメッセージが投稿されます。
後は日時で定期実行するEventBridgeを設定しており毎日特定の時間に通知されるように設定しています。

Amazon Translateについては、下記記事にてAmazon TranslateとAWS LambdaでAmazon S3にアップロードされたファイルの内容を翻訳するアプリケーションを作成する手順を解説していますので、興味がありましたらご確認ください。

関連記事
Amazon TranslateとAWS Lambdaで簡単自動翻訳:AWS公式ハンズオン紹介

作成手順

本手順では下記の流れで構築していきます。

  1. Slack APP作成
    1.1 Slackチャンネル設定
  2. Lambdaレイヤー&関数作成
    2.1 Lambda関数設定
    2.2 Lambdaコード作成
  3. Lambda関数実行
  4. EventBridge作成

1. Slack APP作成

まず外部サービス連携でよく使われるIncoming Webhookは以下の説明文のとおり非推奨であり将来的に削除される可能性があるため、代替手段のSlack APPを使用しています。
Slack apiでAPPを作成して権限のあるSlackワークスペースにインストールすることが可能です。

本項ではSlack APPを作成してOAuth&権限設定を行いワークスペースにインストールする手順を解説していきます。

Slack apiより「Create New App」を選択します。
「From scratch」を選択します。

  • App Nameは任意の値を選択(今回の場合はtranslate bot)
  • Pick a workspace to develop your app inは任意のワークスペースを選択

左ペインの「OAuth & Permissions」を選択します。
Scopesという項目がありますので「Add an OAuth Scope」をクリックして下記権限を選択します。

  • chat:write
  • chat:write.customize
  • chat:write.public ※APPが参加していないチャンネルに通知する場合

完了したら「Basic Information」に戻り、「Install to Workspce」を選択します。

APPの実行できる権限が表示されるので確認して「許可する」を選択します。

先ほどの「OAuth & Permissions」ペインでBot User OAuth Tokenが発行されていますのでこれをcopyしておいてください。
後の手順で使用します。

1.1 Slackチャンネル設定

Slackチャンネルに先ほど作成したAPPを追加します。
先ほどの権限設定でchat:write.publicを付与した場合はチャンネルに追加せずとも通知可能です。

通知したいSlackチャンネルの設定画面を開き「インテグレーション」から「アプリの追加」で作成したAPPを追加します。

同じ画面の「チャンネル情報」タブに記載されているチャンネルIDについても後の手順で使用しますのでcopyしておいてください。

2. Lambdaレイヤー&関数作成

AWS Lambdaはデフォルトでは外部ライブラリを利用することができません。
そのためライブラリと実行ファイルをひとまとめにしてzipファイル化してLambdaレイヤーにインポートすることでその外部ライブラリを利用することが可能になります。
今回はRSSフィード用のfeedparserとSlack通知用のslack_sdkを利用しているためLambdaレイヤーにそれぞれインポートしていきます。
Lambda関数1つにつき5つのレイヤーまでという制限があるため気になる方は複数のライブラリをひとまとめにしてアップロードしても問題ありません。

本項ではfeedparser,slack_sdkそれぞれのLambdaレイヤーを作成し関数に紐づける手順を解説していきます。
「Lambda」コンソールに移動して「Lambdaレイヤーを作成」を選択します。

  • 名前は任意の名前を選択(今回の場合はnt1-feedparserとnt1-slack_sdk)
  • ライブラリをアップロードします。方法は割愛しますがpythonフォルダにpipなどを使用してライブラリをインストールしてzipファイル化すれば大丈夫です。
  • 互換性のあるアーキテクチャ-オプションを「x86_64」を選択
  • 互換性のあるランタイム-オプションを「Python3.8」を選択

作成が完了したら「関数」タブの「関数を作成」を選択します。

  • 名前は任意の名前を選択(今回の場合はnt1-translate-rss)
  • ランタイムは「Python3.8」を選択
  • アーキテクチャは「x86_64」を選択
  • 実行ロールは「基本的な Lambda アクセス権限で新しいロールを作成」を選択
    ※IAMロールは後から権限追加します。
  • その他はデフォルトで問題ありません。

では先ほど作成したLambdaレイヤーをLambda関数に紐づけます。
下記画像の「Layers」を選択します。

「レイヤーの追加」を選択します。

  • レイヤーソースは「カスタムレイヤー」を選択
  • 先ほど作成したLambdaレイヤーを追加

レイヤーとして表示されていれば完了です。

2.1 Lambda関数設定

本項ではLambda関数のタイムアウト設定、アクセス権限を設定していきます。

タイムアウトの設定

今回の関数だとタイムアウト値がデフォルトの3秒では処理が終わらないため30秒くらいに設定しておきます。
この辺りはRSS URLの数やフィードの数に依存すると思いますので適宜変更してください。

Lambda関数の「一般設定」から「編集」を選択します。

  • タイムアウトを30秒に設定

アクセス権限設定

Lambda関数の「アクセス権限」から「IAMロール名」を選択しIAMの画面に遷移します。


「許可を追加」⇒「ポリシーをアタッチ」からマネージドポリシーのTranslateFullAccessを選択します。

Lambda関数設定についてはこれで完了です。

2.2 Lambdaコード作成

Lambdaコードの全文は下記になります。
SLACK APPで使用するSLACK_ACCESS_TOKENCHANNEL_ID1. Slack APP作成でcopyしたBot User OAuth TokenとチャンネルIDに置き換えてください。

import re
import feedparser
import boto3
import slack_sdk
from datetime import datetime,timedelta
from dateutil import tz
from dateutil import parser
from slack_sdk import WebClient

# Amazon translate
translate = boto3.client('translate')
SRC_LANG = 'en'
TRG_LANG = 'ja'

# timezone
timezone = tz.gettz('Asia/Tokyo')

# RSS URL
RSS_URL = 'https://aws.amazon.com/about-aws/whats-new/recent/feed/'

def lambda_handler(event, context):
    # RSS取得
    data = feedparser.parse(RSS_URL)

    # 1件ずつitemを取得
    for entry in data.entries:
        print(entry.description)
        title = entry.title
        link = entry.link
        # summaryにはHTMLタグが含まれるので削除
        description = remove_http_tag(entry.summary)
        # 現在の時刻と更新時刻を取得
        published = parser.parse(entry.published).astimezone(timezone)
        current_time = datetime.now(timezone)

        # 1日前までに更新があったものだけ翻訳&Slack通知
        if current_time < published + timedelta(days=1):
            # タイトルと要約はAmazon Translateで翻訳
            ja_title = get_translate_text(title)
            ja_description = get_translate_text(description)

            # Slackに通知
            SLACK_ACCESS_TOKEN = '<SLACK_ACCESS_TOKEN>'
            CHANNEL_ID = '<CHANNEL_ID>'
            
            # Slackクライアントを作成
            client = WebClient(SLACK_ACCESS_TOKEN)

            # チャンネルにメッセージを投稿
            msg = f"<{link}|{ja_title}>\n\n*概要:* {ja_description}"
            response = client.chat_postMessage(channel=CHANNEL_ID, text=msg, icon_emoji=':ghost:')

def remove_http_tag(str):
    return re.sub(re.compile('<.*?>'), '', str)
    
def get_translate_text(text):
    # 英語→日本語 翻訳
    response = translate.translate_text(
        Text=text,
        SourceLanguageCode=SRC_LANG,
        TargetLanguageCode=TRG_LANG
    )

    return response.get('TranslatedText')

Lambdaコード解説

ここからはコードの解説です。手順を先に進めたい方は3. Lambda関数実行まで読み飛ばしてください。

取得しているRSS

What’s New with AWS?からRSSフィードを取得しています。
日本語版のサイトもありますが英語版のほうが更新が速いので英語版で見たいです。

# timezone
timezone = tz.gettz('Asia/Tokyo')

# RSS URL
RSS_URL = 'https://aws.amazon.com/about-aws/whats-new/recent/feed/'

def lambda_handler(event, context):
    # RSS取得
    data = feedparser.parse(RSS_URL)

    # 1件ずつitemを取得
    for entry in data.entries:

RSSの取得方法

RSSフィードを一件ずつ処理していきます。
titlelinksummaryを取得します。
summaryにはHTMLタグが含まれるため除外しています。
publishedの時間と現在の時間を比較して1日前までに更新されたものだけ翻訳処理をかけるようにしています。

    # 1件ずつitemを取得
    for entry in data.entries:
        print(entry.description)
        title = entry.title
        link = entry.link
        # summaryにはHTMLタグが含まれるので削除
        description = remove_http_tag(entry.summary)
        # 現在の時刻と更新時刻を取得
        published = parser.parse(entry.published).astimezone(timezone)
        current_time = datetime.now(timezone)

        # 1日前までに更新があったものだけ翻訳&Slack通知
        if current_time < published + timedelta(days=1):
            # タイトルと要約はAmazon Translateで翻訳
            ja_title = get_translate_text(title)
            ja_description = get_translate_text(description)
                   :
                 [省略]
                   :
def remove_http_tag(str):
    return re.sub(re.compile('<.*?>'), '', str)

Amazon Translateによる翻訳

AWS SDK for Python (Boto3)を使用してAmazon Translateを呼び出し翻訳しています。
SRC_LANGTRG_LANGで言語を選択してAPIをたたいて翻訳しています。
Amazon TranslateのAPIを利用するのに特段事前設定は必要なく非常にシンプルでわかりやすいです。

# Amazon translate
translate = boto3.client('translate')
SRC_LANG = 'en'
TRG_LANG = 'ja'
                   :
                 [省略]
                   :
        # 1日前までに更新があったものだけ翻訳&Slack通知
        if current_time < published + timedelta(days=1):
            # タイトルと要約はAmazon Translateで翻訳
            ja_title = get_translate_text(title)
            ja_description = get_translate_text(description)
                   :
                 [省略]
                   :
def get_translate_text(text):
    # 英語→日本語 翻訳
    response = translate.translate_text(
        Text=text,
        SourceLanguageCode=SRC_LANG,
        TargetLanguageCode=TRG_LANG
    )

    return response.get('TranslatedText')

Slackへの通知方法

Slack APPを使用しています。
通知フォーマットについては特にこだわる予定はなかったので最低限設定しています。
SLACK_ACCESS_TOKENCHANNEL_ID1. Slack APP作成でcopyしたBot User OAuth TokenとチャンネルIDに置き換えてください。

            # Slackに通知
            SLACK_ACCESS_TOKEN = '<SLACK_ACCESS_TOKEN>'
            CHANNEL_ID = '<CHANNEL_ID>'
            
            # Slackクライアントを作成
            client = WebClient(SLACK_ACCESS_TOKEN)

            # チャンネルにメッセージを投稿
            msg = f"<{link}|{ja_title}>\n\n*概要:* {ja_description}"
            response = client.chat_postMessage(channel=CHANNEL_ID, text=msg, icon_emoji=':ghost:')

3. Lambda関数実行

では想定通り動くかどうかLambda関数を手動で実行してみましょう。
Lambdaのテスト画面から「テスト」を選択します。

うまくいった場合はSlackチャンネルに以下のようなメッセージが投稿されているかと思います。

4. EventBridge設定

最後に定期実行用のEventBridgeの設定を行います。
実行頻度はCron式もしくはrate式で設定することが可能です。
時間指定する際はUTC時間で設定が必要なので注意してください。

Lambda画面より「トリガーを追加」を選択します。

  • ソースを選択で「EventBridge(Cloudwatch Events)」を選択
  • Ruleで「Create a new rule」を選択
  • Rule name、Rule descriptionは任意の値を選択
  • Rule typeは「Schedule expression」を選択
  • Schedule expressionはcron式もしくはrate式で入力できます。(私は朝7:00くらいに通知してほしいのでcron(0 22 * * ? *)と入力しました。)

最後に

以上がRSSリーダーで取得した英語を日本語に翻訳するアプリケーションを作成してSlackに通知する手順となります。
私と同じ英語苦手勢に刺さればいいなと思っています。
今のところAmazon Translateが翻訳した文章に違和感はありません。
これからもしばらく使ってみてAmazon Translateの翻訳精度についても確認していきたいですね。

最後まで読んでいただきありがとうございます!

NT1

インフラエンジニアです。刹那的に生きてます。

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら