Piszemy własnego bota w .NET Core, część I

Piszemy własnego bota w .NET Core, część I

Piszemy własnego bota w .NET Core, część I

Słowo bot jest skrótem od słowa robot. Jeśli kojarzy wam się z naszą swojską „robotą” – słusznie. Termin ten bowiem pochodzi z języka czeskiego. Pierwszy raz użył go pisarz Karel Capek w opublikowanej w 1920 r. sztuce R.U.R.

Prawdziwym pomysłodawcą słowa był co prawda brat Karela, Josef, a roboty przedstawione w sztuce są żywymi istotami – specjalnymi wersjami człowieka przeznaczonymi do ciężkiej pracy. Mimo to w zbiorowej świadomości do właśnie Capek jest twórcą postaci mechanicznego robota.

W rzeczywistości ludzkość marzyła o mechanicznych pomocnikach od tysięcy lat i ponoć nie raz już te marzenia realizowano. Liczne są legendy o mechanicznych sługach czy golemach. Podobno Talos był olbrzymim mechanicznym wojownikiem, który patrolował wody morskie wokół Krety i chronił ją przed piratami.

Bot software’owy

Dziś zajmiemy się bliżej botem software’owym – a nawet spróbujemy sami takiego napisać. Bot taki to program lub serwis, który potrafi uczestniczyć w konwersacji z człowiekiem. Możemy się z nim porozumiewać tekstowo przez Skype’a, Slacka, Messengera lub głosowo, tak jak z Asystentem Google bądź z Siri w iPhonie.

Tego typu boty mogą być przyszłością tego, w jaki sposób wchodzimy w interakcję z oprogramowaniem. Wypełnianie formularzy i wybieranie opcji zostanie zastąpione rozmową, w trakcie której powiemy rozumiejącemu kontekst asystentowi, o co nam chodzi.

Od strony oprogramowania możemy wyróżnić wspólny wzorzec ich pisania:

  • Piszemy tzw. reakcje na zachodzące zdarzenia
  • Architektura pluginowa (wtyczkowa) pozwala na pisanie tzw. responderów (widać to szczególnie dobrze w Asystencie Google i Aleksie, gdzie każdy może rozszerzyć możliwości asystenta)

Wybór technologii

W celu przedstawienia przykładu tego, jak możemy napisać własnego bota, wybrałem framework .NET Core i język C#. Zrobiłem to ze względu na jego dostępność, multiplatformowość, lekkość i prostotę. Zadziała wszędzie i nie wymaga dużo ściągania. .NET Core SDK instalujemy stąd.

Jako edytor i IDE mogę polecić Visual Studio Code, do pobrania stąd. Możemy też obyć się bez tego i pisać w jakimkolwiek edytorze tekstowym.

Instalując .NET Core, uzyskujemy dostęp do polecenia dotnet, które służy do budowania i uruchamiania naszych aplikacji.

Co musisz wiedzieć, aby zacząć

Aby przejść zamieszczoną tutaj lekcję, powinieneś:

  • Znać trochę programowanie i języki obiektowe (rozumieć mniej więcej, gdzie jest klasa, a gdzie metoda…)
  • Umieć zainstalować i skonfigurować program (Windows, MacOS bądź Linux – .NET Core jest multiplatformowy)
  • Potrafić pracować z linii poleceń – np. założyć folder i przejść do niego
  • Umieć zarządzać stworzoną grupą (zespołem) na Slacku

Wszystkie przykłady można uruchomić na Linuksie, MacOS lub Windows.

Zaczynamy

Aby stworzyć nowy projekt w technologii .NET Core, zakładamy nowy katalog, przechodzimy do niego (wszystko to wykonujemy z linii poleceń). Nie musimy być administratorem.

Następnie wpisujemy w linii poleceń:

dotnet new console

Tworzy to w bieżącym katalogu nowy projekt .NET Core oparty o szablon aplikacji linii poleceń (tzw. konsolowej). To standardowy programik typu „Hello World“.

Możemy go następnie uruchomić poleceniem:

dotnet run

Jeśli chcemy edytować pliki za pomocą wygodnego edytora, możemy w bieżącym katalogu wywołać Visual Studio Code za pomocą polecenia

code .

Co ja paczę – składnia C#

Nowo stworzony program składa się w tej chwili jedynie z jednego pliku Program.cs. Przypomnijmy sobie podstawowe pojęcia związane ze składnią języki C# na poniższym screenshocie.

Najważniejsze w tym pliku to:

  • Sekcja using – zawierająca informacje, jakie przestrzenie nazw importujemy do naszego projektu.
  • Sekcja namespace – zawierająca przestrzeń nazw naszego kodu – framework stworzył go domyślnie na podstawie nazwy folderu
  • Sekcja class – tu definiujemy klasę. Ze względu na to, że jest to specjalny przypadek – aplikacja linii poleceń, została stworzona klasa Program, służąca do uruchamiania takich programów
  • Metoda Main – jak w wielu innych językach programowania, ta metoda jest tzw. punktem wejścia – jest automatycznie wywołana przez framework poleceniem run. Jak widzimy, Main ma również parametry – w tablicy args otrzymamy parametry z linii poleceń.

Aby w łatwy sposób oprogramować bota dla Slacka, użyjemy biblioteki open source MargieBot. Ponieważ jest ona dostępna w katalogu NuGet, wystarczy, że napiszemy w linii poleceń:

dotnet add package MargieBot

Jeśli zajrzymy to pliku .csproj w naszym projekcie, zauważymy, że odpowiednia referencja została dodana do tego pliku.

Nowo dodana biblioteka odnosi się do kilku innych, musimy rozwiązać te referencje przez wywołanie

dotnet restore

Można również wcisnąć odpowiedni przycisk w Visual Studio Code, który wywoła to polecenie za nas.

Przygotowanie Slacka

Naszego bota możemy podpiąć do każdego istniejącego zespołu Slack. Ja w tym celu założyłem nowy zespół w Slacku.

Aby umożliwić naszemu botowi uczestniczenie w dyskusjach, musimy dodać go w panelu administracyjnym.

Wybieramy Administration -> Manage apps, aby wejść do odpowiedniego panelu.

Następnie wchodzimy w Custom integrations i widzimy sekcję Bots.

Klikamy w opcje nowego bota i jesteśmy w stanie skonfigurować jego nazwę, ikonę, oraz ustawić kilka innych opcji. Najbardziej jednak interesuje nas informacja zawarta w polu API Token. Właśnie tego ciągu znaków będziemy potrzebowali, aby nasz bot odnalazł odpowiednią instalację Slacka. Skopiujmy go.

Następnie możemy dodać naszego nowego bota, używając jego nazwy, do kanału -podobnie jak zwykłego użytkownika.

Przygotowanie podstawowego bota za pomocą biblioteki MargieBot

Po skonfigurowaniu Slacka wracamy do naszego programu.

W pliku Program.cs dodajemy polecenie using (poniżej istniejących), mówiące o użyciu przestrzeni nazw biblioteki MargieBot:

using MargieBot;

Kasujemy istniejące w metodzie Main wywołanie Console.WriteLine i dopisujemy:

Bot myBot = new Bot();

myBot.Connect("<tutaj wstawiamy klucz API Slacka>");

Console.Read();

Ostatnie polecenie ma na celu zatrzymanie akcji programu i zapobieżenie wyjściu z niego. Należy traktować takie rozwiązanie jako tymczasowe.

Uruchamiamy nasz program poleceniem

dotnet run

Bądź wybraniem w Visual Studio Code polecenia Debug -> Start Debugging. Domyślnie możemy również wcisnąć F5.

Pozostawiając program uruchomiony, zalogujmy się do naszego Slacka. Zobaczymy, że w sekcji Aplikacji pojawił się aktywny (z zieloną kropką) bot o zdefiniowanej przez nas nazwie. Pierwsze koty za płoty.

Spróbujmy do niego napisać:

Jak widzimy w uruchomionym programie, otrzymaliśmy wiadomość:

Wiadomość otrzymamy niezależnie od tego, czy była to wiadomość prywatna, czy tzw. mention, czyli napisanie na kanale #general bądź innym @nazwabota, np. „@nazwabota cześć kolego”.

Wychodzimy z programu za pomocą Ctrl-C (linia poleceń), bądź klikając „Stop Debugging“ (Visual Studio Code). Wracając do Slacka, zauważymy, że kropka przy nazwie bota stała się szara.

Uczymy bota nowych rzeczy

Udało nam się uruchomić bota i otrzymać powiadomienie o otrzymanych wiadomościach. Użyliśmy do tego infrastruktury popularnego programu Slack. Czas teraz nauczyć go czegoś pożytecznego.

Programowanie najprostszych odpowiedzi bota

Na początku dodajmy zwykłą reakcję na słowo kluczowe. Jest to podstawowa zdolność, która jest używana również przez boty różnych przedsiębiorstw, jak i np. Siri.

Użyjemy w tym celu funkcji dostarczonych wraz z biblioteką MargieBot. Musimy użyć funkcji udostępnionej przez obiekt Bot z tej biblioteki RespondsTo().With() Ważne: funkcja ta zwraca ten sam obiekt, co umożliwia ich łączenie w łańcuchy.

Przykładowo, możemy spróbować odpowiedzieć na łańcuch „kawa“.

myBot.RespondsTo("kawa").With("ze śmietanką czy bez").With("espresso raz").With("zapraszam na filiżankę");

Od tej chwili nasz bot zareaguje na słowo „kawa“ za pomocą jednej ze zdefiniowanych odpowiedzi. Uruchamiamy go ponownie („dotnet run“).

Programowanie bardziej złożonych odpowiedzi

Aby móc oprogramować bardziej skomplikowaną logikę, musimy stworzyć klasę, która implementuje interfejs IResponder udostępniony przez bibliotekę MargieBot. Stwórzmy nowy plik SimpleResponder.cs

Możemy to zrobić wybierając New File w Visual Studio Code (lub, jeśli mamy zainstalowany dodatek „C# Extensions“, od razu stworzyć plik nowej klasy).

Metodę CanRespond implementujemy tak, aby pozwoliła nam zdecydować, czy mamy uruchomić logikę danego „respondera“. Załóżmy że chcemy napisać taki, który odpowiada na pozdrowienie „Hello“. Wskazujemy interfejs do implementacji, podając jego nazwę po dwukropku.

Ważniejsza jest metoda GetResponse, która umożliwia stworzenie nam odpowiedzi, za pomocą stworzenia i zwrócenia obiektu typu BotMessage.

Samo stworzenie nowej klasy nie wystarczy, musimy jeszcze przekazać obiekt tego typu do naszego bota. Wracamy do metody Main().

myBot.Responders.Add(new SimpleResponder());

Jak widzimy, Responders to kolekcja. Oznacza to, że możemy mieć dowolną liczbę responderów działających w jednym bocie. Zamierzamy to wykorzystać, ale najpierw – wypróbujmy nową funkcję bota. Uruchommy go, a następnie napiszmy do niego tekst zawierający słowo “hello”.

Uczymy naszego bota nowych sztuczek

W kolejnej części artykułu stworzymy nowy responder, który będzie potrafił odpowiedzieć na pytania związane z pogodą w podanym mieście. Wykorzystamy tę okazję, aby pokazać, jak połączyć się z publicznym interfejsem REST podającym nam dane. Gdy to nam się uda, kolejną rzeczą, jakiej nauczymy naszego bota, będzie funkcja, którą rzeczywiście można nazwać sztuczną inteligencją…

Dołącz do dyskusji