PowerAppsとPowerAutomateで撮って翻訳アプリを作成する


#>改版 2020/11/28
[Microsoft MVP Hiroさん](https://qiita.com/h-nagao "Microsoft MVP Hiroさん") より、
PowerAutomate での「選択」時に、ヘッダを出力しない方法をご教示いただきました。
よって、後続のReplace処理は不要となり、さらに処理の簡素化、高速化が実現しました。
ありがとうございます。



#概要

カメラで撮影した文書の文字を読み取り、日本語に翻訳するアプリを作成します。
完成した物はこんな感じ。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">この記事のおかげで「撮って翻訳」が高速化！されちょっとだけ使い物になりました。25秒→7秒<br>AutomateのApply to each撲滅は本当に効きます！ありがとうございます。<a href="https://t.co/VQ24ZSGhOQ">https://t.co/VQ24ZSGhOQ</a>…<a href="https://twitter.com/hashtag/PowerApps?src=hash&amp;ref_src=twsrc%5Etfw">#PowerApps</a> <a href="https://twitter.com/hashtag/PowerAutomate?src=hash&amp;ref_src=twsrc%5Etfw">#PowerAutomate</a> <a href="https://twitter.com/hashtag/JPPUG?src=hash&amp;ref_src=twsrc%5Etfw">#JPPUG</a> <a href="https://t.co/wyNofIkbmm">pic.twitter.com/wyNofIkbmm</a></p>&mdash; Miyake Mito (@MiTo60448639) <a href="https://twitter.com/MiTo60448639/status/1331408739295842304?ref_src=twsrc%5Etfw">November 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



処理の流れ
① PowerApps で撮影し、Azure Blob Storage に画像を保存
② PowerAutomate を呼び出す
③ PowerAutomate で AI Builder を利用し、①の画像の文字を識別する
④ PowerAutomate から Cognitive services の翻訳機能を利用し、③の文字を翻訳する

こんなイメージになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/731e4c93-0818-97cb-d913-7a61813c745e.png)


#はじめに

Azure Blob Storage を利用するために、Azure でストレージアカウントを作成してください。
以下のDocsが参考になると思います。
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-account-create?tabs=azure-portal
※今回はほぼ初期値で作成しました。

Cognitive Services を利用するために、Azure でCognitive Services を作成してください。
https://docs.microsoft.com/ja-jp/azure/cognitive-services/cognitive-services-apis-create-account?tabs=multiservice%2Cwindows
※今回はほぼ初期…


##Blob storage作成

作成したストレージアカウントでの概要で、コンテナーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/aa304ce9-97f3-db6f-9a02-fe88f2096334.png)

画面左上の＋コンテナーを押下し、任意の名前を入力し（今回はuploadimageとしました）、作成ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/34c724ba-be09-a1fe-4634-987b933c44e7.png)


コンテナー作成後、アクセスキーを開き、ストレージアカウント名とKey1のキーを控えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/cebcc379-c6c6-a7b7-bc6d-6fa46df6345b.png)


以上でBlob Storageの作成は完了です。


##Cognitive Services のキーとエンドポイントについて

Cognitive Services を利用するためには、キーとエンドポイントが必要です。
作成した Cognitive Services を開き、キーとエンドポイントで値を取得できます。
こちらも後程利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/99abc9a6-ba22-7860-2516-3ee7fdf0403d.png)



##PowerAppsで、Azure Blob Storage に画像保存

まず、Blob Storageとの接続を作成します。
PowerAppsのホームで、「データ」→「接続」→「新しい接続」→「一から作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ab212fef-4197-533e-ad83-f28eb37e8a8d.png)

Azure ストレージアカウント名とアクセスキーには、上記で作成したストレージアカウントの値を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/03ade91d-c483-51d1-a49f-8c209d5f6f8f.png)

PowerAppsでキャンパスアプリを作成し、画像、ボタン、テキストラベルを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7276c19e-e674-45d6-24f6-122918216eef.png)

撮影した画像をblobストレージへアップロードします。
ボタンの「OnSelect」プロパティに下記を入力します。
OnSelect：

```
//GUIDを取得
UpdateContext({txtguid:Text(GUID())});
//画像ファイルをアップロード
AzureBlobStorage.CreateFile("uploadimage",txtguid,UploadedImage1.Image);
//アップロードしたファイルのURLを取得
UpdateContext({txtURL:First(Search(AzureBlobStorage.ListFolderV2("uploadimage").value,txtguid,"Name")).Path});
```
ファイル名はGUIDでunique値を設定し、ファイルURLを取得しています。


##PowerAutomateで文字識別と翻訳

次に、PowerAutomateの作成を行います。
PowerAppsから呼び出すフローを作成するため、PowerAppsのホームで、「フロー」→「接続」→「新しい接続」→「インスタント 一から作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/5452d795-d844-18dc-3842-2fa32e5b23eb.png)

フロー名を入力し、トリガーをPowerAppsを選択しをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6016ac86-3b06-3f83-8142-0969ca562487.png)

文字列変数を初期化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/884d7b48-4aed-ea96-6efe-8c8a244d411e.png)




次に、「blobコンテンツの取得」を選びます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/35969a88-dd43-4cda-3e22-e0d1e848466b.png)

BLOBコンテンツの指定は、PowerAppsよりURLを受け取りますので、「PowerAppsで確認」を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/134a6625-1353-1c8a-4417-e3fe0dcf4c99.png)

AI Builder の「画像内のテキストを認識する」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/c3757384-129e-df91-de37-6b6feb8b6a70.png)

画像にはBLOBコンテンツより取得したファイルコンテンツを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ec09a3fa-a2ce-7422-31f1-8b46bbc57372.png)

認識されたテキストはJSON形式のため、JSONの解析を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/566019bc-f938-e43a-dc3b-e3fa348462e0.png)

コンテンツには「画像内のテキストを認識する」-「lines」を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a16018c6-0eb9-454e-f559-1b3c392c3557.png)
さらにサンプルから生成で、下記JSONペイロードを入力して完了をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6ee2c40e-6325-b6ca-8cfb-4045c83a22b3.png)

サンプル：

```
{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "@@odata.type": {
                "type": "string"
            },
            "text": {
                "type": "string"
            },
            "boundingBox": {
                "type": "object",
                "properties": {
                    "@@odata.type": {
                        "type": "string"
                    },
                    "left": {
                        "type": "number"
                    },
                    "top": {
                        "type": "number"
                    },
                    "width": {
                        "type": "number"
                    },
                    "height": {
                        "type": "number"
                    },
                    "polygon": {
                        "type": "object",
                        "properties": {
                            "@@odata.type": {
                                "type": "string"
                            },
                            "coordinates@odata.type": {
                                "type": "string"
                            },
                            "coordinates": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "@@odata.type": {
                                            "type": "string"
                                        },
                                        "x": {
                                            "type": "number"
                                        },
                                        "y": {
                                            "type": "number"
                                        }
                                    },
                                    "required": [
                                        "@@odata.type",
                                        "x",
                                        "y"
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "required": [
            "@@odata.type",
            "text",
            "boundingBox"
        ]
    }
}
```

解析したJSONより認識した文字を抽出するため、データ操作の「選択」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f34f57ba-adc6-b35b-11ad-1c0474d9c8ab.png)

開始にはJSONの解析で取得した本文を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/24497b0b-b3b4-c1f5-e8c4-913fd01c94ba.png)
出力のマップとして値の入力にtextを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/fd88f6ec-fa4e-dd73-f430-bb289c944834.png)
さらに、「テキストモードに切り替え」ボタンを押下し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6b41b37c-bd41-f228-c360-2536058a0543.png)
下記、赤枠の部分を削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4974f8f7-7c0e-7a8f-4b42-ff29b341be3f.png)↓
　　　　　　　　　　　　　　　　　↓↓↓↓↓↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7ab3a64c-6243-d6d7-73e2-d3024ec3ccd9.png)
※ textのみに編集したのは「選択」により抽出された文字列に｛｝や、""：が付与されてしまうのを防ぐためです。

データ操作の「選択」は下記のようなデータ構造を出力します。
[
  "Azure's Computer Vision service gives you access to advanced algorithms that process images and return",
  "information based on the visual features you're interested in. For example, Computer Vision can determine",
  "whether an image contains adult content, find specific brands or objects, or find human faces."
]
これらの文字列を繋ぎ、1行に整形したいのですが、Applay to eachでループ処理を作成すると処理時間が遅延します。
データ操作の参加を利用することで、高速化を図ります。

データ操作の「参加」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1784a917-39aa-3f17-46d1-f82444eff035.png)

結合する配列には、上記「選択」の出力を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/cddc3bd3-462c-1c1f-29c5-710e1f180007.png)
結合文字は" "（SPACE）を指定します。

こういったApplay to eachによるループ制御を使用することなくフローを構築する手順は下記をご参照ください。
https://mofumofupower.hatenablog.com/entry/2020/08/12/093000

「参加」（結合）の出力を変数に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/3a7f10fe-dcf7-e814-cae1-836e9afed37a.png)

「Microsoft Translate」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1b66095d-66a7-600a-33b1-e11bc490abd6.png)

接続名を聞かれますので、上記のCognitive Services のキーとエンドポイントをセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/b2b2acaa-03ef-2fed-22b7-33691a3eb10d.png)

Target Language に日本語、TEXTに上記replaceの出力を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/74148efc-44bb-284a-d9db-28b50d1d5bc9.png)


最後に、翻訳した文字列をPowerAppsに返却するため、「PowerappsまたはFlowに応答する」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/b6e09c21-d9a8-0ec8-9a29-51d8d7412347.png)

「テキスト」を選択し、PowerApps側の戻り値名を設定します。（今回はreturnという名前にしました）
値にはTranslatde Textを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/61c02333-2e17-fcda-45cf-658514ba48f7.png)


##PowerAppsでフローを呼び出し

上記で作成したPowerAppアプリに戻りアクション－Power Automateで開いたペインで、作成したフローを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/0fb7655c-dc21-b3b6-a8e0-b3c75d73785e.png)

すると、選択中のオブジェクトの任意のプロパティにフロー名が表示されるので、これを切り取ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7c2b0fa1-29f7-6463-06a5-0db88028e46d.png)

ボタンの「OnSelect」プロパティのblobストレージへの画像アップ処理に続き、下記処理を追記します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6036c847-0487-e7eb-e2cb-8ac1d2aa308a.png)

OnSelect：
```
UpdateContext({txtReturn:文字を認識し翻訳する.Run(txtURL)});
AzureBlobStorage.DeleteFile(Last( AzureBlobStorage.ListFolderV2("uploadimage").value).Id)
```
※blobストレージにアップロードした画像ファイルを削除します。

最後にテキストラベルのTextプロパティに、フローの戻り値を設定して完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/79ea6f4b-235b-b346-d2f3-0a45cd8b8240.png)



#まとめ

出来上がったものはGoogle翻訳アプリの足元にも及ばない自己満足アプリです。
ですが、PowerAppsからAzureのストレージアクセスやCognitive servicesによるAIが活用できることで、色々なことが実現できそうです。