Warning: Declaration of Jetpack_IXR_Client::query() should be compatible with IXR_Client::query(...$args) in /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php on line 122

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723

Warning: Cannot modify header information - headers already sent by (output started at /www/htdocs/v103323/continuous-intelligence/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php:122) in /www/htdocs/v103323/continuous-intelligence/wp-includes/rest-api/class-wp-rest-server.php on line 1723
{"id":134,"date":"2018-11-02T00:03:24","date_gmt":"2018-11-01T22:03:24","guid":{"rendered":"https:\/\/www.continuous-intelligence.de\/?p=134"},"modified":"2018-11-02T00:03:24","modified_gmt":"2018-11-01T22:03:24","slug":"sql-saturday-772-metalbot-erste-schritte-im-bot-framework","status":"publish","type":"post","link":"https:\/\/www.continuous-intelligence.de\/2018\/11\/02\/sql-saturday-772-metalbot-erste-schritte-im-bot-framework\/","title":{"rendered":"SQL Saturday #772 MetalBot \u2013 erste Schritte im Bot Framework"},"content":{"rendered":"

Bots sind eine spannende Erg\u00e4nzung zur Arbeit mit Daten in Unternehmen und er\u00f6ffnen den Mitarbeitern neue Wege, um mit Daten zu interagieren und sich Informationen zu beschaffen. Nachdem ich mich in den letzten Monaten einige Male mit dem Microsoft Bot SDK (link<\/a>) besch\u00e4ftigen durfte, habe ich mich auf der Bahnfahrt zum SQL Saturday in M\u00fcnchen spontan entschieden, f\u00fcr die Session mit Frank Geisler (twitter<\/a>\/www<\/a>), einen Bot zu programmieren und vorzustellen.<\/p>\n

Unser Bot, der MetalBot erf\u00fcllt nur eine einzige Aufgabe, n\u00e4mlich den User nach einem Bild seines Lieblingsgetr\u00e4nks zu fragen und basierend auf einem hochgeladenen Bild eines Getr\u00e4nks eine Empfehlung auszusprechen, welche Band der User als n\u00e4chstes h\u00f6ren sollte.<\/p>\n

F\u00fcr Eilige: wenn ihr die Session gesehen habt oder nicht an den Erkl\u00e4rungen interessiert seid sondern nur zum Quellcode m\u00f6chtet, dann begebt euch bitte hier<\/a> direkt zum Quellcode des Bots.<\/p>\n

Gundelegende Konzepte im BOT SDK<\/h2>\n

Sehen wir uns zun\u00e4chst einige grundlegende Konzepte des Bot Frameworks an. Grunds\u00e4tzlich kommunizieren Clients nicht direkt mit eurem Bot sondern mit einem Bot Service Framework, dieses Service Framework „spricht “ wiederum \u00fcber REST Calls mit eurem Bot. Das hei\u00dft einerseits m\u00fcsst ihr f\u00fcr euren Bot nicht Konnektoren zu verschiedenen Kan\u00e4len implementieren, da das Microsoft bereits f\u00fcr euch \u00fcbernommen hat, andererseits habt ihr klar definierte Schnittstellen \u00fcber die euer Bot kommuniziert.<\/p>\n

Was macht das Framework mit Nachrichten?<\/h3>\n

Im Bot Framework gibt es nun einen ganzen Stack, der die Nachrichten verarbeitet, bevor sie euren Bot erreichen. Der Stack zur Kommunikation wird in der Dokumentation von Microsoft<\/a> erkl\u00e4rt.<\/p>\n

\"\"<\/a>
Abbildung 1: Die Kommunikation im Bot Framework<\/figcaption><\/figure>\n
    \n
  1. Der Benutzer schickt mit seinem Client eine Nachricht an den Bot Framework Service.<\/li>\n
  2. Der Bot Framework Service macht daraus einen HTTP POST mit der Nachricht und weiteren Informationen zur Benutzeraktivit\u00e4t als JSON Objekt im Payload.<\/li>\n
  3. Dieser POST Request wird an einen Webserver weitergereicht. Dort wird er in ein Activity-Objekt des Bot SDKs umgewandelt.<\/li>\n
  4. Es wird die „process activity“-Methode eines Adapters in der Middleware aufgerufen, dem das Activity-Objekt \u00fcbergeben wird.<\/li>\n
  5. Der Adapter erzeugt ein Turn Context-Objekt, das an die Middleware \u00fcbergeben wird, die es an den Bot weiterreicht.<\/li>\n
  6. Der Bot prozessiert den Turn Context und sendet eine Antwort an die Middleware.<\/li>\n
  7. Die Middleware reicht die Antwort an den Framework Service weiter, der sie wiederum an den User kommuniziert.<\/li>\n
  8. Es werden Acknowledgement-Nachrichten vom Framework Service an die Middleware und von dort zum Bot und zur\u00fcck \u00fcber Middleware, Webserver zum Franework Service gereicht. Diese dienen dazu, auch auf Ereignisse wie das Zustellen von Nachrichten reagieren zu k\u00f6nnen, sind hier aber nicht weiter von Bedeutung.<\/li>\n<\/ol>\n

    Es gibt zahlreiche M\u00f6glichkeiten, in einzelne Schritte dieses Prozesses einzugreifen. Diese sind in der Dokumentation des Bot Frameworks zu finden. Sie erm\u00f6glichen es beispielsweise mittels dependency injection in der Middleware den Kontext anzureichern und so weitere Informationen an die Nachrichten anzuh\u00e4ngen.<\/p>\n

    Im Bot selber greifen folgende Konzepte:<\/p>\n

    Connector<\/h3>\n

    Die Connector Library im Bot SDK erm\u00f6glicht den Zugriff auf den Connector im Bot Framework Service, der die Nachrichten vom Kanal zum Bot und vom Bot zum Kanal weiterreicht.<\/p>\n

    Activity<\/h3>\n

    Das Activity-Objekt ist das zentrale Objekt der Kommunikation und wird vom Connector verwendet, um Informationen vom und zum User an die Middleware und den Bot weiterzureichen. Die meisten Activity-Objekte sind Nachrichten, es kann aber auch andere Aktivit\u00e4ten geben.<\/p>\n

    Dialog<\/h3>\n

    Dialoge sind die Objekte, die den Ablauf einer Konversation steuern. Es k\u00f6nnen (und werden normalerweise) mehrere Dialoge implementiert werden, die sich auch gegenseitig aufrufen k\u00f6nnen. Dialoge sind die zentralen Objekte, die ihr in Bot-Projekten \u00fcblicherweise anpasst und erzeugt.<\/p>\n

    Form Flow<\/h3>\n

    Form Flow kann in Bots verwendet werden, um die Informationserhebung zu steuern. Form Flow ist hilfreich, wenn es darum geht, dass \u2013 \u00e4hnlich einem Formular \u2013 mehrere Informationen erfasst werden m\u00fcssen, um eine Eingabe abzuschlie\u00dfen.<\/p>\n

    State<\/h3>\n

    Im Bot Builder Framework kann der Status einer Konversation \u00fcber ein State-Objekt organisiert werden. Im State-Objekt sind beispielsweise vorherige Interaktion mit dem User gespeichert oder auch der Benutzer-Name, wenn ihr User pers\u00f6nlich begr\u00fc\u00dfen m\u00f6chtet.<\/p>\n

    Implementierungsdetails<\/h2>\n
    \"\"<\/a>
    Abbildung 2: Die gesamte Solution<\/figcaption><\/figure>\n

    Um einige dieser Konzepte in Aktion zu erleben, sehen wir uns nun an, wie unser Metal-Bot implementiert ist.<\/p>\n

    Unser Metal-Bot ist ziemlich einfach gestrickt, er erf\u00fcllt nur eine einzige Aufgabe und wir haben auch das Error-Handling und den Kommunikations-Ablauf auf ein Minimum reduziert.<\/p>\n

    Deshalb gibt es auch nur drei Klassen, die bei der Implementierung von Interesse sind (also f\u00fcr die Funktionalit\u00e4t genau genommen sogar nur 2 Klassen, die dritte Klasse, den MessagesController, fassen wir nur f\u00fcr ein kleines Gimmick an).<\/p>\n

    Die Klassen, in denen f\u00fcr den ersten Bot Code geschrieben werden muss sind die RootDialog Klasse enthalten in RootDialog.cs\u00a0 und eine Hilfsklasse namens MessageUtil in der entsprechenden .cs-Datei.<\/p>\n

    Zus\u00e4tzlich haben wir noch im MessagesController eine kleine \u00c4nderung vorgenommen, um die Konversation mit dem Bot etwas „menschlicher“ zu gestalten.<\/p>\n

    Der Root Dialog<\/h3>\n

    Wir verwenden in unserer Applikation nur einen Dialog, dieser ist standardm\u00e4\u00dfig der RootDialog. Wie der Konversations-Fluss f\u00fcr unseren „Bandempfehlungs“-Prozess aussehen sollte, haben wir in Abbildung 3 aufgezeichnet.<\/p>\n

     <\/p>\n

    \"\"<\/a>
    Abbildung 3: Konversationsfluss mit dem Metal-Bot<\/figcaption><\/figure>\n

    Um uns zu merken, wo wir uns gerade in diesem Ablauf befinden (eine Empfehlung k\u00f6nnen wir schlie\u00dflich nicht abgeben ohne vorher das Bild bekommen und analysiert zu haben), haben wir in MessageUtil.cs ein Enum eingef\u00fchrt, das verschiedene Zust\u00e4nde unserer Konversation abbildet:<\/p>\n

    \r\npublic enum State { \r\n  INITIATED, \r\n  IMAGE_TRIGGERED, \r\n  AWAITING_IMAGE, \r\n  GIVING_RECOMMENDATION, \r\n  FINDING_BANDS }\r\n<\/pre>\n

    Die Zust\u00e4nde sind:<\/p>\n