Azure OpenAI と Power Platform の連携：簡単な書籍の要約メモ機能を Power Apps のアプリに実装してみた

## 序
昨今、AI活用について（良くも悪くも）耳にする機会が増えてまいりました。

企業側のご要望に沿えるように準備をしておかなければ…と思いながらも、正直なところ Microsoft 365 や Power Platform のアップデートを追いかけたり、引き出しを増やしたりすることに精一杯で、今の今まで放置状態でした（人間の認知能力との対比やテクノロジーとしては興味があるものの、その活用についてはあまり関心がありません）

とりあえず AI と Power Platform の連携の要点さえ抑えておけば、将来、誰かのお仕事を楽にすることができるようになるだろう…と、興味というよりは危機感と慈善意識で AI を活用したアプリ開発を試みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/48229a9d-f386-5d78-3c8c-24918ac17d74.png)

アプリ開発といっても、Power Platform と連携できるようになっておく…という点にだけ関心があったため、ゼロからアプリを作るのは手間に感じていました。今回は、レスポンシブ・デザインの学習のために個人的に作成していた「蔵書管理アプリ」の機能を拡張することで AI の実装を試みました。

![新規キャンバス.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/e776c811-d845-ce43-9318-88cfdac675ff.jpeg)

実装した機能は、書籍の要約と所感をメモ程度に記してくれるものです。今回の記事は、個人的にハマってしまった／ハマるだろうなあと思われるポイントを押さえながら実装手順をご紹介します。

### Azure OpenAI と ChatGPT の違い
Power Automate と Power Automate for desktop が異なるツールであるのと同様に、Azure OpenAI と ChatGPT が異なるツールであることをまず理解する必要があります。

どちらも OpenAI の技術を利用した製品ですが、それぞれの提供形態や向き不向きが異なっており、連携に必要なものが異なっています。この記事は Azure OpenAI と Power Platform を連携しています。両者、導入方法は同じようなものですが、出発点を間違えないように注意しましょう。

#### Azure OpenAI
![新規キャンバス_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/56a6ced3-d5bd-a105-e645-f749e0982d6e.jpeg)

Azure OpenAI は、Microsoft の Azure クラウドサービスの一部として提供されています。怒られることを承知で書くと Azure は「仮想環境」と置き換えておいてもらえればOKです。仮想環境とは、インターネット経由で計算能力やデータストレージなどのコンピュータリソースを提供する環境をいいます。皆さんの普段使っているパソコンの本体がオンライン上にあるものと捉えて問題ありません（クラウド・コンピューティング・サービスといいます）

ユーザーは自分のコンピュータにソフトウェアやハードウェアをインストールせずに、インターネットを介してこれらのリソースを利用できるというご利益があり、これにより、コスト削減や効率化が図れます。

そんな Azure OpenAI の主な機能や役割は次のとおりです。
- OpenAI のモデル（GPT-4 や GPT-4o、Codex など）を Azure 上で利用可能である点
- Azure 上で利用できるため、セキュリティやコンプライアンス機能が強化されている（安心安全ということ）
- 他の Azure サービス（データベース、機械学習ツール、分析ツールなど）と数珠繫ぎ的に統合可能
- 利用ケースとしては、企業アプリケーションの開発、カスタマーサービスの自動化、ドキュメント生成やデータ分析の補助などが挙げられる

#### ChatGPT
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/69dc463d-d4e7-b046-cf10-54e56b55d697.png)

一方、ChatGPT は、OpenAI が直接提供するウェブベースのインターフェースまたは API のことを指します。「ウェブベースのインターフェースまたは API 」が分からないという人は、ChatGPT の画面のことだと思っておいてください。要は、ChatGPT とユーザーを繋げるための画面や住所を提供しているということです。

主な機能や役割は次のとおりです。
- ユーザーとの対話を通じて情報提供や質問応答を行う
- さまざまな用途（カジュアルな会話、情報検索、タスク支援など）に対応
- 開発者や個人が簡単にアクセスできる
- 利用ケースは、一般ユーザー向けの情報提供やエンターテインメント、個人的なアシスタント、プロトタイピング（＝新しい製品やシステムの設計・開発において、その初期段階で試作品を作成する過程）や学習目的での使用

#### 違いの要点（まとめ）
Azure OpenAI が Microsoft の Azure クラウドサービスの一部として提供しているのに対し、ChatGPT は OpenAI が直接提供するサービスを指しています。

クラウドサービスとして提供している点から、Azure OpenAI は、セキュリティ面に優れていると云えます。主に企業や開発者が使用すると良いと考えています。ふんわりとした言い方になりますが、ChatGPT と比べると（レートリミットの観点から）安定的な運用も期待できます。要するに、懐が広いのですね。

一方、ChatGPT は、ウェブ上での利用が可能である点から、一般ユーザーや教育的利用など幅広い層に使いやすいツールだと思います。もちろん、機密情報のような漏洩したら困るような情報を入れなければ、開発者でも使用できます。

まずは大まかにこれらを理解した上で、Azure Open AI を利用すべきか ChatGPT を利用すべきかを判断すると良いでしょう。

### 実装の大まかな流れ
ということで、Azure OpenAI のテキスト生成を Power Platform に実装してみましょう。Power Platform にたどり着くまでに時間を要するので気長に取り組んでください。

:::note warn
別途、Power Automate のライセンス（有償）が必要です。
:::

#### Azure OpenAI の利用申請（サブスクリプション作成）
Azure OpenAI を使うために、[コチラのフォーム](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUNTZBNzRKNlVQSFhZMU9aV09EVzYxWFdORCQlQCN0PWcu)から、まずは利用申請を行う必要があります。全部英語ですが、翻訳ツールなどを駆使しながら回答してください（気持ちは分からなくもないですがココで折れないように）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/62527f68-e1cd-0c1d-de84-71e192b0248d.png)

注意しなければならないのは、メールアドレスの項目だと思います。赤字で "Applications submitted with a personal email address (e.g. gmail.com, hotmail.com, outlook.com, etc.) will be DENIED." と書いてあるように、独自ドメインのメールアドレスが必要となります（取得方法はggってください）

#### Azure OpenAI のリソースを作成する
利用申請を終えたら、その旨のメールが届きます。そのメールが届いたらリソースを作成します。リソースの作成方法は、[コチラの記事](https://yo-yon.hatenablog.com/entry/azure20230722)が分かりやすかったです。参考にして取り組んでみてください（その前に、Azure Portal の画面を開いておきます）

![新規キャンバス_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/198e7e1d-0fba-51c9-eeee-a2750c9aa1dc.jpeg)


#### Azure OpenAI のモデルをデプロイする
リソースの作成も完了したら、そのリソース内にモデルをデプロイします。使い始めた時、カタカナ語だらけで意味が分かりませんでしたが、簡単に「フォルダを分けて作成する」という理解で良いと思います。従量課金（支払い）の観点から、この作業が大切なのでしょうね。

今回も[コチラの記事](https://yo-yon.hatenablog.com/entry/azure20230726)が参考になりました。なお、モザイクがかかってある箇所は他人に共有しないように細心の注意を払ってくださいね。悪用されかねません。

#### Azure OpenAI の API 等を取得する
Power Platform との連携には、Azure OpenAI の API が必要になります。API とは、あるアプリと別のアプリを結びつけるものをいいます。その取得の手順は[コチラの記事](https://qiita.com/Takashi_Masumori/items/96b9e0f1590762fd6fad)を参考にしました。アップデートにより画面が異なっているためトレースする形で記しておきます（非常によくまとまっているため、ご一読ください）

![新規キャンバス_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/8646f46d-5f23-1d08-f4d4-6e86289f45e9.jpeg)

まず、Azure Portal から Azure OpenAI をクリックします。

![新規キャンバス_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/5330cf15-3a50-2a74-1f44-e311d1ae0d31.jpeg)

次に、画面左手のサイドメニューから「キーとエンドポイント」を選択します。すると、API キーが2つあるので、その内のどちらか1つをコピーしてメモ帳などに控えておきます（※取り扱い注意）

同様に「エンドポイント」もコピーして、同様にメモ帳などに控えておきます（※こちらも取り扱い注意）

![新規キャンバス_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/b672ad98-c57b-2f05-2acd-05bdf5456529.jpeg)

最後に、Azure OpenAI Studio に移動し、チャットプレイグラウンドをクリックします。画面が表示されたら、薄い青色の背景の中に「コードの表示」というボタンがあるのでクリックします。

![新規キャンバス_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/ca1bf2a6-1647-a9cf-861b-ead4f7687394.jpeg)

書いていて気付きましたが、全部ココから必要な情報が取り出せましたね。ここでは、JSON のコードをコピーして控えておきます。

#### Power Automate のフローを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/7ad0483c-a3f4-4c48-d9fc-6a81496b727a.png)

Power Automate のフロー作成も、[コチラの記事](https://qiita.com/Takashi_Masumori/items/96b9e0f1590762fd6fad)を参考にしています。Power Apps 側でのある特定の操作をトリガーにしてフローが発火します。

作成アクションには、先ほど控えておいた API キーを入力し、後続の HTTP アクションの「ヘッダー」で活用します（引用の記事をご覧ください。ハートを忘れないように付けておいてください）

一点だけ、ここでハマりやすいのは、引用記事の「コピーしたURL」に入力する内容かなと思います。ここには、先ほど控えておいたエンドポイントをそのまま貼り付けてもエラーになってしまうので、次の内容に修正して入力する必要があります（[Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference#authentication) に書いてあります。筆者の記事を鵜呑みにせず、必ずご確認ください）

~~~
（控えておいたエンドポイント。https://から始まる）/openai/deployments/（デプロイ名）/completions?api-version=（APIのバージョンを YYYY-MM-DD の形式で）
~~~

何度かエラーを吐くかもしれませんが、HTTP アクション時点でのエラーなので費用は発生しません（でした）。安心してトライ・アンド・エラーを繰り返してみてください。API のバージョンは、プレビューになっていない最新のものを書いておくと良さそうです。

また、HTTP アクションの後続のフローである JSON の解析で必要なスキーマは次のとおりです。エラーを吐く際は（お手数をかけますが）一度ワークフローを動かして必要な情報を貼り付けてください。

~~~
{
    "type": "object",
    "properties": {
        "id": {
            "type": "string"
        },
        "object": {
            "type": "string"
        },
        "created": {
            "type": "integer"
        },
        "model": {
            "type": "string"
        },
        "usage": {
            "type": "object",
            "properties": {
                "prompt_tokens": {
                    "type": "integer"
                },
                "completion_tokens": {
                    "type": "integer"
                },
                "total_tokens": {
                    "type": "integer"
                }
            }
        },
        "choices": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "object",
                        "properties": {
                            "role": {
                                "type": "string"
                            },
                            "content": {
                                "type": "string"
                            }
                        }
                    },
                    "finish_reason": {
                        "type": "string"
                    },
                    "index": {
                        "type": "integer"
                    }
                },
                "required": [
                    "message",
                    "finish_reason",
                    "index"
                ]
            }
        }
    }
}
~~~

最後の作成アクションは、Azure OpenAI からの回答を取得します。その回答は、上で貼り付けた JSON の content に戻って来ます。なので、次のような処理で抽出してあげます。

~~~
first(body('JSON_の解析')?['choices'])?['message']?['content']
~~~

解説すると、JSON の階層の「choices の {} 内にある最初の項目で、message の {} 内にある、content です。この場合 first 関数を使用しなくても良いのですが、Apply to each を避けることができ、フローを早く処理できるメリットがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/6e571047-702d-e89b-1963-9af645e69a68.png)

仕様のためお見せできないところが多々ありますが Power Automate 側の操作は以上です。Poawer Apps 側の操作に写りましょう。

#### Power Apps からフローを呼び出せるようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/39a33b95-0fbe-ad0c-6ddd-ab3dd137859a.png)

オーサリングメニューの Power Automate のアイコンから、先ほど作成した Power Automate を呼び出します。呼び出したら、アイコンを１つ挿入し、OnSelect プロパティに次の数式を入力しました。

~~~
Set(gblAnswer,ChatGPT_Summary.Run(lblAuthor.Text&"の"&"『"&DataCardValue2.Text&"』"&"という本を日本語で200字程度で要約し、あなたの所感を140字程度で教えてください。"))
~~~

ChatGPT のパターンでも作成したのでフロー名がそのままとなっていますが、Azure OpenAI とは別なのでお気をつけください（ごめんなさい）

解説すると、現在選択されている書籍の要約をしてもらい、その回答を gblAnswer に格納するように設定しています。ちなみに、著者名もプロンプトに入れているのは、重複する書籍名があった場合の対応策です。AI から必要な情報を引き出すためには、結構マメに指示をする必要があります。まあ、それは人間に指示を出す時と同じです。

どういったアプリでも、共通して言えるのは、トークン数の節約のために、プロンプトには文字数制限を設けたほうが良いかなという点です（湯水のように使って良い環境なら別ですが、筆者はちょっと生活苦なので原稿用紙１枚分、400字以内になるように設定しています。携帯電話にもスッポリ収まるので丁度いい文量です）

最後に、次のようにテキストラベルに変数を呼び出して実装完了です。
~~~
gblAnswer.content
~~~

微調整の後、完成したのがコチラとなります。API の呼び出しに時間がかかってしまいましたが、コツさえ掴んでしまえば先駆者のおっしゃる通り、確かに簡単ですね。

https://x.com/eigogakuto/status/1804391468502540531

## 結
今回は、Azure OpenAI との連携を焦点に絞って AI 活用の記事を書きました。ChatGPT と Power Platform の連携は[コチラの記事](https://qiita.com/Takashi_Masumori/items/8a07fb6d1869967ce1f9)に詳しいです。連携の要領は Azure OpenAI と同じなので、この記事を読んで実装できるようになっていれば（たぶん）大丈夫だと思います（気付けば全て益森さんの記事ですね。この場を借りて御礼申し上げます）

とはいえ、いきなり対話型のアプリ開発は難しいはずなので、次の基本を押さえながら、のんびりと一歩ずつ取り組んでみてください。JSON で必要なデータを抽出できるようになれば、色々なアイディアに対応できるはずです。

1. Power Apps から Power Automate のフローを発火させられるようになる
1. Power Automate で必要なデータを抽出できるようになる（JSON の操作）
1. 抽出したデータを Power Apps に戻して表示できる（当記事で行ったように変数を活用する）

JSON の操作に関しては、末尾に付した記事やスライドが参考になります。　

さて、色々と応用が利きそうです。連携だけに絞ったので Power Automate で抽出したデータを Power Apps に戻して表示するだけでしたが、AI の回答を修正したいといった要望があった時は、ラベルコントロールに表示するのではなく、テキスト入力コントロールに表示することで、アプリ使用者による修正を入れることもできるでしょうね。

とりあえず連携方法さえ理解できていれば、色々な応用が利くはず…ということで、備忘録がてら記事を執筆しました。ここまで読んでいただきありがとうございました。次回の記事でまたお会いしましょう。

## JSONと仲良くなろう
- Hiro さん, 2020, 『[JSON と仲良くなるために (1)](https://mofumofupower.hatenablog.com/entry/2020/09/03/152715)』.
- Hiro さん, 2020, 『[JSON と仲良くなるために (2)](https://mofumofupower.hatenablog.com/entry/2020/09/03/204727)』.
- Hiro さん, 2020, 『[JSON と仲良くなるために (3)](https://mofumofupower.hatenablog.com/entry/2020/09/04/021523)』.
- Hiro さん, 2020, 『[JSON と仲良くなるために (4)](https://mofumofupower.hatenablog.com/entry/2020/09/04/164851)』.
- Hiro さん, 2020, 『[JSON と仲良くなるために (まとめ)](https://mofumofupower.hatenablog.com/entry/2020/09/04/190039)』.
- Hiro さん, 2020, 『[Select アクションで配列を変換する](https://mofumofupower.hatenablog.com/entry/2020/05/15/003312)』.
- Hiro さん, 2020, 『[Apply to each のパフォーマンス改善（配列加工の場合）](https://mofumofupower.hatenablog.com/entry/2020/08/12/093000)』.
- Makoto Maeda さん, 2023, 『[JSON 解析の基本【Power Automate】](https://zezeze.hateblo.jp/entry/2023/01/11/130159)』.
- MiyakeMito さん, 2021, 『[JSON の読み解き方](https://speakerdeck.com/miyakemito/jsonfalsedu-mijie-kifang)』.
- MiyakeMito さん, 2022, 『[JSON は怖くない](https://speakerdeck.com/miyakemito/jsonhabu-kunai)』.
- 太田浩史, 2023, 『[Power Automate ではじめる業務の完全自動化](https://www.amazon.co.jp/Power-Automate%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E6%A5%AD%E5%8B%99%E3%81%AE%E5%AE%8C%E5%85%A8%E8%87%AA%E5%8B%95%E5%8C%96%EF%BC%88%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%A8%E3%82%AD%E3%82%B9%E3%83%91%E3%83%BC%E3%83%88%EF%BC%89-%E5%A4%AA%E7%94%B0-%E6%B5%A9%E5%8F%B2/dp/4295017795)』, pp.234-252, 株式会社インプレス.
- MiyakeMito さん，2024, 『[JSON攻略法！](https://speakerdeck.com/miyakemito/jsongong-lue-fa)』.
- MiyakeMito さん，2024, 『[Power Automateのデータ操作(Data Operation)について](https://speakerdeck.com/miyakemito/power-automatenodetacao-zuo-data-operation-nituite-ver-dot-modandezaina)』.

## 追記
![新規キャンバス_6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952933/f1d3dd41-8a93-e37d-6885-a2153975520a.jpeg)

大体 10 数件ほど要約してコレくらいの費用感です。サイドメニューの「コスト分析」から確認できます。書き忘れていました。お詫び申し上げます。