W ostatnim wpisie omówiłem podstawy działania Bot Connectora. Wspomniałem między innymi o tym, że nasz kod sprowadza się tak naprawdę do obsługi zapytań HTTP POST z usługi Bot Connector oraz generowania zapytań do tejże usługi celem wysłania odpowiedzi. Dzisiaj przyjrzymy się jak to wygląda w praktyce.
Szablon dla Visual Studio
Zanim zaczniemy, musimy pobrać szablon z gotową aplikacją dla Bot Connectora – klikamy tutaj i zapisujemy pobrany plik w katalogu %USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C# (dla Visual Studio 2015). Przed całą operacją polecam też zainstalowanie wszystkich aktualizacji do Visual Studio.
Po pobraniu szablonu tworzymy nowy projekt typu Bot Application:
Co zawiera ten szablon projektu?
Krótko mówiąc jest to standardowa aplikacja ASP.NET Web Api. To co ją wyróżnia od domyślnego szablonu to przykładowy kontroler MessagesController oraz dodatkowe ustawienia w pliku Web.config:
<appSettings> <!-- update these with your BotId, Microsoft App Id and your Microsoft App Password--> <add key="BotId" value="YourBotId" /> <add key="MicrosoftAppId" value="" /> <add key="MicrosoftAppPassword" value="" /> </appSettings>
Ustawienia te posłużą nam w przyszłości do uwierzytelniania naszego bota w usłudze Bot Connector. Wracając jednak do serca projektu, przyjrzyjmy się co zawiera MessagesController:
[BotAuthentication] public class MessagesController : ApiController { /// <summary> /// POST: api/Messages /// Receive a message from a user and reply to it /// </summary> public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl)); // calculate something for us to return int length = (activity.Text ?? string.Empty).Length; // return our reply to the user Activity reply = activity.CreateReply($"You sent {activity.Text} which was {length} characters"); await connector.Conversations.ReplyToActivityAsync(reply); } else { HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; } private Activity HandleSystemMessage(Activity message) { if (message.Type == ActivityTypes.DeleteUserData) { // Implement user deletion here // If we handle user deletion, return a real message } else if (message.Type == ActivityTypes.ConversationUpdate) { // Handle conversation state changes, like members being added and removed // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info // Not available in all channels } else if (message.Type == ActivityTypes.ContactRelationUpdate) { // Handle add/remove from contact lists // Activity.From + Activity.Action represent what happened } else if (message.Type == ActivityTypes.Typing) { // Handle knowing tha the user is typing } else if (message.Type == ActivityTypes.Ping) { } return null; } }
Domyślny kod szablonu nie jest może najładniejszy, ale jest bardzo ładnie skomentowany, więc od razu wiadomo co do czego służy. Zwrócę jednak uwagę na kilka rzeczy.
Autoryzacja
W pierwszej linijce widzimy atrybut BotAuthentication. Służy on do uwierzytelniania BotConnectora w ramach naszego kodu – do tego potrzebujemy ustawić wspomniane wcześniej parametry w Web.config. Więcej o procesie uwierzytelniania i autoryzacji poczytacie w dokumentacji BotConnectora.
Rozpoznawanie typu aktywności
Opisywana metoda HTTP POST jest „bramką” dla wszystkich wywołań z Bot Connectora, toteż istotne jest, aby w pierwszym kroku stwierdzić, jakiego typu aktywność otrzymaliśmy.
W ramach BotConnectora mamy do czynienia z następującymi aktywnościami:
- Message – podstawowa aktywność, z którą będziemy mieć najwięcej do czynienia – zawiera wiadomość od użytkownika.
- DeleteUserData – Bot Framework pozwala użytkownikowi na wyczyszczenie swoich danych – wystarczy, że użytkownik wpisze /deleteprofile (w niektórych kanałach trzeba to poprzedzić spacją) a bot otrzyma aktywność typu DeleteUserData. W ramach obsługi tej aktywności powinniśmy wyczyścić dane skojarzone z użytkownikiem, od którego ta wiadomość przyszła. Funkcjonalność ta jest szczególnie przydatna w trakcie testów, gdyż pozwala na łatwe wyzerowanie stanu użytkownika.
- ConversationUpdate – aktywność używana do powiadomienia bota o przyłączeniu lub odłączeniu się użytkowników od danej konwersacji lub też (o ile kanał obsługuje) o zmianie tematu konwersacji. W praktyce aktywność tę możemy wykorzystać np. do przywitania użytkownika lub reakcji na zmianę tematu.
- ContactRelationUpdate – aktywność odpowiada za powiadomienie bota o tym, że ktoś go dodał lub usunął z listy kontaktów. Tutaj też możemy implementować rzeczy typu przywitanie użytkownika.
- Typing – niektóre kanały obsługują notyfikacje o tym, że ktoś jest w trakcie pisania. Aktywność Typing służy do powiadamiania o tym fakcie.
- Ping – testowa aktywność, którą Bot Connector może wysłać do naszego bota. W praktyce nie ma potrzeby obsługiwania tej aktywności.
Poza powyższymi, dostępnymi od razu w szablonie, Bot Connector w najnowszej wersji (3.5.5 w momencie pisania) oferuje także aktywność typu Event (dawniej Trigger), która służy do powiadamiania bota o zdarzeniach np. z zewnętrznych aplikacji za pośrednictwem Bot Connectora.
Generowanie odpowiedzi
Ostatnią rzeczą, którą chciałbym poruszyć w dzisiejszym wpisie jest wysyłanie odpowiedzi do użytkownika. Wysłanie odpowiedzi realizuje następujący kod:
var connector = new ConnectorClient(new Uri(activity.ServiceUrl)); var reply = activity.CreateReply($"You said: {activity.Text}"); await connector.Conversations.ReplyToActivityAsync(reply);
Powyższy kod wywołany w odpowiedzi na activity typu Message da nam prostego echo-bota, który odpisze dokładnie to co mu napisaliśmy.
W pierwszej linii tworzymy obiekt ConnectorClient przekazując mu adres Bot Connectora otrzymany w ramach activity – nie hardcodujemy go, aby możliwe było działanie także na emulatorze, poza tym nie wiemy z jakiego adresu nastąpiło wywołanie ze strony Bot Connectora. Druga linia tworzy odpowiedź na bazie otrzymanej activity – w praktyce podmienia identyfikatory nadawcy i odbiorcy, a zostawia identyfikator konwersacji oraz kanału. Ostatnia linia wysyła odpowiedź do Bot Connectora.
Bot Connector następnie zajmuje się dostarczeniem odpowiedzi do danego użytkownika na wskazanym kanale. I tak oto działa nasz bot :)
W następnych częściach…
…przejdziemy do BotBuildera i przyjrzenia się ficzerom jakie oferuje, w szczególności skupię się na systemie dialogów.
Aby nie przegapić kolejnych wpisów zapraszam do śledzenia tego bloga, czy to przez kanał RSS, czy też poprzez stronę na Facebooku.
Dodaj komentarz