#PowerApps と #PowerAutomate で プレビュー公開された #TextAnalytics の テキスト要約(summarize text)を実装してみた

Azure の CogniticeServices の一つ、Text Analytics に先日、テキスト要約機能（Summarize Text）が実装されました。
[How to: summarize text with Text Analytics (preview)](https://docs.microsoft.com/en-us/azure/cognitive-services/text-analytics/how-tos/extractive-summarization)

この機能・・・ビジネスアプリケーションにもめっちゃ使える奴やん！！

っていうことで、こんな感じで早速実装してみることにしました。

* 3行要約の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/30b2f137-518a-c5ca-ca32-6d3f6a56364d.png)

* 7行要約の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/8bfd41b7-4803-9d93-df00-e441a5c687b9.png)


# コネクタには・・・

そりゃありませんよね(笑)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/ecf52403-0b7b-6067-2a5b-579bfb1f8cee.png)

閑話休題

# Text Analytics APIの仕様を調べてみよう！

まぁこのページ、[How to: summarize text with Text Analytics (preview)](https://docs.microsoft.com/en-us/azure/cognitive-services/text-analytics/how-tos/extractive-summarization)を見るのが一番早いんですが・・・

要約をする上で2種類のAPIを送信する必要があるようです。

# Power Automate での作業

というわけで、Power AutomateでAPIの仕様に合わせて実装してみましょう。

## 処理要求API

```
https://<your-custom-subdomain>.cognitiveservices.azure.com/text/analytics/v3.2-preview.1/analyze
```

まずこのURLを使って、要約したい文章と文章の言語の指定、そして何行出力するのかといったことを指定するようです。

ちなみに詳しい仕様はこちらに書いてあります。

[Text Analytics API (v3.2-preview.1)](https://westcentralus.dev.cognitive.microsoft.com/docs/services/TextAnalytics-v3-2-preview-1/operations/Analyze)

なので、HTTPコネクタとしてはこういう設定になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/b24f1bcd-51e0-c1a8-18df-03dd896f278d.png)

で、実行すると、HTTPのヘッダーに、出力結果を問いあわせるURLが出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/4c6d7c4a-bcb1-06b4-2e81-ed423cc554bc.png)

operation-location こいつが要求結果を取得するURLです。

なので、要求結果を取得するHTTPコネクタで使用できるように、ヘッダーをJSON解析をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/28d38990-72f1-bf53-7edc-397eced590fe.png)

JSONのスキーマ情報書いときますねー＼( 'ω')／

```json
{
    "type": "object",
    "properties": {
        "Transfer-Encoding": {
            "type": "string"
        },
        "operation-location": {
            "type": "string"
        },
        "x-envoy-upstream-service-time": {
            "type": "string"
        },
        "apim-request-id": {
            "type": "string"
        },
        "Strict-Transport-Security": {
            "type": "string"
        },
        "x-content-type-options": {
            "type": "string"
        },
        "Date": {
            "type": "string"
        },
        "Content-Length": {
            "type": "string"
        }
    }
}
```

これで処理の要求APIは以上です。

## 処理要求の結果取得までの準備

要求をしてすぐ取得できるわけじゃなく、クラウド側の処理が完了するまで待つ必要があります。
少なくとも1分程度は必ずかかるため、一度遅延処理を1分指定しておきましょう。
また合わせて、出力ができたか判定するためのフラグと要約結果を格納する変数も合わせて作成しておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/32a39dd1-b581-d6e6-cc82-de63a874a4dd.png)


## 処理要求の結果取得

1分ほど待った後に、実際に処理要求の結果を取得しに行きます。

取得するまで繰り返す必要がありますので、Do Until を使い、TextAnalyze が true になるまで繰り返すように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/65dddb2b-1d81-13fd-e4fe-3a63d39f4f08.png)

### 処理要求結果取得のHTTPコネクタ

結果取得のAPI仕様はこちらに書いてあります。
[Text Analytics API (v3.2-preview.1)](https://westcentralus.dev.cognitive.microsoft.com/docs/services/TextAnalytics-v3-2-preview-1/operations/AnalyzeStatus)

API の仕様に合わせて作成したHTTPコネクタはこのようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/0011228c-6a0d-edb0-ca00-b73fde69fa28.png)

URIに指定している、operation-location は、ヘッダーのJSON解析のアクションを使って指定しています。

### 取得結果のJSON解析

取得結果はJSONで返ってきますので、JSON解析で他のアクションでも使用できるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/69441133-1f8a-7d23-2c31-23054ab5d99e.png)

JSONのスキーマ情報書いときますねー＼( 'ω')／

```json
{
    "type": "object",
    "properties": {
        "jobId": {
            "type": "string"
        },
        "lastUpdateDateTime": {
            "type": "string"
        },
        "createdDateTime": {
            "type": "string"
        },
        "expirationDateTime": {
            "type": "string"
        },
        "status": {
            "type": "string"
        },
        "errors": {
            "type": "array"
        },
        "displayName": {
            "type": "string"
        },
        "tasks": {
            "type": "object",
            "properties": {
                "completed": {
                    "type": "integer"
                },
                "failed": {
                    "type": "integer"
                },
                "inProgress": {
                    "type": "integer"
                },
                "total": {
                    "type": "integer"
                },
                "extractiveSummarizationTasks": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "lastUpdateDateTime": {
                                "type": "string"
                            },
                            "taskName": {
                                "type": "string"
                            },
                            "state": {
                                "type": "string"
                            },
                            "results": {
                                "type": "object",
                                "properties": {
                                    "documents": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "sentences": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "text": {
                                                                "type": "string"
                                                            },
                                                            "rankScore": {
                                                                "type": "number"
                                                            },
                                                            "offset": {
                                                                "type": "integer"
                                                            },
                                                            "length": {
                                                                "type": "integer"
                                                            }
                                                        }
                                                    }
                                                },
                                                "warnings": {
                                                    "type": "array"
                                                }
                                            }
                                        }
                                    },
                                    "errors": {
                                        "type": "array"
                                    },
                                    "modelVersion": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```

### 処理結果の判定

処理結果を取得した際に、処理が完了したかどうかは、Statusに記載されています。
なので、条件コネクタを使って、Statusが succeeded かどうかを判定し、処理を分岐します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/c970f89b-cee9-7ebd-ea0d-c08cd13ccbc4.png)


#### まだ実行中（runnning）だった場合

待ち時間を1分設定します。
これで、1分経過した後にループ処理で処理結果の取得が再度行われます。

#### 処理が完了（suceeded）した場合

TextAnalyze を true に設定し、ループを抜けるようにします。

後続で、要約結果を文字列化します。

### 要約結果（配列データ）を文字列化

要約結果は、以下のように行単位で配列化されており、それぞれにテキストとスコアなどが出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/a9035b00-900e-215d-da12-02b214c2705b.png)

Power Apps に返す際はテキスト結果のみを文字列で渡してあげたいので、Apply to Each と 文字列変数に追加のアクションを使って生成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/9dcd480c-fde6-387f-ec32-a9f745ff0f52.png)

値には、JSON解析で取得したTextと以下の式を入れて改行コードを追加しています。

```
decodeUriComponent('%0D%0A')
```

これで、テキストの要約は完了です。
あとは、Power Apps のトリガーと応答を作るだけです。

## Power Apps のトリガー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/76bd831d-7b2c-24d2-ee47-5d5547a28cc4.png)

## Power Apps への応答

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/3626e080-7a43-fd7a-65c1-5d8b9f54aa98.png)

これで Power Apps への連携ができるようになります。

# Power Apps の作成

といっても、Power Apps 側は特に込み入ったことはしていないのでざっくりと書きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/b9fed2c5-3401-1c55-ed5d-9b77183926a5.png)

要約開始のボタンには以下の式を入れています。

```
Set(flowrtn,<フロー名>.Run(TextInput1.Text,Slider1.Value))
```

- 引数１が要約対象のテキストなので、テキスト入力のオブジェクトを指定
- 引数２が要約行数なので、スライダーの値を指定

要約後のテキストが表示されるラベルには以下の式を入れています。

```
flowrtn.summarize
```

これで Power Apps 側は完了です。