Piszemy własnego bota w .NET Core. Część II: tworzymy pogodynkę

Piszemy własnego bota w .NET Core. Część II: tworzymy pogodynkę

Piszemy własnego bota w .NET Core. Część II: tworzymy pogodynkę

W poprzedniej części poradnika udało nam się stworzyć uruchamialnego z linii poleceń bota, który potrafił odpowiedzieć w prosty sposób na Slacku. Były to jednak jedynie proste odpowidzi na nasze zaczepki.

W tej części spróbujemy czegoś bardziej pożytecznego. Nauczymy naszego bota znajdywania nam prognozy pogody.

Tworzymy nowy responder

Aby zachować modularną architekturę naszego rozwiązania, do poszukiwania pogody stwórzmy nowy responder. Tym sposobem będziemy mogli decydować czy ładować go w danej instancji naszego bota czy też nie.

Nowy responder tworzymy podobnie jak SimpleResponder w poprzedniej części: tworzymy nowy plik klasy. Możemy zrobić to w dowolny sposób. Najłatwiej zrobić to w Visual Studio Code:

  • Wybierając opcję New File -> i nazywając nowy plik WeatherResponder.cs
  • Jeśli doinstalowaliśmy plugin do Visual Studio Code o nazwie C# Extensions, możemy od razu stworzyć predefiniowaną klasę:

Wynikiem działania powinna być taka klasa:

Dopiszmy jeszcze dwie linijki na początku pliku:

using System;

using MargieBot;

Następnie zaimplementujmy interfejs, na razie rzucając jedynie wyjątek NotImplementedException. Visual Studio Code zrobi to za nas, gdy klikniemy ikonkę „żarówki“ i wybierzemy opcję Implement Interface.

Zdobywamy dostęp do danych o pogodzie

Czas zadbać o źródło danych o pogodzie. W tym celu udamy się na stronę OpenWeatherMap API, gdzie możemy otrzymać dostęp do API udostępniającego nam dane pogodowe za darmo.

W tym celu rejestrujemy się jako darmowy użytkownik. Wybierzmy opcję „Current weather data“ i kliknijmy „Subscribe“. Następnie w kolumnie „Free“ klikamy „Get API key and Start“. Po zakończeniu tworzenia konta w sekcji „API Keys“ będziemy mieli dostęp do naszego klucza. Skopiujmy go sobie, by wykorzystać później przy tworzeniu obiektu naszej klasy WeatherResponder.

Najpierw jednak przetestujemy działanie klucza. Wpiszmy w przeglądarce taki adres:

http://api.openweathermap.org/data/2.5/weather?q=Szczecin&mode=json&units=metric&APPID=<TUTAJ PODAJEMY SWOJ KLUCZ API>

Naszym oczom powinien ukazać się JSON (typowy format przesyłania danych w sieci), zawierający informcje o bieżącej pogodzie w Szczecinie.

Przyjrzyjmy się jeszcze raz wpisanemu przez nas adresowi i rozłóżmy go na czynniki pierwsze:

  • Po q= podajemy nazwę miasta, którą chcemy przeszukać
  • Po mode= podajemy tryb zwracanych danych – użyjemy tutaj wartości json
  • Po units= podajemy rodzaj zwracanych danych. Metric oznacza że interesują nas jednostki metryczne, czyli wyrażone w stopniach Celsjusza (wiele krajów używa stopni Fahrenheita).
  • W sekcji APPID= podajemy nasz klucz aplikacji, dzięki czemu nie musimy się logować do usługi w żaden inny sposób.

Otrzymany JSON będzie wyglądał mniej więcej tak:

Niesformatowany JSON wygląda dosyć nieczytelnie. Jednak Visual Studio Code to doskonałe narzędzie, aby przyjrzeć się mu w ładniejszej formie. Skopiujmy całość do nowego okna Visual Studio Code i wciśnijmy Shift-Alt-F (lub Shift-Option-F na Macu).

Od razu lepiej, poświęćmy chwilę aby przyjrzeć się, jakie dane pogodowe (i nie tylko), zwraca nam OpenWeatherMap.

Format tych danych będzie zawsze taki sam: zmieniać się będą jedynie wartości. Tego typu założenie nazywamy kontraktem – istnieje kontrakt że endpoint API zwróci nam wartości w określonej formie.

Czas wywołać OpenWeatherMap z naszego bota

Musimy teraz zmodyfikować nasz responder tak aby:

  • odnalazł w naszej wiadomości nazwę miasta, w którym chcemy poznać pogodę,
  • wywołał OpenWeatherMap z odpowiednim URL i odczytał zwracany JSON,
  • zdekodował tekst zwrócony w JSON, by poznać konkretne dane pogodowe,
  • Sformułował odpowiedź i wysłał ją na Slacku.

Do roboty. Musimy wykonać taką samą pracę jaką wykonała przeglądarka, otwierając podany URL i pobierając dane.

Na początku zaplanujmy konstruktor naszej klasy tak, abyśmy musieli podać mu klucz API. Dlaczego? Dzięki temu będziemy mogli używać tej klasy w różnych środowiskach, bez zdradzania naszego klucza.

Następnie zaimplementujemy metodę CanRespond. Sprawdzimy w niej, czy wystąpiło w niej słowo „pogoda“. Wtedy założymy że reszta to nazwa miasta. Czyli przykładowe wywołania naszego bota to: „pogoda Szczecin“, „pogoda Warszawa“ etc. To duże uproszczenie, ale zależy nam tutaj na szybkim efekcie.

public bool CanRespond(ResponseContext context)
{
	return context.Message.Text.ToLower().Contains("pogoda");
}

Teraz musimy sformułować odpowiedź. Odbędzie się to w metodzie GetResponse, identycznie jak w SimpleResponder.

BotMessage response = new BotMessage();

string city = context.Message.Text.Replace("pogoda ", "");

string url = $"http://api.openweathermap.org/data/2.5/weather?q={city}&mode=json&units=metric&APPID={ApiKey}";

response.Text = "Szukales pogody w miescie: " + city;

string pogoda = String.Empty;

using (HttpClient client = new HttpClient())
{
    string json = RetrieveJsonAsync(url, client).Result;
    dynamic jsonData = JObject.Parse(json);
    pogoda = $"Temperatura w tym mieście to {jsonData.main.temp} stopni Celsjusza";
}

response.Text = response.Text + Environment.NewLine + pogoda;

return response;

Próba kompilacji wskaże błędy. Brakuje nam pakietów, w których znajduje się:

  • HttpClient – obiekt do pobierania danych z sieci,
  • Metody RetrieveJsonAsync, która pomoże nam „zaczekać“ na asynchroniczne pobranie,
  • Obiektu JObject, służącego to wczytywania i analizowania danych JSON, znajdującego się w znanym open source’owym pakiecie Newtonsoft.

Pierwszy problem naprawimy dodając w sekcji using using System.Net.Http;

Drugi z problemów – poprzez zdefiniowanie potrzebnej metody:

private async Task<string> RetrieveJsonAsync(string url, HttpClient client)
{
	string result = await client.GetStringAsync(url);
	return result;
}

Dopisujemy using System.Threading.Tasks; w sekcji using.

Trzeci z problemów zaś pozwolimy naprawić Visual Studio Code. Obok błędu w linii z JObject znajduje się ikona żarówki – wybieramy dodanie using Newtonsoft.Json.Linq; do sekcji using.

Teraz musimy jeszcze dodać naszego respondera w czasie uruchamiania bota, podając mu klucz aplikacji z OpenWeatherMap. W tym celu przez Console.Read() dopisujemy linijkę:

myBot.Responders.Add(new WeatherResponder("<tutaj klucz API OpenWeather>"));

Uruchamiamy naszego bota i testujemy.

Działa… ale szybko zauważymy, że bot sprawia problemy – gdy wpiszemy nazwę miasta, którego nie mógł znaleźć, wyrzuca błąd – który uniemożliwia dalszą rozmowę. Usprawnienie go (np. użycie klauzuli try…catch…finally) pozostawiam czytelnikom! Możemy się pokusić również o poinformowanie użytkownika, że wystąpił błąd.

W kolejnej części spróbujemy użyć naszego chatbota do funkcji, z którą kojarzymy sztuczną inteligencję. Połączymy się z dostępnymi usługami AI i wykorzystamy je w funkcjonalności bota.

Musisz przeczytać:

Dołącz do dyskusji