ChatGPTは最近の話題は教えてくれないので、API連携して外部APIを叩くと最新話題も取ってこれます。
ただし、通常言葉の揺らぎや別の言い回しになると認識してくれず、機械に人間が合わせる感じになりますね。
Function Callingで文脈の特定
まずは前回、Function Callingのお試しをしてみました。
文脈を特定して実際に処理を実行
前回のコードの続きみたいな処理です。前回はgetMoriokaWeather関数
を作っていて盛岡限定でしたが今回はgetWeather関数
として都市名を入れ込めるようにしてみます。
const OpenAI = require('openai');
const openai = new OpenAI({
apiKey: 'APIキー',
});
const prompt = {
role: 'user',
content: process.env.USERTEXT, //ターミナルから実行時に命令を入力して受ける
};
//天気を調べる関数
const getWeather = async (city) => {
console.log(city);
let cityId = '';
//都市名とIDの対応はここを参照 https://weather.tsukumijima.net/primary_area.xml
if(city === '盛岡') cityId = '030010'; //ここを連携する処理を書けば自動判定できそう
const url = `https://weather.tsukumijima.net/api/forecast/city/${cityId}`;
try {
const response = await fetch(url);
const data = await response.json();
// console.log(data.description.bodyText);
return data;
} catch (error) {
console.error("There was a problem with the fetch operation:", error.message);
}
}
const functions = {
getWeather,
};
const main = async () => {
const gptOptions = {
model: "gpt-4-0613",
messages: [prompt],
function_call: "auto",
functions: [
{
name: "getWeather",
description: "天気を取得",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "天気を調べる地名, e.g. 盛岡, 花巻, 平泉"
},
}
},
},
],
}
const completion = await openai.chat.completions.create(gptOptions);
const message = completion.choices[0].message;
console.log(completion.choices[0]);
let responseMessage = '';
//Function Callなのかそうではないのか
if(completion.choices[0].finish_reason === "function_call"){
console.log("function_callします...");
const functionCall = message?.function_call;
const args = JSON.parse(functionCall.arguments || "{}"); //引数の取得
// console.log(args)
const functionRes = await functions[functionCall.name](args?.city); //関数の実行
// console.log(functionRes); //実行結果
responseMessage = functionRes.description.bodyText
}else{
//Function Callではない場合
responseMessage = message?.content;
console.log(`通常GPT返信`);
}
console.log(responseMessage);
}
main();
実行: 盛岡の天気を教えて
盛岡の天気を教えて と言ってみます。
$ USERTEXT=盛岡の天気を教えて node fc.js
console.log(completion.choices[0]);
の箇所は以下のようなJSONになっています。
arguments(引数)にプロパティで設定したcityと入力した
{
index: 0,
message: {
role: 'assistant',
content: null,
function_call: { name: 'getWeather', arguments: '{\n "city": "盛岡"\n}' }
},
finish_reason: 'function_call'
}
結果、以下のようなAPIからの返信を取得できました。
高気圧が日本のはるか東にあって、本州付近に張り出しています。一方、低気圧がオホーツク海にあって北東へ進んでおり、前線が北海道付近を通って日本海へのびています。
岩手県は、晴れや曇りで、雨の降っている所があります。
1日夜は、高気圧に覆われるため、晴れや曇りでしょう。
2日は、前線の影響により、曇りや雨で、雷を伴い激しく降る所がある見込みです。
よもやま
仙台の天気を教えてなどでもちゃんとcityの引数に"仙台"という引数が入ります。このAPIが地名から検索できる仕様だったらこのまま使えてそうでした。
こちらから取得してIDとの紐付けが必要なのでこの辺別の処理を書けば完璧っぽかったですね。