Power Virtual AgentsとPower Automateを使ってOpen AIと対話してみよう

# はじめに
ChatGPTがのインパクトにより、Open AIのAPIを利用したテクニックも数々上げられています。
今はプレビュー段階ですので、「今後どのくらい使えるのか?」という点は未知数ですが、OpenAIを活用して
仕事の景色も変わってくることが予想されます。

今回は`Power Platform`の中で、`Power Virtual Agents`と`Power Automate`を使って
**OpenAIと対話するBotをPowerPlatformを活用し、ローコードで作っていきたい**と思います。

# OpenAI APIの使い方
Google Apps Scriptを中心に、既に多くの活用事例を紹介されています。
私は、その内容を**PowerAutomateで表現するとこうなる**という紹介をさせていただきます。

https://openai.com/api/

## 流れ
1. OpenAIのアカウントを作る
1. APIキーの発行

こちらについては、AutoWorkerを運営しているヤマタケさんのBlogが大変参考になります。
この通りやれば作れるので詳細は深堀しません。

https://auto-worker.com/blog/?p=6988

[OpenAI API](https://openai.com/api/)のページでクリックしていけばたどり着きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b0ba099d-0ff8-de3b-8cc7-5b2e69043103.png)


:::note alert
このsecret Keyは絶対に公開してはいけません！
:::

# 1. Power Automateのフローを作成する
Power Virtual Agents（以下PVA）にPower Automateのフローは組み込みが可能です。
`Question` to `Answer`のサイクルを回すために、AIの力を借ります。

PVAの設計時に **予めフローが用意されていた方が** 作成の効率が良かった経験から、
まずPower Automateのフローを紹介します。

フローの種類は **自動化したクラウド フロー**です。
トリガーは ***Power Virtual Agentsがフローを呼び出すとき（V2）*** です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2c161ab5-9066-39e9-b101-e89d3acc0c89.png)

### フローの全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e9fc0bca-9c31-93bb-0759-597fd300ebf4.png)

とても簡素ですね。シンプルなんです。

流れを書くと
1. Power Virtual Agentsからチャットのコトバをテキストで受け取る
1. APIの認証のために使用する秘密鍵を定数として保持する
1. AIのMODELをテキストで設定する
1. temperature　- 意味：0から2の範囲を取り、出力する単語のランダム性を指定します。
1. TOKENS - 出力される単語の数
1. HTTP要求を送信する - POST Method
1. 戻り値を取得し、加工したうえでPower Virtual Agentsに返す（改行コードなど余計であるため）

- Point Power AppsやVirtual Agentsからデータを受け取る画面
個人的に躓くポイントですが、赤線が受け取る文字列を格納する**値の名前**と解釈しています。
受け取る値を増やすこともできますが、このシーンでは不要ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/956c55ed-adf9-5742-39cb-442dadcf59b4.png)

後述のステップはこちら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/4e8907be-f8fc-a0d7-8b4e-e57d860836a0.png)

HTTP要求に含めるパラメーターを定数として宣言しています。

入力する文字列は下記の通り - SECRET KEYは秘密鍵なので割愛

|PARAM|意味
|---|---
|MODEL NAME|AIのモデル名です
|MODEL TEMP|出力する単語のランダム性
|MODEL TOKENS|生成する文章の最大単語数

私はFlow作成時にGoogle Apps Scriptで書かれている方々の設定値を参考にしましたが
[Reference](https://beta.openai.com/docs/api-reference/introduction)を見ると豊富ですね！AIモデルの数が豊富って素敵✨

https://beta.openai.com/docs/api-reference/introduction

All Englishですが翻訳機能を使ったりして目を通しておくことをおすすめします。
AIの種類や設定値も多様なんだ！って感動でした。

### HTTP要求

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e383ad98-0183-f890-0ed4-56991b4e9011.png)

#### URI
```
https://api.openai.com/v1/completions
```

#### ヘッダー
|項目|値
|---|---
|Content-Type|application/json
|Authorization|Bearer 秘密鍵

オーソドックスなパターンです。

#### Body

|項目|値|データ型
|---|---|---
|model|モデル名|文字列
|prompt|質問の文章|文字列
|temperature|ランダム性|数値
|max_tokens|単語数|数値

ポイントはデータ型を気を付けましょう。
ダブルクオーテーションで囲むところと、**囲まないところ** が混在するので注意です！

### 戻り値

HTTP要求から戻るBodyのスキーマです。

```JSON:スキーマ
{
    "type": "object",
    "properties": {
        "id": {
            "type": "string"
        },
        "object": {
            "type": "string"
        },
        "created": {
            "type": "integer"
        },
        "model": {
            "type": "string"
        },
        "choices": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "text": {
                        "type": "string"
                    },
                    "index": {
                        "type": "integer"
                    },
                    "logprobs": {},
                    "finish_reason": {
                        "type": "string"
                    }
                },
                "required": [
                    "text",
                    "index",
                    "logprobs",
                    "finish_reason"
                ]
            }
        },
        "usage": {
            "type": "object",
            "properties": {
                "prompt_tokens": {
                    "type": "integer"
                },
                "completion_tokens": {
                    "type": "integer"
                },
                "total_tokens": {
                    "type": "integer"
                }
            }
        }
    }
}
```
この中で返ってくる質問への答えは`choices`です。
なんとArrayなんですね。複数回答が返ってくるのか・・・と驚きですが、
検証として、**最初の要素のテキストを取得します。**

同時に、改行コードなど余計なモノが入っているので`trim`関数を挟みます。
```
@{trim(body('HTTP')?['choices'][0]?['text'])}
```
これでFlowは完成です。
***

# 2. Power Virtual Agentsを作成する
さて、ここでBotをたてます。
**運用向けのビルド**でサクっとプロビジョニングします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/6644f3b7-6249-f172-9464-b9d5a3e70ab5.png)

 - 参考 PVAの画面

`トリガーフレーズ`に対する反応が予め揃っていますね。
今回初めて触りましたが、**あっ！これはいるよね！** と思う内容は網羅されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/325cdecf-be86-47bc-4917-05d95b517f5b.png)

挨拶などは確かに一から設定することがとても手間ですのでありがたい・・

さて、Power Automateとのコラボレーションに移ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/cf44b3ec-1548-bcf0-2a3c-0a439921a5be.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/a0422e26-1538-8e92-33ed-79814e089686.png)

1. **トリガーフレーズ** OpenAIで問い合わせが開始
1. Botから「What do you want to hear?」が返ってくる
1. **聞きたい質問**を返す
1. 変数`question`に質問が全部格納され、Power Automateのフローが起動する
1. Power Automateから文字列が返り、変数`answer`に返す
1. `answer`をそのまま返答として返す

https://learn.microsoft.com/ja-jp/power-virtual-agents/advanced-use-flow

慣れればどうにでもなりそうですね。
他の対話の中でも、リダイレクトという形でOpenAIの話題に持っていくことが出来るので、繰り返し内容確認が出来そう！

### 注目ポイント Power Virtual Agents！

画像は実際の挙動です。

https://twitter.com/DemodoriGatsuo/status/1620011098144641026

なんと**Teams**に入っています！わからないことスグ確認できるじゃん！！凄すぎる👀✨

他にもリーチできる範囲は大きい！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/15c401ad-8314-487c-52b4-ba63fd023a43.png)

いやあAIの波は改めて凄い・・・。私の仕事も無くなるかも・・・。
それまでに楽しみながら勉強したいと思います！

それでは皆様、良いPower Lifeを!!