Power Automate Desktop「メロンとメロンパンの違いを完全に理解した話」

## 概要

Power Automate Desktop（以下PAD）からMicrosoft Lobeを利用した機械学習による画像分類をおこないます。
Lobe単体でも簡単に画像分類を体験できますが、PADと連携することで実用できそうな何かになるかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/875d1acb-1abf-abb1-fef0-61725ec2c9cc.png)
## 今回やること

数10枚のメロンとメロンパンの画像を分類するアプリ的な何かを作ります。

* 簡単なLobeモデル作成
* 機能拡張を使ってモデルを強化
* LobeのRestAPIにPADから画像をPOSTし、結果をhtmlテーブルで生成、出力

  ![05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/aee77826-cefa-9b42-e318-e1056205bfc8.jpeg)

## Lobeについて

https://lobe.ai/

* Lobeはプログラミングすることなく画像分類モデルを作ることができます。
* 現在ベータ版ですが無料で利用可能です。
* 作成したモデルは書き出してさまざまなアプリケーションから利用可能です。
* LobeアプリケーションにREST APIが備わっているためPAD等他のアプリから直接利用できます。
* ローカル環境（自分のPC）のAPIなので回数制限等を気にすることなく学習できます。

## Power Automate Desktopについて

https://flow.microsoft.com/ja-jp/desktop/

インストール手順や出来ることについては@Maekawa さんと@K2_kzy さんの記事が参考になります。
最新版の情報については@YutoKa　さんの記事を参考にしていただければとおもいます。
他力本願です。

## 注意事項

* 個人の学習を目的としています。
* 画像は加工しているので見ずらいかもしれません。
* Microsoft Lobe、Power Automate Desktop、Microsoft Edgeを使用します。
* 無償利用可能ですがWindows 10とユーザー登録が必要です
* 公式サイトからダウンロードおよびインストールしてください。
* https://lobe.ai/
* https://flow.microsoft.com/ja-jp/desktop/
* https://www.microsoft.com/ja-jp/edge
* 2021年4月の情報です。
* 自己責任でお願いいたします。
* 複数行が使えない部分は、特殊な方法を使っています。過去記事を参照ください。
* [フォーラム](https://powerusers.microsoft.com/t5/Power-Automate-Ideas/Power-Automate-Desktop-Make-quot-Write-text-to-file-action-quot/idi-p/874710)に複数行が使えるように要望しましたが反応がいまいちです😥Voteお願いします。

## Lobeモデルの作成

2つのフォルダーを用意して各5枚づつ画像を入れておきます。フォルダー名には分類する（ラベリングしたい）名前をつけておきます。
![06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/8c4e85ab-94f6-df41-eeb3-8320f903dec8.jpeg)

Lobeを起動しNew Projectを作成します。

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/76a60681-de60-fe98-3653-9b5c6b990a1b.png)

import>Datasetを選択します。
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/3e133bdb-f514-adbd-8363-c69247bd0b64.png)

Choose Datasetで進みます。　
![54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/cea1f4e5-1b94-1c9a-fa62-d9089882839c.png)

画像フォルダーを選択します。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/28a1fbc3-c159-92fc-d2f2-6dd60bc96e16.png)

Label Using Folder Nameを選択してImportします。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/25bcbe58-1922-1383-41f3-95e500a15c4d.png)

画像が読み込まれたら、同じ作業を繰り返し、もうひとつのファルダーもインポートします。
![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/590bc700-758c-c7ae-6453-19a1f1d1791a.jpeg)

自動で機械学習が行われこのような状態になったらモデルの完成です。

## とりあえず試してみる
Useに移行し画像をウインドウにドラッグドロップしてみます。
https://www.pakutaso.com/20110751192post-365.html　の画像を使わせていただきました。

![56-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/fbf42fb4-002c-6cd5-5d14-ae3908ef247c.png)

いまのところ理解できてなさそうです。

![09-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/94a1effd-a975-9bd0-d26d-d59de9f0863c.png)


## 拡張機能を使ってモデルを強化する

画像を追加していくとモデルを強化できます。ブラウザ拡張機能をつかうことで効率よくモデルを強化できます。
開発者モード拡張機能のため問題が起こる可能性もあります。
参考　[誰でもノーコードで画像判別の機械学習モデルを作成できる「Lobe」](https://internet.watch.impress.co.jp/docs/column/shimizu/1316830.html)

### Microsoft Edgeへのインストール

https://github.com/lemillermicrosoft/lobe-chrome-extension
からLobeBrowserExtension.zipに移動してDownloadします。

ダウンロードしたらファイルをデスクトップ等わかりやすいところに解凍します。
![](181645.jpg)![181645.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/ae717a06-6692-c933-3c64-d35c4373bfb4.jpeg)

Microsoft Edgeの拡張機能画面を開きます。

![](181330.jpg)![181330.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/36be1cfd-36ca-59f3-597c-99beb94ca55f.jpeg)

開発者モードをONにして展開して読み込みを行います。
![53-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/08bd0224-a730-a1ea-c794-4799a68f3549.png)

先ほど解凍したファイルを選択します。
![aa.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c104cf4d-f288-fe7a-9e3b-def35f798172.png)

インストールがうまくいくとアイコンが表示されます。
)![57-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/31fdd83e-77fd-85d2-b04a-c1db3b54cb20.png)

Edgeを立ち上げ直すとこのようなダイアログが出ますが×で閉じます。
![02-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/3b1240df-c555-3171-7924-4fe222e8ea36.png)

先ほどつくったLobeのモデルは立ち上げたままにしておきます。
メロンをBingって、検索結果の画像を表示し拡張機能のアイコンを押します。
![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/7e5e91ba-5101-2fef-7c31-74b760490bd1.jpeg)

ウインドウが開いたらメロンの画像なのにメロンパンと表示されていたりゲージが低いものを中心に学習させます。誤解答の場合はラベルをクリックして正しい解答を選択します。
![04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/143f43ca-9b66-54aa-baf2-c528144a6235.jpeg)

メロンパンの画像も同様におこないます。
今回は各10枚づつ追加で学習させました。
Trainが完了したらノーコードでモデル作成終了です。
長くなりましたが実際は5分くらいでできます。
ここからが本番です。

## PADからLobeのモデルを使うフローを作る

今回のフローを作るにあたって、理解に役立つポイントが2つあります。

* **REST API**
* **Base64**

#### REST APIについて

『ウィキペディア（Wikipedia）』からかいつまんで引用します。
https://ja.wikipedia.org/wiki/Representational_State_Transfer

>Representational State Transfer (REST) は、ウェブAPI[（英語版）](https://en.wikipedia.org/wiki/Web_API)の定義に使用されるアーキテクチャスタイル

>ステートレスなクライアント/サーバプロトコル
HTTPメッセージの一つ一つが、そのリクエスト（メッセージ）を理解するために必要な全ての情報を含む。

>HTTP では操作（メソッド）の小さなセットが定義されている。最も重要なのは "GET"、"POST"、"PUT"、"DELETE" である。

ざっくりとですが、このAPI（Application Programming Interface）が用意されていればHTTPメッセージを通して情報をやり取りできるということです。

そしてLobeのモデルにはローカール環境でありながらREST APIが用意されています。つまり、PADの「Webサービスを呼び出します」アクションを用いて扱えるということです。

#### Base64について

[ウィキペディア（Wikipedia）](https://ja.wikipedia.org/wiki/Base64)からの引用します。

>Base64は、データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式である。MIMEによって規定されていて、7ビットのデータしか扱うことの出来ない電子メールにて広く利用されている。具体的には、A–Z, a–z, 0–9 までの62文字と、記号2つ (+, /)、さらにパディング（余った部分を詰める）のための記号として = が用いられる。この変換によって、データ量は4/3（約133%）になる。

REST APIと情報のやり取りをする場合、画像データはBase64文字列で表す必要があります。Lobeについても同様に画像をBase64形式にエンコードする必要があります。今回のフローではPowerShellを用いて変換します。Base64形式の画像データはURI情報を付加することで、ブラウザやPower BIで画像として表示できます。

### フロー

あらかじめループ処理の必要ない部分をhtmlに書き込んでおき、行データはループでリストに貯め、最後にまとめてhtmlに追記します。

![07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/7cdf8ed2-8bbd-4ebf-df16-e8a4fbabfd73.jpeg)


ポイントである9~14番目のアクションを細かく見ていきます。
**※フローを実行する場合は必ず作成したLobeモデルを開いておく必要があります。**

9.「PowerSellスクリプトの実行」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/b26d5aa6-5e75-77be-6f16-0b9bf1b35281.png)




変数\$outに%files%リストからファイルパス%CurrentItem%を設定してBase64文字列に変換します。Echo $outでPADの変数％PowershellOutput％に出力しています。大きいサイズの画像の変換は時間が掛かります。

10.項目をリストに追加

変数％PowershellOutput％にタグとDataURIを追記して%Listに追加します。Base64データにData URIを追記するとブラウザで画像を表示できます。今回はhtml内に画像データも直接格納します。なので大きい画像を判定につかったり、大量の画像を判定するとhtmlファイルも大きくなります。Data URI shemeについては[Wikiペディア](https://ja.wikipedia.org/wiki/Data_URI_scheme)を参照ください。
![2021-04-17-22-48-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/ced816c8-2915-e21d-9c1f-af19836207ae.png)
11. 「テキストのトリミング」

Base64形式に変換された画像データ変数％PowershellOutput％はなぜか行末に改行コードが入ってしまいます。
![32-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2790b5a7-698f-14c8-59ad-d92e6e546a37.png)

改行コードが残っているとPOST時エラーになるので、このアクションで取り除きます。トリミングしたデータを%base64%という変数名にしています。
![12-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/836f297c-6c3d-f6c3-5a62-54b226f9de6b.png)


12.「Webサービスを呼び出します」

LobeのREST APIにデータを投げて判定結果を返却してもらいます。
先ずはLobeのAPIを仕様を見てみます。
次の手順で仕様を見ることができます。

![8-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4daee95a-dd05-0924-03eb-44c81acda568.png)

フォーマットはJSONを使います。
![za](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/756e5dbd-2395-e025-cf45-2b2f5c4b6d6e.png)


仕様を見ていきましょう。

##### 接続先URLとリクエスト

接続先URLはモデルによってpredict/以下のIDは変わります。

``` URL http://localhost:38101/v1/predict/xxxx-xxxx-xxxx-xxxx-xxxx ```

リクエストをみると、
メソッドはPOST
Content-Type　application/json
要求本文（body）image": "base64画像データ"
となっています。

``` json:JSON
{
  "method": "POST",
  "headers": {
    "Content-Type": "application/json"
  },
  "body": {
    "image": "<base64 image>"
  }
}
```
これをもとに、PADアクションをつくります。

![50-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/df8c672a-a158-ac96-514b-fc983b9ac9f3.png)

必ず詳細を展開して「要求本文をエンコードします」の**チェックを外します。**

13.JSONをカスタムオブジェクトに変換

正常に実行できると返却されるデータは次のようなJSON形式なります。JSONはただの文字列なのでPADで読めるようにでカスタムオブジェクトに変換します。

``` json:JSON
{
    "predictions": [
        {
            "label": "メロン",
            "confidence": 0.9999855756759644
        },
        {
            "label": "メロンパン",
            "confidence": 0.000014392863704415504
        }
    ]
}

```


14. 変数の設定

Confidence「信頼性」の高いラベルが上位に来るようにできています。Confidenceの最大値は1です。
そこで
![41-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/e37c74bd-3119-2885-8c8e-2c3ba98db38b.png)


として1番目のラベルをカスタムオブジェクトから取得して変数名%Pred%としています。

#### その他

htmlについてはUTF-8 BOMなしにしています。
フローを実行すると選択したフォルダー内にhtmlが生成されます。
![](07-27.png)![2021-04-17-23-07-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/a57dc415-847a-54f1-c5a4-9cf428cb193c.png)
ブラウザで閲覧可能です。

## コード

LobeモデルのIDについてはYour-Modelの部分を適宜書き換えてください。

```R:PowerAutomateDesktop

Folder.GetSpecialFolder SpecialFolder: Folder.SpecialFolder.DesktopDirectory SpecialFolderPath=> SpecialFolderPath
Display.SelectFolder Description: $'''画像フォルダーを選択してください。''' InitialDirectory: SpecialFolderPath IsTopMost: False SelectedFolder=> SelectedFolder ButtonPressed=> ButtonPressed3
Folder.GetFiles Folder: SelectedFolder FileFilter: $'''*.jpg''' IncludeSubfolders: False FailOnAccessDenied: True SortBy1: Folder.SortBy.NoSort SortDescending1: False SortBy2: Folder.SortBy.NoSort SortDescending2: False SortBy3: Folder.SortBy.NoSort SortDescending3: False Files=> Files
SET htmltext TO $'''<!DOCTYPE html>
<html lang=\"ja\">

<head>
  <meta charset=\"UTF-8\">
  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
  <title>メロンとメロンパンの違いを完全に理解した</title>
  <style>img {max-width: 100%%;width: 300px;height: auto;}</style>
</head>

<body>
  <table border=\"1\">
    <th>URI</th>
    <th>Pred</th>
    <th>FileName</th>

'''
File.WriteText File: $'''%SelectedFolder%\\pred.html''' TextToWrite: htmltext AppendNewLine: True IfFileExists: File.IfFileExists.Overwrite Encoding: File.FileEncoding.UTF8NoBOM
Variables.CreateNewList List=> List
LOOP FOREACH CurrentItem IN Files
    Variables.AddItemToList Item: $'''<tr>''' List: List NewList=> List
    System.RunPowershellScript Script: $'''$out=[Convert]::ToBase64String([IO.File]::ReadAllBytes(\"%CurrentItem%\"))
echo $out''' ScriptOutput=> PowershellOutput ScriptError=> ScriptError
    Variables.AddItemToList Item: $'''<td><img src=\"data:image/jpeg;base64,%PowershellOutput%\" /></td>''' List: List NewList=> List
    Text.Trim Text: PowershellOutput TrimOption: Text.TrimOption.ToEnd TrimmedText=> base64
    Web.InvokeWebService Url: $'''http://localhost:38101/v1/predict/Your-Model''' Method: Web.Method.Post Accept: $'''application/json''' ContentType: $'''application/json''' RequestBody: $'''{\"image\": \"%base64%\"}''' ConnectionTimeout: 30 FollowRedirection: True ClearCookies: False FailOnErrorStatus: False EncodeRequestBody: False UserAgent: $'''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20100312 Firefox/3.6''' Encoding: Web.Encoding.AutoDetect AcceptUntrustedCertificates: False ResponseHeaders=> WebServiceResponseHeaders Response=> WebServiceResponse StatusCode=> StatusCode
    Variables.ConvertJsonToCustomObject Json: WebServiceResponse CustomObject=> JsonAsCustomObject
    SET Pred TO JsonAsCustomObject['predictions'][0]['label']
    Variables.AddItemToList Item: $'''<td>%Pred%</td>''' List: List NewList=> List
    Variables.AddItemToList Item: $'''<td>%CurrentItem.Name%</td>''' List: List NewList=> List
    Variables.AddItemToList Item: $'''</tr>''' List: List NewList=> List
END
Variables.AddItemToList Item: $'''</table></body></html>''' List: List NewList=> List
File.WriteText File: $'''%SelectedFolder%\\pred.html''' TextToWrite: List AppendNewLine: True IfFileExists: File.IfFileExists.Append Encoding: File.FileEncoding.UTF8NoBOM

```

## まとめ

* Microsoft Lobe,Power AutoDesktop,PowerShell,Edgeを連携させました。
* Lobeおもしろいので1回は使ってみてほしいです。
* 完全に理解したと思ったら沼にはまり込むアレです。
* ノーコードでモデルが作成できますが、TensorFlowのモデルで書き出したりと奥が深いです。
* タイトルでは完全に理解した話となっていますが、完全に理解しようとした話に読み替えてください。
* 20個の画像を試したら2個間違ってました　(;'∀')
* REST APIがローカル環境で回数制限もなく使えるので機械学習やJSON、APIをはじめて触る人には最適かとおもいます。
* 今回はお遊びですが、PADとLobeの連携で実際に使えるフローができそうに感じました。

## 外部リンク、参考

* https://lobe.ai/
* https://flow.microsoft.com/ja-jp/desktop/
* https://www.microsoft.com/ja-jp/edge
* https://www.pakutaso.com/20110751192post-365.html
* [誰でもノーコードで画像判別の機械学習モデルを作成できる「Lobe」](https://internet.watch.impress.co.jp/docs/column/shimizu/1316830.html)
* https://github.com/lemillermicrosoft/lobe-chrome-extension
* https://ja.wikipedia.org/wiki/Representational_State_Transfer
* https://ja.wikipedia.org/wiki/Base64
* https://ja.wikipedia.org/wiki/Data_URI_scheme
* https://qiita.com/maekawawawa
* https://qiita.com/K2_kzy
* https://qiita.com/YutoKa