2022年11月11日 更新

Azure Translator ドキュメント翻訳APIとLogicAppsで社内向けサービスを作った話

さまざまな仕事関連で海外とのやり取りが増えるにつれ、外国語の文書を読まなければいけない場面も増えていますね。まずは時間をかけずに翻訳して内容を把握できたら...という需要も聞かれるようになっています。そこでAzure Translatorの機能であるドキュメント翻訳API(公式ブログ)をLogicAppsと組み合わせて、ローコードかつサーバーレスでさくっと社内向けサービスとして公開した事例を紹介します。

ざっくり構成と処理の流れ

1. SharePoint上に翻訳インプット用のフォルダを作成し、ユーザーは翻訳したいファイルをアップロードします。
2. フォルダにファイルがアップロードされたことをトリガーにLogicAppsが起動し、対象ファイルを取得。
3. ファイルをBlobストレージに配置。
4. ドキュメント翻訳APIにリクエストを送信。
5. 翻訳されたファイルがBlobストレージにできるので取得。
6. 取得したファイルをSharePoint上にアップロード。
7. Blob上のファイルを削除して終了。

処理の詳細とポイント


├─ドキュメント翻訳
│ ├─アウトプット
│ └─インプット
│ ├─日本語→英語
│ └─英語→日本語


.

前提

公式ドキュメントをもとにTranslatorサービスのリソースとBlob Containerを作成しておく。
・ SharePointの任意の場所にインプットとアウトプットフォルダを作成しておく。
※今回はMicrosoftサービスで統一していますが、LogicAppsにはBoxやDropBoxのコネクタも用意されています。

① トリガーの設定

SharePointコネクタの「ファイルが作成されたとき」トリガーを設定します。
トリガーが発火すると作成されたファイルの識別IDが取得できます。

② 翻訳ターゲットの言語を指定するために変数を確保しておく

ファイルがアップロードされたフォルダによって翻訳ターゲットの言語を振り分けるため変数を2つ確保しておきます。

1つはfolderとし、初期値にファイルが置かれたフォルダ名が入るように式を書きます。
式はlast(take(split(triggerBody()?['{Path}'],'/'),4))とします。
※①で取得したファイルへのパスを / でスプリットし、配列の最後の値を取得しています。

もう1つはlangとします。

③ 翻訳ターゲットの言語を設定する

Switchアクションを使います。
スイッチの比較対象には②で初期化したfolder変数を、各ケースにはフォルダ名(日本語→英語など)を設定します。

ケースごとのアクションではlang変数に enjaなどの言語コードを指定します。
※Azure Translatorが対応している言語コード一覧はこちら

④ ファイルコンテンツの取得

①で取得した識別IDを使って実際のファイルコンテンツを取得します。

⑤ Blobストレージにファイルをアップロード

ドキュメント翻訳APIを実行するには、一度コンテンツをBlobに置き、そのパスを指定する必要があります。

⑥ SAS(Shared Access Signature)を取得

SASについては公式ドキュメントを参照ください。
まずは翻訳前(ソース)ドキュメントのblobからSASを取得。
有効期限は式 addMinutes(utcNow(),10,'yyyy-MM-ddTHH:mm:ss')を使って10分後を指定。
アクセス許可はReadとList。

次に翻訳後(ターゲット)ドキュメントのSASを取得。
ターゲットにはドキュメントを指定するのではなくBlobコンテナーを指定。
有効期限は同様に10分後。
アクセス許可はWriteとList。

⑦ ドキュメント翻訳APIへのリクエスト

ヘッダーのOcp-Apim-Subscription-KeyにはTranslatorサービスのサブスクリプションキーを指定。
URIは、https://.cognitiveservices.azure.com/translator/text/batch/v1.0-preview.1

本文(Body)

・sourceUrl: 翻訳前ファイルのSASを指定。
・language: ③で指定した言語コード。
・targetUrl:翻訳後のファイルとわかるようにファイル名の先頭にtranslated-を付与し、後半に元のファイル名+ ターゲットSASの?より後ろを指定。

?@{last(split(body('パスを使用して_SAS_URI_を作成する_2')?['WebUrl'],'?'))
・SASの?以降にトークン情報が含まれているため。


{
"inputs": [
{
"source": {
"sourceUrl": "@{body('パスを使用して_SAS_URI_を作成する')?['WebUrl']}"
},
"storageType": "File",
"targets": [
{
"language": "@{variables('lang')}",
"targetUrl": "https://<NAME-OF-YOUR-RESOURCE>.blob.core.windows.net/target/translated-@{triggerBody()?['{FilenameWithExtension}']}?@{last(split(body('パスを使用して_SAS_URI_を作成する_2')?['WebUrl'],'?'))}"
}
]
}
]
}


.

⑧ ターゲットのBlobパスで変数を初期化

ドキュメント翻訳APIはバッチで処理されるため成功してもレスポンスにはターゲットBlobのパスは含まれない。
そのため文字列と元のファイル名を連結してblob_pathを宣言しておく。
concat('/target/translated-',triggerBody()?['{FilenameWithExtension}'])

補足:Blobが作成されるまである程度ラグがあるため1分程度スリープを入れる。

⑨ターゲットBlobのコンテンツを取得

⑧で宣言したblob_pathを指定して、翻訳後のコンテンツを取得します。

⑩SharePointに翻訳されたコンテンツを作成

Azure上にファイルを残さないようにソース、ターゲット共に削除。
※当社のセキュリティ要件

完成!

翻訳前(日本語)


翻訳後(英語)

まとめ

無事ドキュメントが丸ごと翻訳できました:。

ローコードと言いつつも結構LogicAppsの式を多用する結果になってしまいましたが、豊富な関数で柔軟に対応できるのがLogicAppsの強みだと思います。
Microsoft系のサービス(もちろんそれ以外も)とLogicAppsで連携することによって利用者にAPIを意識させることなく、ちょっとしたサービスを作ることができます。

それでは良いローコードライフを!

※掲載内容は個人の見解です。
※会社名、製品名、サービス名等は、各社の登録商標または商標です。

関連記事