「AIしげちゃん」の天気予報機能
Unityプロジェクトを破損してしまって、ChatdollKit v0.6.6 で再構築中の「AIしげちゃん」ですが、破損前のバージョンで GPTのFunction Callingを使って実装していた、以下の機能を復活させているところです。
気象庁の気象情報APIを利用し、指定した地域の天気予報を答える
環境センサーと連携し、温湿度の値や不快指数等を答える
スマートリモコンと連携し、部屋の照明や家電製品を制御する
まず始めは、ChatdollKitのサンプルにもあった 1. の天気予報です。折しも、ChatdollKit v0.6.6 でIoT制御コンポーネントを作ってる方(下記)がいらっしゃったので、参考にさせていただきつつ、手始めとして。
正直、ソースを公開するのは、ホビープログラマーの私にとって勇気のいることなのですが、また、ソースを失うような事態があるかもしれませんので、バックアップ代わりとしてw
[WeatherSkill.cs]
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using ChatdollKit.Dialog;
using ChatdollKit.Dialog.Processor;
using System;
using System.Net.Http;
namespace ChatdollKit.Kazz
{
public class WeatherSkill : ChatGPTFunctionSkillBase
{
public string FunctionName = @"get_weather";
public string FunctionDescription = @"指定した都市の天気予報を取得します。都市の名前は英語で答えてください(例:「Tokyo」)。";
public string InstructionPrompt = @"以下は指定された都市の天気予報です。あなた自身の言葉でユーザーに伝えてください。";
public override ChatGPTFunction GetFunctionSpec()
{
// Make function spec for ChatGPT Function Calling
var func = new ChatGPTFunction(FunctionName, FunctionDescription);
func.AddProperty("location_name", new Dictionary<string, object>() { { "type", "string" } });
return func;
}
protected override async UniTask<FunctionResponse> ExecuteFunction(
string argumentsJsonString, Request request, State state, User user, CancellationToken token)
{
// Parse arguments
var arguments = JsonConvert.DeserializeObject<Dictionary<string, string>>(argumentsJsonString);
var locationName = arguments["location_name"];
string locationCode = "270000";
switch (locationName)
{
case "Sapporo":
locationName = @"札幌";
locationCode = @"016000";
break;
case "Sendai":
locationName = @"仙台";
locationCode = @"040000";
break;
case "Tokyo":
locationName = @"東京";
locationCode = @"130000";
break;
case "Yokohama":
locationName = @"横浜";
locationCode = @"140000";
break;
case "Nagoya":
locationName = @"名古屋";
locationCode = @"230000";
break;
case "Kyoto":
locationName = @"京都";
locationCode = @"260000";
break;
case "Osaka":
locationName = @"大阪";
locationCode = @"270000";
break;
case "Kobe":
locationName = @"神戸";
locationCode = @"280000";
break;
case "Hiroshima":
locationName = @"広島";
locationCode = @"340000";
break;
case "Fukuoka":
locationName = @"福岡";
locationCode = @"400000";
break;
case "Naha":
locationName = @"那覇";
locationCode = @"471000";
break;
default:
locationCode = "";
break;
}
string message = string.Empty;
if (locationCode == "")
{
message = locationName + @"の天気を調べることができませんでした。";
}
else
{
string url = "https://www.jma.go.jp/bosai/forecast/data/forecast/" + locationCode + ".json";
try
{
var httpClient = new HttpClient();
var weathersResponse = await httpClient.GetAsync(url);
var weathersJson = weathersResponse.Content.ReadAsStringAsync().Result;
List<Weather> weathers = JsonConvert.DeserializeObject<List<Weather>>(weathersJson);
string weather = weathers[0].timeSeries[0].areas[0].weathers[0].Replace(" ", "");
double mintemp = weathers[0].timeSeries[2].areas[0].temps[0];
double maxtemp = weathers[0].timeSeries[2].areas[0].temps[1];
message = locationName + @"の天気は" + weather + @"です。";
message += @"最高気温は" + maxtemp.ToString("0") + @"度です。";
if (mintemp != maxtemp)
{
message += @"最低気温は" + mintemp.ToString("0") + @"度、";
}
}
catch
{
message = locationName + @"の天気を調べることができませんでした。";
}
}
return new FunctionResponse(
InstructionPrompt + $"\n\n{message}");
}
private class Weather
{
public string publishingOffice { get; set; }
public DateTime reportDatetime { get; set; }
public List<TimeSeries> timeSeries { get; set; }
}
private class TimeSeries
{
public List<DateTime> TimeDefines { get; set; }
public List<Areas> areas { get; set; }
}
private class Areas
{
public List<string> weathers { get; set; }
public List<double> temps { get; set; }
}
}
}
この記事が気に入ったらサポートをしてみませんか?