見出し画像

「AIしげちゃん」の天気予報機能

Unityプロジェクトを破損してしまって、ChatdollKit v0.6.6 で再構築中の「AIしげちゃん」ですが、破損前のバージョンで GPTのFunction Callingを使って実装していた、以下の機能を復活させているところです。

  1. 気象庁の気象情報APIを利用し、指定した地域の天気予報を答える

  2. 環境センサーと連携し、温湿度の値や不快指数等を答える

  3. スマートリモコンと連携し、部屋の照明や家電製品を制御する

まず始めは、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; }
        }
    }
}

この記事が気に入ったらサポートをしてみませんか?