はじめに
Livebook から AWS のサービスを操作するシリーズです
今回は Amazon Translate を使います
その名の通り、翻訳サービスです
対応言語は 75 言語(日本語含む)、 100 万文字あたり $15 で使用できます
最初の12ヶ月は無料利用枠が適用されるため、 200万文字 / 月まで無料で利用できます
ただし、2022年12月19日現在、東京リージョンでは使えない点に注意してください
実装したノートブックはこちら
事前作業
AWS のアカンウトと、 Translate の権限を持った IAM ユーザーと、その認証情報(ACCESS_KEY_ID と SECRET_ACCESS_KEY)が必要です
実行環境
Livebook 0.8.0 の Docker イメージを元にしたコンテナで動かしました
コンテナ定義はこちらを参照
セットアップ
ex_aws_translate を中心に、必要なモジュールをインストールします
Mix.install([
{:ex_aws, "~> 2.0"},
{:ex_aws_translate, "~> 0.3"},
{:jason, "~> 1.4"},
{:poison, "~> 5.0"},
{:hackney, "~> 1.18"},
{:sweet_xml, "~> 0.7"},
{:kino, "~> 0.8"}
])
エイリアスを付けておきます
alias ExAws.Translate
認証
入力エリアを用意し、そこに IAM ユーザーの認証情報を入力します
ACCESS_KEY_ID と SECRET_ACCESS_KEY は秘密情報なので、値が見えないように Kino.Input.password
を使います
access_key_id_input = Kino.Input.password("ACCESS_KEY_ID")
secret_access_key_input = Kino.Input.password("SECRET_ACCESS_KEY")
普段なら東京リージョンを使うのですが、 Translate は東京リージョンで使えないため、バージニアリージョンを指定します
region_input = Kino.Input.text("REGION", default: "us-east-1")
各認証情報を ExAws に渡すためにまとめておきます
秘密情報が実行結果に現れないよう、セルの最後には "dummy"
を入れておきましょう
auth_config = [
access_key_id: Kino.Input.read(access_key_id_input),
secret_access_key: Kino.Input.read(secret_access_key_input),
region: Kino.Input.read(region_input)
]
"dummy"
言語一覧の取得
実は ex_aws_translate には list_languages 関数が実装されていません
また、なんと GitHub リポジトリーも閉じられてしまっています
パンがなければ作ればいい、ということで無理矢理実装します
languages =
%ExAws.Operation.JSON{
stream_builder: nil,
http_method: :post,
parser: nil,
path: "/",
data: %{},
params: %{},
headers: [
{"Content-Type", "application/x-amz-json-1.1"},
{"X-Amz-Target", "AWSShineFrontendService_20170701.ListLanguages"}
],
service: :translate,
before_request: nil
}
|> ExAws.request!(auth_config)
|> then(& &1["Languages"])
|> Enum.map(&{&1["LanguageCode"], &1["LanguageName"]})
何言語あるか確認してみましょう
Enum.count(languages)
公式 FAQ では 75 言語と書いてあるのに、 76 言語ありました
多い分には良いですが
言語の選択
言語を選択できるようにします
src_lang_select = Kino.Input.select("翻訳元言語", languages, default: "en")
src_lang = Kino.Input.read(src_lang_select)
dst_lang_select = Kino.Input.select("翻訳先言語", languages, default: "ja")
dst_lang = Kino.Input.read(dst_lang_select)
翻訳
元言語と先言語を指定して翻訳します
"Hello"
|> Translate.translate_text(src_lang, dst_lang)
|> ExAws.request!(auth_config)
文章を翻訳してみましょう
text_input =
Kino.Input.textarea("TEXT",
default:
~s/Elixir is a dynamic, functional language for building scalable and maintainable applications. Elixir runs on the Erlang VM, known for creating low-latency, distributed, and fault-tolerant systems. These capabilities and Elixir tooling allow developers to be productive in several domains, such as web development, embedded software, data pipelines, and multimedia processing, across a wide range of industries./
)
text_input
|> Kino.Input.read()
|> Translate.translate_text(src_lang, dst_lang)
|> ExAws.request!(auth_config)
|> then(& &1["TranslatedText"])
"Elixirは、スケーラブルで保守可能なアプリケーションを構築するための動的で機能的な言語です。Elixirは、低レイテンシー、分散型、耐障害性のあるシステムを作ることで知られるErlang VM上で動作します。これらの機能とElixirツールにより、開発者は幅広い業界のウェブ開発、組み込みソフトウェア、データパイプライン、マルチメディア処理など、さまざまな分野で生産性を高めることができます。"
かなり良い感じに翻訳できています
ちなみに、翻訳元言語に "auto" を指定すれば自動的に識別してくれます
# 翻訳元言語の自動識別
text_input
|> Kino.Input.read()
|> Translate.translate_text("auto", dst_lang)
|> ExAws.request!(auth_config)
|> then(& &1["TranslatedText"])
用語登録
Translate の翻訳でも、専門用語など、微妙に正しく翻訳してくれない場合があります
そういった場合に特定の単語はこう翻訳しなさい、と指定できます
以下は手巻き寿司の説明文です
text =
"Temakizushi are cones made of nori seaweed and filled with sushi rice, seafood and vegetables."
text
|> Translate.translate_text("auto", dst_lang)
|> ExAws.request!(auth_config)
|> then(& &1["TranslatedText"])
そのまま翻訳すると以下のような文章になります
"手巻き寿司は、海苔でできたコーンに寿司飯、魚介類、野菜を詰めたものです。"
「コーン」だとトウモロコシだと誤解を招きそうです
「円錐」にしてもらいましょう(それもどうかと思いますが)
用語データは CSV 形式の文字列を BASE64 エンコードして渡します(TSV や TMX にも対応しています)
ヘッダーに言語コード、2行目以降に用語を列挙します
以下のようにすると、英語で「cones」は日本語で「円錐」になります
sushi_terminology_data =
("en,ja\n" <>
"cones,円錐")
|> Base.encode64()
用語データを Translate に登録します
Translate.import_terminology(
"sushi_terminology",
%{
file: sushi_terminology_data,
format: "CSV"
},
"OVERWRITE"
)
|> ExAws.request!(auth_config)
登録した用語データを terminology_names
に指定して翻訳しましょう
text
|> Translate.translate_text("auto", dst_lang, terminology_names: ["sushi_terminology"])
|> ExAws.request!(auth_config)
|> then(& &1["TranslatedText"])
"手巻き寿司は、海苔でできた円錐に寿司飯、魚介類、野菜を詰めたものです。"
きちんと「円錐」になりました
まとめ
翻訳サービスも色々あるのであえてこれを選ばないといけないこともないですが、 AWS 上に建てたシステムからは簡単に呼び出せるので選択肢の一つです
もちろん、 Bumblebee で翻訳できるようになるのももうすぐですが