GPT Function Calling で LINE WORKS から kintone にデータ入力と LINE WORKS の予定作成

サイボウズさん主催の kintone devCamp Boost! のセッション中にお見せしたデモンストレーションの内容を記事にしました。

https://page.cybozu.co.jp/-/devcampboost/

なお、セッション中のハンズオンの内容は、別で記事にしています。
TITLE: LINE WORKS の WOFF アプリから kintone アプリにデータ入力
URL: https://qiita.com/iwaohig/items/163beae48a425cdb60f6

## Function Calling で LINE WORKS の会話から kintone にデータ入力、LINE WORKS の予定作成
ChatGPT の API の Function Calling を使い、自然な会話のなかから必要なデータを取り出して kintone の API を実行してデータ入力したり、LINE WORKS の API でカレンダーの予定を作成したりできます。

動作の様子です。
通常の発言には、GPT の API が一般的な応答をします。
![l_147288799_349_93d09bf2dd1e498d665f2ad4134a51de.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/7f24e206-3de8-826b-be84-52915258be14.png)

作業報告に関連した発言と判別された場合は、kintone の API でレコード登録を行い、その結果を伝えてくれます。
![l_147288799_350_f318d2a7c7589792a13a39b35d9bc23e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/8be30ae3-26f0-2221-886a-d5e8917b5e88.png)

kinton アプリにレコード登録されます。
![l_147288799_351_d52fb664a1c6e4696d2ff94bf8bd9796.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/ce034400-c9b9-7958-406f-5fb3051250d5.png)

予定作成を求める発言と判別された場合は、LINE WORKS の API で予定を作成し、その結果を伝えてくれます。
![l_147288799_352_992adbbf97e7e61283b91ecf67e00e5c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/444f365b-da18-c51b-dd2f-9617114eef4b.png)

LINE WORKS のカレンダーに予定が作成されます。
![l_147288799_354_b73b676b65365a279ccabfd50dff48c4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/4fdb20f1-69bc-3ac7-d041-862a91068cc5.png)

これらの動作は GPT の API の Function Calling の機能を使っています。
https://platform.openai.com/docs/guides/gpt/function-calling

このデモンストレーションでは、レコード登録と予定作成の 2 つの functions のパラメータを指定しています。具体的なパラメータは後述します。

functions が設定されていると、「何ができますか」などの質問に対して、functions を発動するのに必要な情報を教えてくれるようです。
![l_147288799_356_92de62d36904ff651f3347d7a171796d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/62e1b0d9-9cc6-061d-954d-be8b51a57455.png)

## Power Automate のフロー作成
Power Automate のフローで作成してみます。

利用者は LINE WORKS の Bot と会話します。
Bot あての発言を受けるため、HTTP 応答のトリガーを作成します。

![l_147288799_334_39d80e25bca2efb6289542ed932d9062.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/ea1e5019-38a3-64b0-aec2-a67dafd0c5f0.png)

JSON スキーマは以下です。
~~~
{
    "type": "object",
    "properties": {
        "type": {
            "type": "string"
        },
        "source": {
            "type": "object",
            "properties": {
                "userId": {
                    "type": "string"
                },
                "channelId": {
                    "type": "string"
                },
                "domainId": {
                    "type": "integer"
                }
            }
        },
        "issuedTime": {
            "type": "string"
        },
        "content": {
            "type": "object",
            "properties": {
                "type": {
                    "type": "string"
                },
                "text": {
                    "type": "string"
                }
            }
        }
    }
}
~~~

「今日の」や「昨日の」といった発言から日付を割り出すために [日時] のコネクタで取得したデータを利用して GPT に今日の日付を伝えます。
![l_147288799_335_602ae48e7ef2863412f3b2f397f4b5c7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/59492cb2-4af1-5b92-f30e-64e34f619b60.png)

[HTTP] アクションで OpenAI の GPT の API を実行します。
![l_147288799_336_b3faaf6c6501d8a831d2273d93afa2d4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1f3f197c-f9a0-08f0-62ef-c9024cb80b60.png)

user の content は LINE WORKS の Bot で受けたユーザーの発言を指定しています。
functions の description で [日時] コネクタで指定した日付を記載しています。
その他はデータの入力先の kintone アプリと LINE WORKS の予定作成に合わせて作成しています。具体的に記述すると期待した結果を得やすいです。ただ token 数との兼ね合いも考慮が必要です。日本語が使えますが、英語だと token が節約できるとのことです。

サンプルは以下です。
~~~
{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "user",
      "content": "@{triggerBody()?['content']?['text']}"
    }
  ],
  "functions": [
    {
      "name": "daily_work_report",
      "description": "日報データを送信します。作業者名、作業日、時刻、作業内容、場所の情報を送信します。今日の日付は@{body('タイム_ゾーンの変換')}",
      "parameters": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "title": "作業レコード",
        "description": "作業者の詳細なレコード",
        "properties": {
          "作業者名": {
            "type": "string",
            "description": "作業者の名前"
          },
          "作業日": {
            "type": "string",
            "format": "date",
            "description": "作業が行われた日2023-mm-dd のフォーマット"
          },
          "時刻": {
            "type": "string",
            "format": "time",
            "description": "作業が行われた具体的な時刻 hh:mmのフォーマット"
          },
          "作業内容": {
            "type": "string",
            "description": "行われた作業の内容"
          },
          "場所": {
            "type": "string",
            "description": "作業が行われた場所"
          }
        },
        "required": [
          "作業者名",
          "作業日",
          "時刻",
          "作業内容",
          "場所"
        ]
      }
    },
    {
      "name": "events",
      "description": "予定を作成します。主催者情報は user@lwugdev、開始時間、終了時間ただし指定がないときは開始時間の60分後、イベントの概要、イベントの詳細を送信します。",
      "parameters": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "properties": {
          "eventComponents": {
            "type": "array",
            "description": "イベントのコンポーネント一覧",
            "items": {
              "type": "object",
              "properties": {
                "summary": {
                  "type": "string",
                  "description": "イベントの概要"
                },
                "description": {
                  "type": "string",
                  "description": "イベントの詳細説明"
                },
                "location": {
                  "type": "string",
                  "description": "イベントの場所"
                },
                "organizer": {
                  "type": "object",
                  "description": "主催者情報",
                  "properties": {
                    "email": {
                      "type": "string",
                      "description": "主催者のメールアドレス"
                    },
                    "displayName": {
                      "type": "string",
                      "description": "主催者の表示名"
                    }
                  }
                },
                "start": {
                  "type": "object",
                  "description": "開始時間情報",
                  "properties": {
                    "dateTime": {
                      "type": "string",
                      "description": "開始日時"
                    },
                    "timeZone": {
                      "type": "string",
                      "description": "タイムゾーン"
                    }
                  }
                },
                "end": {
                  "type": "object",
                  "description": "終了時間情報",
                  "properties": {
                    "dateTime": {
                      "type": "string",
                      "description": "終了日時"
                    },
                    "timeZone": {
                      "type": "string",
                      "description": "タイムゾーン"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  ]
}
~~~

GPT からのレスポンスが通常の場合か、Function Calling の応答かで処理を分岐します。

![l_147288799_357_598911dde46954070d85916a8cef3d49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/8ff3e7a9-7ac0-41f9-abf8-7b5e6f54dc11.png)

~~~
body('HTTP')?['choices'][0]?['finish_reason']
~~~
上記が "function_call" で始まる場合は、Function Calling の処理に繋ぎます。
該当しない場合は通常の応答をします。

![l_147288799_358_0171026f286e171e541cc18cf8722b00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/9fad5406-74fc-4e68-d36e-92b73c517083.png)

text 部分は下記です。
~~~
body('HTTP')?['choices'][0]?['message']?['content']
~~~

Function Calling の処理です。kintone のレコード登録か、LINE WORKS の予定作成かをスイッチで分岐します。

~~~
body('HTTP')?['choices'][0]?['message']?['function_call']?['name']
~~~

function_call の name を見ています。

以降、GPT API のレスポンスから取得したパラメータを使ったレコード登録と、予定作成の API 実行、GPT への function calling の結果の送信、および Bot からの送信をつないでいます。

![l_147288799_360_75dd884270d084206ecc8ca1f6a679f2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/8ab34e8a-4f47-c03e-d7b6-3e42cb36757f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/11ac6b3c-e0a7-98be-2e94-5a97fb016d27.png)

![l_147288799_362_a0bd96353dacc92f89e9ef894e869071.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/946ff31b-50b6-1cbe-90f7-8fab086c90fd.png)