Power Automate for desktop 「データ制約に合わせた入力の自動化」

## 概要

　Power Automate for desktopだけでは難しかったデータ制約に合わせた入力の自動化に、Azure OpenAI Serviceを活用する方法です。

古めの基幹システムに入力の自動化を試みる際、文字の種類や数の制限が厳しいことがあります。特に課題となっていたのが「摘要欄」や「通信欄」の文字数制限です。この解決にAzure OpenAI ServiceのGPTモデルを利用して要約をおこないPower Automate for desktopと組み合わせます。

![CleanShot 2023-09-18 at 04.13.28.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/5eafc391-879e-1ced-1a43-ebd19019cc8a.gif)

## 前提条件

- Windows 11 Pro 22H2
- Power Automate for desktop 2.35.159.23221
- Azure OpenAI  Model gpt-35-turbo 0613

## 注意事項

- 2023年9月18日時点の情報です。
- Azure OpenAI Serviceを利用できるAzure環境が必要です。
- 環境準備については触れません。参考Learn[「Azure OpenAI Service リソースを作成してデプロイする」](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/create-resource?pivots=web-portal)
- Azure OpenAI Serviceは従量課金です。今回の検証程度であれば数十円程度でした。
- この分野は進歩が早いため注意が必要です。
- 注意していますが個人的見解を多く含みます。
- 1次情報ではありませんので自己責任でお願いします。

## Azure OpenAI Serviceについて

https://www.microsoft.com/ja-jp/ai/responsible-ai?rtc=1&activetab=pivot1:primaryr6

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/overview#comparing-azure-openai-and-openai

>Azure OpenAI では、プライベート ネットワーク、リージョンの可用性、責任ある AI コンテンツのフィルター処理が提供されます。

個人的な感想です。

- REST APIが用意されていて、データーをモデルの再学習に使わない観点から、アプリに組み込んで業務利用する場合に向いていると思います。
- Azure OpenAI Studio の Web ベースのインターフェイスからプロンプト調整がしやすいです。

![スクリーンショット 2023-09-12 215801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/8558b44a-da85-c4ad-2391-1452b0695c9c.png)

## フロー概要

### 今回の条件

- 受注データの通信欄を想定した文章データを全角12文字に要約します。
- 今回の入出力はExcel to Excelで試行します。
- 要約時12文字より多くなった場合、再帰させずに人が確認修正します。

### フロー概略

条件を考慮したフロー概略です。

```mermaid
graph TB
A["入力データ"]-->B("12文字以上？")--Yes-->C("AOAIで12文字以内に要約、全角化")-->D("12文字以上？")--Yes-->E("カスタムフォーム確認、修正")-->F("入力")
B--NO-->G("全角化")-->F
D--NO-->F
```

今回のフローではうまく要約できるかが鍵になっています。そこでAzure OpenAIを想定の動作に近づけるための調整作業をします。

## System messageとExamplesを使った調整

モデルはgpt-35-turbo 0613を利用しています。Azure OpenAI StudioにあるChat playgroundに移動します。

UIは「Assistant setup」「Chat session」「Configuration」の3つに分かれています。今回は「Chat session」で試しながら、「Assistant setup」のSystem messageとExamplesを使い調整します。

![スクリーンショット 2023-09-12 215801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/75ae35fd-ec4d-680d-5414-8fb2b0c73abe.png)

はじめに「Assistant setup」を使わず試しました。
![スクリーンショット 2023-09-12 220409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4149407f-7c9a-50d4-4046-baa6e8100615.png)
前提条件のない状態ですが、例文ではそこそこの良い要約です。

今度はSystem messageに前提となる条件を与えてみます。

![スクリーンショット 2023-09-12 220751.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/284bcfac-7cc1-c7f5-8c35-a05ca2addf4a.png)

「。」が残っていますが、ほどほどに要約されています。

しかし少し複雑な文章になると12文字の制約は無視されました。
![CleanShot 2023-09-14 at 00.46.14@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/eb07e6a3-f5b8-d269-84c6-b5b922cd7723.png)

そこで「Examples」にいくつか回答例を与えました。

![スクリーンショット 2023-09-12 223524.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/91285e1d-a25e-aaba-78ab-7a15db4fad31.png)

System messageとExampleをいろいろ変化させ試行錯誤します。
![スクリーンショット 2023-09-12 230400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/3805b1b3-ef88-b3a3-db36-3db60aa3963f.png)

![スクリーンショット 2023-09-12 231805.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/987cbedc-68c3-1623-78fa-a0ceb03be2af.png)

最終的にSystem messageとExampleは次のJSONのように設定しました。
JSONは「Chat session」のShow raw JSONのトグルスイッチをONすることで表示できます。

![CleanShot 2023-09-14 at 12.33.52@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/57becbd8-5a2b-61d7-bbed-297866bfccce.png)
ただし結果は完全ではないので12文字の制限を超えたときは人が確認修正するようにフロー側で行うようにします。

```json
[
    {
      "role": "system",
      "content": "あなたは日本語の先生です。あなたはユーザからの文章を12文字以内に要約してください。送り仮名を使わないで表現にしてください。また文字は全角に変換してください。スペースや句点および読点を削除して1文にしてください。必ず12文字以内になっているか確認します。12文字を超えた場合、再度、適切に文字削除を行ってください。"
    },
    {
      "role": "user",
      "content": "午前中"
    },
    {
      "role": "assistant",
      "content": "Ａ"
    },
    {
      "role": "user",
      "content": "プレゼント"
    },
    {
      "role": "assistant",
      "content": "プレ"
    },
    {
      "role": "user",
      "content": "9月15日午後の配達でお願いします。プレゼント包装希望です。"
    },
    {
      "role": "assistant",
      "content": "９／１５Ｐプレ包装"
    },
    {
      "role": "user",
      "content": "過剰包装はやめてください。"
    },
    {
      "role": "assistant",
      "content": "過剰包装不要"
    },
    {
      "role": "user",
      "content": "午後"
    },
    {
      "role": "assistant",
      "content": "Ｐ"
    },
    {
      "role": "user",
      "content": "10月20日午前"
    },
    {
      "role": "assistant",
      "content": "１０／２０Ａ"
    },
    {
      "role": "user",
      "content": "リボンをつけた"
    },
    {
      "role": "assistant",
      "content": "リボン付"
    },
    {
      "role": "user",
      "content": "ラッピング"
    },
    {
      "role": "assistant",
      "content": "包装"
    },
    {
      "role": "user",
      "content": "ギフトボックス"
    },
    {
      "role": "assistant",
      "content": "贈箱"
    }
]
```

## Power Automate for desktopに実装する

- サンプル文章はExcelファイルで用意しました。
  ![CleanShot 2023-09-18 at 14.41.06@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/66681b53-92d0-a587-e69f-a327be925c97.png)
- 概略図の中で主要になる3つの動作について解説します。
![CleanShot 2023-09-18 at 00.20.43@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/f5809cf6-2bad-6f6e-d7e3-a38d1d1c93c6.png)

![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c3dd6ef0-8cbc-2bc1-0868-c92bccea9d60.png)

### 1.「Web サービスを呼び出します」アクションを使いAzure OpenAI Serviceで要約します

Azure OpenAI StudioのChat sessionのView codeに進みます。
![CleanShot 2023-09-18 at 00.41.27@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/7d0177a6-e4df-ff6d-4548-b4a1ee511efc.png)

コードをJSONに切り替えます。ここにある情報を参考に「Web サービスを呼び出します」アクションの各項目を埋めて行きます。

![CleanShot 2023-09-17 at 11.10.39@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/55a159a9-1e78-3bdf-e0c3-9ce9463bbd57.png)

![CleanShot 2023-09-18 at 00.45.50@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/d8cdf2b6-5c40-2e61-dbc6-83d241d6aa0e.png)

 - URL 「Sample Code」に表示されたEndpointを使用します。
  `https://サブドメイン名.openai.azure.com/openai/deployments/モデル名/chat/completions?api-version=2023-03-15-preview`
 - メソッド　`POST`を選択します。
 - コンテンツタイプ　`application/json`にします。
 - カスタムヘッダー `api-key:%APIKey%`　api-keyは「Sample Code」に表示されたKeyを直接書くこともできますが、ここでは変数にしています。
 - 要求本文　「Sample Code」に表示された基本形を加工します。
  
  ```json
    {
      "messages": [],
      "temperature": 0.7,
      "top_p": 0.95,
      "frequency_penalty": 0,
      "presence_penalty": 0,
      "max_tokens": 800,
      "stop": null
    }
  ```

  messagesの`[ ]`配列とShow raw JSONから取得したSystem messageとExamplesを置き換えます。その配列の最後に次のJSONをつけ足します。

  ```json
    {
      "role": "user",
      "content": "%UserMessage%"
    },
    {
      "role": "assistant",
      "content": ""
    }
  ```

  userの`%UserMessage%`は要約したい文章の変数です。assistantの`""`は要約された答えが返却される部分です。

  ```json
  {
  "messages": [
    {
      "role": "system",
      "content": "あなたは日本語の先生です。あなたはユーザからの文章を12文字以内に要約してください。送り仮名を使わないで表現にしてください。また文字は全角に変換してください。スペースや句点および読点を削除して1文にしてください。必ず12文字以内になっているか確認します。12文字を超えた場合、再度、適切に文字削除を行ってください。"
    },
    {
      "role": "user",
      "content": "午前中"
    },
    {
      "role": "assistant",
      "content": "Ａ"
    },
    {
      "role": "user",
      "content": "プレゼント"
    },
    {
      "role": "assistant",
      "content": "プレ"
    },
    {
      "role": "user",
      "content": "9月15日午後の配達でお願いします。プレゼント包装希望です。"
    },
    {
      "role": "assistant",
      "content": "９／１５Ｐプレ包装"
    },
    {
      "role": "user",
      "content": "過剰包装はやめてください。"
    },
    {
      "role": "assistant",
      "content": "過剰包装不要"
    },
    {
      "role": "user",
      "content": "午後"
    },
    {
      "role": "assistant",
      "content": "Ｐ"
    },
    {
      "role": "user",
      "content": "10月20日午前"
    },
    {
      "role": "assistant",
      "content": "１０／２０Ａ"
    },
    {
      "role": "user",
      "content": "リボンをつけた"
    },
    {
      "role": "assistant",
      "content": "リボン付"
    },
    {
      "role": "user",
      "content": "ラッピング"
    },
    {
      "role": "assistant",
      "content": "包装"
    },
    {
      "role": "user",
      "content": "ギフトボックス"
    },
    {
      "role": "assistant",
      "content": "贈箱"
    },
    {
      "role": "user",
      "content": "%UsertMessage%"
    },
    {
      "role": "assistant",
      "content": ""
    }
  ],
  "temperature": 0.7,
  "top_p": 0.95,
  "frequency_penalty": 0,
  "presence_penalty": 0,
  "max_tokens": 800,
  "stop": null
}
  ```

- 要求本文をエンコードしますのトグルスイッチを**オフ**にします。忘れるとエラーになります。
- 「Web サービスを呼び出します」アクションから戻ってきたJSONをカスタムオブジェクトに変換します。
  ![CleanShot 2023-09-18 at 01.27.01@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/1f62b7ef-0e80-6384-850f-15ea6df785e4.png)
- assistantの回答はカスタムオブジェクト`%JsonAsCustomObject['choices'][0]['message']['content']%`に格納されています。
  
### 2.「カスタムフォームを表示」アクションを使い要約が12文字を超えた場合、修正を要求する

Azure OpenAI Serviceから戻ってくる要約はそこそこ良い感じなのですが、答えに微妙な揺れがあります。
![CleanShot 2023-09-18 at 01.44.13@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/dc6a1736-c8cd-ec53-db5c-f6d583158da1.png)
![CleanShot 2023-09-18 at 01.43.34@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/1a796d59-edaf-5af3-7020-972c08c73f5c.png)
![CleanShot 2023-09-18 at 01.42.11@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/333e5898-4a5d-b196-8513-e8a980c8ae99.png)

たまに12文字を超えてしまう場合もあります。今回は「カスタムフォームを表示」アクションを用いてその場合は人が修正としました。

![CleanShot 2023-09-18 at 01.55.42@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4455f614-a131-cba9-a38a-0380158b00c7.png)

![CleanShot 2023-09-18 at 01.59.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/41f0ca46-afe2-be93-85e9-bec06ddb3d79.png)

「カスタムフォームを表示」アクションから出力される変数はカスタムオブジェクトです。修正した要約文として`%CustomFormData['Text input']%`を取得します。

### 3.「PowerShellスクリプトの実行」アクション

そもそも12文字以下で要約が必要ない場合、全角変換だけ行いました。

![CleanShot 2023-09-18 at 02.12.39@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/8446f459-a6a4-11cf-7b0d-3f3777d7b989.png)

```PowerShell
Add-Type -AssemblyName "Microsoft.VisualBasic"
[Microsoft.VisualBasic.Strings]::StrConv("%CommunicationField%", [Microsoft.VisualBasic.VbStrConv]::Wide)
```

`%PowershellOutput%`は空白文字が残るので削除しています。
![CleanShot 2023-09-18 at 02.16.46@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/10af0eb4-9d30-b8d3-6339-ad8bfc467baf.png)

## まとめ

今回Excel to Excelで行いましたが、基幹システムにAPIがなくターミナルエミュレーターを操作するような入力自動化を行うときはPower Automate for desktopとAzure OpenAI Serviceを組み合わせてデータの制約を解決できそうです。しかし次のような課題があるのも事実です。

- 完璧ではないので許容できる範囲を決めるのと、人を必要とする部分が残ります。要件によっては全てを任せてしまうのは今の段階では厳しそうです。
- Examplesを増やせば結果は良くなるかもしれまんがトークンを多く消費します。そのあたりはトレードオフです。
- かなり多くのコメントに対応できそうですが、扱うデータの性質（例えば受注、入金データ、通販など）によって傾向が異なるため、Examplesはデータに合わせて調整した方がよさそうです。
- 文章中で何が重要か単語の重みづけが難しいとき、文字数制限を破ってくる傾向です。
- 文字数制限を満たすまで再帰フローも試みましたが、意味の変化が散見さられた為、今回のフローでは採用しませんでした。
- 今回使ったモデルはChatGPT 3.5 turboですので4.0に期待です。

　反省点として、例文が悪かったと感じています。しっかりした通販サイトであれば日時指定や包装紙など間違えが許容できないデータは入力フォームで選択式にデザインすると思います。あくまで自動化のプラクティスということで・・。

　本当はPower Automate for desktopの「Azure OpenAI Service の GPT でテキストを作成する（プレビュー）」アクションを使いたかったのですが2023年9月18日現在[Learn](https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/actions-reference/aibuilder)に
>この機能は、限定的なプレビューです。 試用版に参加するために申請してください。 申請するには、限定プレビュー リクエストにアクセスしてください。

とあります。しかしリクエスト先のフォームは終了しているため、今回はAzure OpenAI Serviceを利用しました。
従量課金といっても、今回の検証程度では少額なので怖がらずどんどん試してみるのが良いと思いました。
![CleanShot 2023-09-18 at 02.32.54@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/3090df70-078f-7242-7393-35cf09d05d62.png)

## 参考

- [Azure OpenAI Service リソースを作成してデプロイする](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/create-resource?pivots=web-portal)
- [Azure OpenAI Service の REST API リファレンス](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference)
- [Data, privacy, and security for Azure OpenAI Service](https://learn.microsoft.com/ja-jp/legal/cognitive-services/openai/data-privacy?context=%2Fazure%2Fai-services%2Fopenai%2Fcontext%2Fcontext)
- [祝 Azure OpenAI Service GA! ⑤幼稚園生の疑問に答えてくれる "しま〇ろう BOT" を ChatGPT で作ってみる](https://qiita.com/annie/items/b816119dde120b09bbca)　　[Cogbot](https://cogbot.connpass.com/)でお世話になった記事です。