WinActorからOpenAI APIを叩いてみた
はい、かーでぃです。
この記事は、2023/12/19に開催したRPACommunityのWinActor-Talk支部で話をした内容のまとめ記事です。
イベント情報
19日のイベントなのに、14日にConnpassを公開という…。いつもは2週間ぐらい募集期間があるのに、今回は1週間もない!人が集まるのか心配なところもありますが、14日朝公開で、14日夜には既に30人も登録がありました!
さらになんと!!
WinActor公式アカウントからも、イベントの宣伝ポストがされました!!
これは、ちょいやばい…テンションあがるwww
登壇資料
アーカイブ
まずは概要説明
最終的に制作物は、以下のような表を完成させます。
設定としては、ある観光業企画課のAさんが、上司から「市のリストから、その市のある都道府県名、人口、平均気温、観光名所を埋めて、表を完成させて」と依頼を受けた(投げられた)ところです。
この手の調べもの系の依頼、ちょくちょくありますよね。
そして、往々にしてデータが一か所にまとまっていないため、調べるのにめちゃくちゃ時間がかかるいやーーーーな、パターンのヤツです。
今回は、A列に市の名称が入っているので、そこから残りのB~E列(黄色のセル)を埋めることです。
都道府県名は、これぐらい有名な市(豊橋は愛知県!)ならしらべずともわかりますが、人口や平均気温なんて、どうやって調べれば…
そんな調べものは、知識量は膨大なAI君にやらせてしまおう!というのが今回の趣旨しです。まさに、👇これですねw
そして、そのAI君が、ChatGPTで有名なGPT3.5(無課金のため4が使えなかった…😢)。GPT3.5を使うためにOpenAI APIを利用する、といったわけです。
WinActorからOpenAIを使うために
2つのことが必要です。
あ、前提としては、OpenAI APIキーは取得済としてます。取得の方法は…詳細はググってください(笑)
1 WinActorからAPI連携をする方法
2 OpenAI APIの使い方
この2つがわからないと先に進みません。
WinActorからのAPI連携については、2022年10月のWinActor-Talk支部ですばらしい動画が残ってます!
下記は、その際のイベントページです。動画のリンクも、資料のリンクも掲載されていますので、是非動画と資料を見てください。
自分もこの動画と資料がなかったら、今回のイベントは開催できなかったと思います。
2つめのOpenAI APIは、ググるといろんな方が既に書かれていますので、そちらを参考にして頂ければよいですが、OpenAIが提供しているリファレンスもわかりやすいと思うので、まずはこちらを見るのをオススメします。
https://platform.openai.com/docs/introduction
英語ですが、ブラウザ機能で日本語に翻訳するより、一旦は英語で見て頂くのがいいんじゃないかと思います。
今回はテキスト生成なので、左側メニューの「Text generation」をクリックしてもられば大丈夫です。
少し下にスクロールさせると、modelsと書いてあり、gpt-4,gpt-4 turbo,gpt-3.5-turboのAPI ENDPOINTはこちら、と記載がありますので、URLはココかな、というのがわかります。
もっと下にスクロールさせると、パラメータの与え方等も記載があるので、参考になります。が、ある程度の知識がないとわかりにくいと思うので、その辺りはこの記事で説明していきますね。
ちなみに、サンプルコードとしてPython、node.js、curlが記載されていますが、Pythonとnode.jsはライブラリ利用をしているため、今回はあまり参考になりません。curlが生データを作って組んであるので、そちらで使い方の感覚を掴んでもらえればいいかと思います。
ちなみにAPIとは…
↓のように、サービス提供会社(下記で言えばOpenAI社)が、自社サービスを社外から利用させるためにAPIを提供しており、そのAPIを利用することでOpenAIが提供するAIを間借りすることができています。
また、APIを使う上で切っても切り離せないのがJSONです。JSONのJSは、JavaScriptの略ですが、適用範囲はJavaScriptにとらわれず、広く使われています。
JSONの良いところは、構造化データとして、キーと値のつながりが強く、そしてテキストで扱えるため、分かりやすく汎用性が高いところですかね。
ただ、自分はニガテです(笑)
CSVも構造化データではあるのですが、ヘッダ行が無いと構造化データとは言えず、繋がりが弱いためファイル単位でのデータ受け渡しではよく使われますが、API等ではあまり使われないですね。
もう少し詳しく見ていきます
実際にシナリオに入るまえに、もう少しだけ雑学です。
今回、GPTから「都道府県」「人口」「平均気温」「観光名所」と4つの項目を取得したいと思います。
ChatGPTで叩くと、こんな感じで返ってきます。
あってる/あってないは、ひとまず置いておいて…
どうですか?この返事をもらって、先ほどのエクセルにうめれますでしょうか?
「都道府県名:」をキーワードに文字列検索すれば、「愛知県」は取れそうです。
では、人口は?平均気温は?観光名所は?
文字列操作でこれらの値を取得するのは困難です。できたとしてもシナリオが複雑化しすぎますし、そもそも毎回ChatGPTがこのような形で返してくれるとも限りません。
ではどうするか?
JSON形式で返してもらうように依頼します。
JSON形式で返してもらえれば、余分な情報は無いし、値を取り出すのも簡単です。
では、どうすればChatGPTは、JSON形式で返してくれるのか?
そこで出てくるのが、プロンプトエンジニアリングです。
プロンプトエンジニアリング
AIは膨大な知識量をもっています。その知識の中から欲しい情報をプロンプト(問合せ文字列)を用いて問合せをします。
その際に、欲しい情報にピンポイントに寄せたり、出力形式を整えてもらうようにプロンプトを調整するのが、プロンプトエンジニアリングです(深津式とか有名ですよね!)。
今回は、下記のようなプロンプトを準備しました。$CITY$は、文字列置換でエクセルから取得した市と置き換えます。
あなたは日本一の不動産屋の社長です。
「$CITY$」の都道県名、人口(単位は万人)、平均気温、観光名所を100文字以内で、JSON形式で出力してください。
制約事項
・JSON形式で回答すること。
・回答に単位は含めない。
・回答の数値項目は、数値のみとする。
JSONの形式
・Prefecture: 都道府県名
・Population: 人口
・AverageTemperature: 年間平均気温
・TouristAttractions:観光名所
ついでに言うと、プロンプト自体はテキストファイルで持たせています。プロンプトを変更したいときは、シナリオをいじらず、このテキストファイルを変更するだけで済むので、楽ですよね。
とりあえず座学がここまで。
この後、実際のシナリオを見ていきます!
全体フロー
ざっくり書くと、下記の①~⑥の繰り返しになります。
①プロンプト準備
②OpenAI APIを叩く
③返ってきたJSONからCONTENTキーの値を取得
④CONTENTの値をから各値を取り出す
⑤エクセルに転記
それでは、もう少し詳しく見ていきましょう!
①プロンプト準備とAPI実行
最初に、テキストファイルを読み込んで変数strPromptに代入しています。
その後、エクセルファイルの読み取りですね。
読み取った結果、A列が空欄ならシナリオを終了するようにしています。
IF文内のTRUE側が、このブロックのメインどころになります。OpenAI APIにデータを送るには………わからないので、OpenAI APIのリファレンスを見てみましょう!
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Who won the world series in 2020?"
},
{
"role": "assistant",
"content": "The Los Angeles Dodgers won the World Series in 2020."
},
{
"role": "user",
"content": "Where was it played?"
}
]
}'
curlのサンプルコードは、こんな風に書かれていますね。
ヘッダ情報は「-H」のに該当し、ボディ情報は「-d」が該当します。
-H ヘッダ情報
-d data情報
$OPENAI_API_KEY$は、個人(会社?)で取得したAPIキーを設定してください(取得の方法はググってみてくださいw)。
それを踏まえて、99_外部サービス連携▷02_HTTP関連▷内のHTTPライブラリを見てみましょう。
HTTPライブラリの基本設定になります。
メソッドは、今回はPOSTに設定します。URLは、先ほど示したOpenAIのリファレンスに書かれていたURLになります。
こちらが要求タブのヘッダ情報になります。
先ほどcurlの構文で見たヘッダ情報と同じものが、キーと値に分かれて書かれています。
こちらのライブラリでは、このように設定した値がJSONとしてヘッダ情報になるようです。
こちらは要求タブのボディ部になります。
curlの構文のボディと同じような内容ですが、2点異なっています。
1つめは、messagesですが、値は変数jsonMessagesが設定されています。
では、少しフローを戻ってjsonMessageの設定を確認してみましょう。
まず、変数設定で以下のように設定します。設定値は、curl構文のボディ部のmessagesの中身と似た感じですね。
続いて、ファイルから取得したプロンプト内に埋め込まれた$CITY$と、エクセルから取得した「市」を置換します。
最後に、jsonMessagesの中にある$prompt$を、👆で市に置き換えたプロンプトで置き換えます。
置換後のjsonMessagesの値は、こんな感じになり、この値をHTTPライブラリの要求タブのボディにmessagesキーの値としてセットしています。
[{"role": "user", "content": "あなたは日本一の不動産屋の社長です。「豊橋市」の都道府県名、人口………"}]
②実行結果
実行結果は、応答タブのボディ内で受け取ります。キーと値を正しく設定すれば、変数として受け取ることができるのですが、今回はファイルに落としています。
変数で試したところ、いくつかあるJSONライブラリを試してみたのですがうまくいかず、ファイルに落としたところ一発でうまくいったので、こちらの方が安定してるんじゃないかな、と思っています。
ちなみにヘッダは特に設定する必要はありません。
こちらは、実際に取得したchat応答.jsonの中身です。
必要な情報は、contentキーの中に入っています。
{
"id": "chatcmpl-8UuzxlIyvd4WPqfcwxmAIn88TmEsd",
"object": "chat.completion",
"created": 1702379633,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\n \"Prefecture\": \"神奈川県\",\n \"Population\": 72,\n \"AverageTemperature\": 15,\n \"TouristAttractions\": \"瑞穂町の瑞穂の園、相原公園、深沢公園、多摩動物公園\"\n}"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 185,
"completion_tokens": 79,
"total_tokens": 264
},
"system_fingerprint": null
}
それでは、このcontentを取り出すところを見ていきましょう。
③contentの取り出し
取り出すには、98_構造データ関連▷01_JSON▷JSONファイル 配列読み取りライブラリで、保存したchat応答.jsonを読み込みます。
👆にあるように、目的のcontentは、choicesキーの中に居ますので、👇ではキーにchoicesを指定しています。
これでchoices配下の値を変数jsonChoicesMessageに格納されました。
jsonChoicesMessageの中身は、下記になります。
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\n \"Prefecture\": \"神奈川県\",\n \"Population\": 72,\n \"AverageTemperature\": 15,\n \"TouristAttractions\": \"瑞穂町の瑞穂の園、相原公園、深沢公園、多摩動物公園\"\n}"
},
"finish_reason": "stop"
}
次はcontentキーのすぐ上にあるmessageキーを指定します。
ライブラリは、01_JSON▷JSON変数 読み取りを使います。下記のようにすることで、message配下の値が、strMessageに格納されます。
"role": "assistant",
"content": "{\n \"Prefecture\": \"神奈川県\",\n \"Population\": 72,\n \"AverageTemperature\": 15,\n \"TouristAttractions\": \"瑞穂町の瑞穂の園、相原公園、深沢公園、多摩動物公園\"\n}"
ここまでくれば、あとはcontentキーの値を取得するだけですね。
👆と同様に、JSON変数 読み取りを使って、変数strContentに格納します。
"{\n \"Prefecture\": \"神奈川県\",\n \"Population\": 72,\n \"AverageTemperature\": 15,\n \"TouristAttractions\": \"瑞穂町の瑞穂の園、相原公園、深沢公園、多摩動物公園\"\n}"
これで、strContentには、GPTから得た欲しい回答が取得できました…?
はい、そうですね。欲しい回答は「JSON形式で」とお願いしましたので、ちゃんとJSON形式で返ってきています。
なので、ここからさらにJSONで値を切り出していきます。
今回はキーを毎回指定しながら取得しましたが、下記のように一発で取得することも可能です。
こちらは、JSONが応答変数に入っており、それをキーを「.」で複数繋げて、キー「content」の値を変数回答に格納しています。
④contentの分解・分析
分解する前に、少しプロンプトをおさらいしましょう。
プロンプトでは、結果をJSONで出力してください、とお願いしたのと同時に、JSONの形式も指定しています。
・Prefecture: 都道府県名
・Population: 人口
・AverageTemperature: 年間平均気温
・TouristAttractions:観光名所
GPTから得られた回答も同じ形式になっております。
以前は、ここまでちゃんと返してくれなかったような気がするのですが、最近のGPTはその辺りの調整が進んでるのかもしれませんね。
さて、得たい値は、こちらが指定したキーで設定されていますので、あとは1つづつ取得するだけですね。
ということで、今回使ったJSON系ライブラリは、赤枠付けたこの2つだけなんですよ。
JSON系ライブラリ、合計で20以上あるんですが…2つしか使ってないので、たぶんもっと使いやすいライブラリとかあると思うのですが…この辺りは、また調べてnote記事にアップしていきますね。
⑤エクセルへの転記
最後は、Excel操作(値の設定2)ライブラリを使って、指定の場所に取得した各項目を設定していきます。
以上で、OpenAI APIを叩いて得た回答をエクセルに転記するシナリオができました。
おまけ
目ざとい人は気づいてるかも!?
エクセルファイルの名前がガンダムリストになってることを…。
そして、シート名がSheet2になってることを…。
そうです、実はSheet1にはガンダムネタも仕込んでます!(笑)
ガンダムネタは、IT x ガンダムLT大会でお披露目予定w
こちらも、こうご期待❣❣
12/20追記 忘備録(天の声)
HTTPライブラリ
配列等含むJSONが返ってくる場合には変数受け取りができない
⇒ HTTP(詳細)ライブラリの活用
JSONライブラリの01系と02系
02系の方が新しく機能が豊富だけど…バグ見つけちゃった by 天の声
⇒ 次回更新時に修正予定とのこと。
エスケープコードが消えた問題
JSONを取得する際に、「転記」を選択すると「"」を消す等の処置をしてくれる。その際にエスケープコードも消えるらしい。
一方「値の参照」の場合は、生データが取得されるので、「"」も付与されたままだし、エスケープコードも残る
12/20追記 チャットで頂いた市の調査結果
この記事が気に入ったらサポートをしてみませんか?