Microsoft Bot Framework .NET Edition Jens Siebert (@jens_siebert) .NET User Group Paderborn, 16. Januar 2018 https://www.slideshare.net/JensSiebert1
Chatbots A chatbot is an application, often available via messaging platforms and using some form of intelligence, that interacts with a user via a conversational user interface (CUI). (Joe Mayo, Programming the Microsoft Bot Framework)
Messaging Platform Chatbots Chatbot Service Service Service AI Service (z.B. NLP) Conversational UI Backend Business Logic User Interface
Messaging Plattformen
Conversational User Interface VoiceUserInterface TextUserInterface Speech Speech Recognition Text Text Natural Language Processing Intent Intent Intent Handling Request Response Intent Handling Text Text Speech Synthesis Speech
Beispiel: UPS Bot auf Skype
Warum sollte ich mich damit beschäftigen? […] as messaging apps have grown to dominate both phones and workplaces, we see conversations with other humans being supplemented by intelligent chatbots. As these platforms improve, they will learn to understand the context and intent of conversations, making interactions more lifelike and therefore more compelling. The explosion of interest in the marketplace and mainstream media leads to a corresponding rise in developer interest […] (ThoughtWorks Technology Radar, Volume 16)
Warum sollte ich mich damit beschäftigen? http://www.businessinsider.de/the-messaging-app-report-2015-11
Warum sollte ich mich damit beschäftigen? https://www.twilio.com/learn/commerce-communications/how-consumers-use-messaging
Warum sollte ich mich damit beschäftigen? https://www.twilio.com/learn/commerce-communications/how-consumers-use-messaging
Warum sollte ich mich damit beschäftigen? https://www.gartner.com/smarterwithgartner/top-trends-in-the-gartner-hype-cycle-for-emerging-technologies-2017/
Anwendungsfälle für Chatbots • E-Commerce • Information • Enterprise Productivity • Intelligent Assistant • IoT
Vorteile und Nachteile • Konversation: CUIs bieten, durch Nutzung geschriebener oder gesprochener Sprache, einen natürlicheren Zugang zu Informationen. • Kontext: Es finden keine Kontextwechsel (z.B. unterschiedliche Bedienparadigmen bei mobilen Apps) statt. • Bereitstellung: Die Bereitstellung eines Chatbots ist für den Anwender transparent. Keine Installation, keine Updates, immer aktuell. • Geräte-unabhängig: Die Interaktion mit dem Chatbot kann mit allen Geräten erfolgen, die von einer Messaging-Plattform unterstützt werden. • Plattform-unabhängig: Die Interaktion mit dem Chatbot kann mit allen Plattformen erfolgen, die von einer Messaging-Plattform unterstützt werden. • Notwendigkeit: Es gibt bereits eine erfolgreiche mobile App für einen Service. Welche Vorteile bringt ein zusätzlicher Chatbot? • Angemessenheit: Ist ein CUI die angemessene Benutzerschnittstelle für einen Service? • Kritikalität: Bietet ein Chatbot die richtige Form der Interaktion für einen Service?
Bot Builder SDK Das Microsoft Bot Framework Bot Builder .NET Bot Builder NodeJS Bot Connector Channels Azure Bot Service Chatbot (ASP.NET/NodeJS) Backend Services AI Services (LUIS)
Das Microsoft Bot Framework Bot Connector Channel Chatbot Backend Service AI Service Activity Route Message Query Query Response Response Response Route Response
Das Microsoft Bot Framework • Bot Connector Client • Messages/Activities • Dialog-Management • Dialog-Framework (FormFlow) • State-Management • GUI-Elemente • Anbindung an AI-Services (LUIS, Cognitive Services)
Quickstart https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart
Quickstart File > New Project > Visual C# > Bot Application
Quickstart • Template: ASP.NET MVC Projekt • NuGet-Pakete: Microsoft.Bot.Builder, Microsoft.Bot.Connector • Es gibt auch NuGet-Pakete für ASP.NET Core (Projekt manuell anlegen)
MessagesController-Klasse public class MessagesController : ApiController { public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { await Conversation.SendAsync(activity, () => new Dialogs.RootDialog()); } else { HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; } […] } ActivityTypes.Message ActivityTypes.ConversationUpdate ActivityTypes.ContactRelationUpdate ActivityTypes.Typing ActivityTypes.Ping ActivityTypes.EndOfConversation ActivityTypes.Trigger ActivityTypes.Event ActivityTypes.Invoke ActivityTypes.DeleteUserData ActivityTypes.InstallationUpdate ActivityTypes.MessageReaction
Bot Framework Emulator https://docs.microsoft.com/en-us/bot-framework/bot-service-debug-emulator
Bot Framework Emulator
RootDialog-Klasse [Serializable] public class RootDialog : IDialog<object> { public Task StartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); return Task.CompletedTask; } private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var activity = await result as Activity; int length = (activity.Text ?? string.Empty).Length; await context.PostAsync($"You sent {activity.Text} which was {length} characters"); context.Wait(MessageReceivedAsync); } }
Dialog-basierte Interaktion [Serializable] public class RootDialog : IDialog<object> { public Task StartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); […] } private async Task MessageReceivedAsync(IDialogContext ctx, IAwaitable<object> result) { var activity = await result as Activity; […] IDialogContext IDialogStackIBotContext Suspended Resumed StartedStartAsync() ctx.Wait() ctx.Wait() await result as Activity ctx.Done()
Dialog-basierte Interaktion RootDialog SearchOptions Dialog EventSelection Dialog EventDetails Dialog EventRegistration Dialog ProfileCreation Dialog […] […] search register create
Dialog-basierte Interaktion public Task StartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); […] } private Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var options = new[] { "Search for Events", "Register for Event", „Create Profile" }; PromptDialog.Choice( options: options, resume: ResumeAfterChoiceAsync, […]); […] } private async Task ResumeAfterChoiceAsync(IDialogContext context, IAwaitable<string> result) { […] PromptDialog.Choice( resume: ResumeAfterSearchChoiceAsync, […]); } […] PromptDialog.Attachment PromptDialog.Choice PromptDialog.Confirm PromptDialog.Number PromptDialog.Text
Der Dialog-Stack DialogStack RootDialog new RootDialog() DialogStack RootDialog SearchDialog ctx.Call( new SearchDialog(),…) DialogStack RootDialog SearchDialog ctx.Done(result)
Der Dialog-Stack public class RootDialogStack : IDialog<object> { […] private async Task ResumeAfterChoiceAsync(IDialogContext context, IAwaitable<string> result) { […] if (choice.ToLower().StartsWith("search")) { context.Call(new SearchDialog(), ResumeAfterSearchDialogAsync); } […] } private async Task ResumeAfterSearchDialogAsync(IDialogContext context, IAwaitable<int> result) { […] } […] } public class SearchDialog : IDialog<int> { […] context.Done(result); […] } IDialog<out TResult>
Der Dialog-Stack DialogStack RootDialog SearchDialog ctx.Call( new SearchDialog(),…) DialogStack RootDialog SearchDialog DialogStack RootDialog SearchDialog ctx.Done(result) RegDialog ctx.Forward( new RegDialog(), eventId,…) RegDialog ctx.Done(result) IDialogStack.Wait IDialogStack.Call IDialogStack.Forward IDialogStack.Done IDialogStack.Fail IDialogStack.Reset Weitere interessante Themen: Dialog-Chaining, Scorables
Deklarative Dialog-Programmierung Enter first name Enter last name Enter e-mail Enter company name back() back() back() quit() quit() quit() quit() help() reset() status() switch() ?
FormFlow [Serializable] public class ProfileDialogFormFlow { [Prompt("Please enter your {&}.")] public string FirstName { get; set; } [Prompt("Please enter your {&}.")] public string LastName { get; set; } [Describe("E-Mail")] [Prompt("Please enter your {&}.")] [Pattern(@".+@.+..+")] public string EMail { get; set; } [Describe("Company Name")] [Prompt("Please enter your {&}. (Current value: "{}")")] [Optional] public string Company { get; set; } public IForm<ProfileDialogFormFlow> BuildForm() { return new FormBuilder<ProfileDialogFormFlow>() .Message("Create a new profile...") .OnCompletion(ResumeAfterProfileCreationAsync) .Build(); } […] } reflection
Dialoge erweitern mit UI-Elementen
Message Attachments & Rich Cards • Animation Card • Audio Card • Video Card • Hero Card • Thumbnail Card • Receipt Card • SignIn Card • Adaptive Card Message Attachment Rich Card Media Entity Speech
Adaptive Cards var adaptiveCard = new AdaptiveCard(); adaptiveCard.Body.Add(new TextBlock() { Text = $"### {eventDetails.Name}", }); adaptiveCard.Body.Add(new TextBlock() { Text = converter.Convert(eventDetails.ShortDescription) }); adaptiveCard.Body.Add(new Image() { Url = $"https://dev.virtualearth.net/REST/v1/Imagery/Map/CanvasLight/{latitude},{longitude}/15? [...], Size = ImageSize.Stretch }); adaptiveCard.Body.Add(new TextBlock() { Text = $"{eventLocation.Name}, {eventLocation.Street}, {eventLocation.PLZ} {eventLocation.City}" }); var attachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = adaptiveCard }; message.Attachments.Add(attachment);
Natural Language Processing (NLP) private Task StartAsync(IDialogContext context) { var options = new[] { „All Events", „Upcoming Events", „Past Events" }; PromptDialog.Choice( options: options, resume: ResumeAfterSearchChoiceAsync, […]); […] } private async Task ResumeAfterSearchChoiceAsync(IDialogContext context, IAwaitable<string> result) { string selection = await result; if (selection.ToLower().StartsWith(“upcoming")) { […] } else if (selection.ToLower().StartsWith(“past")) { […] } } […] - „Kommando-artig“ - Keine natürliche Sprache
Language Understanding Intelligent Service https://www.luis.ai Utterances „Show me a list of upcoming events“ Intents „Search“ Entities SearchOptions
Modellierung
Training & Publishing
LUIS Modell im Code einbinden [LuisModel(modelID: "a3caa935-baf8-4e5f-8c3d-…", subscriptionKey: "90f221afa6b4413995e99868a…")] [Serializable] public class SearchDialogLUIS : LuisDialog<int> { [LuisIntent("")] public async Task NoneIntent(IDialogContext context, LuisResult result) { var message = @"Sorry, I didn't get that. […]"; await context.PostAsync(message); context.Wait(MessageReceived); } [LuisIntent("Search")] public async Task SearchIntent(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result) { if (!result.Entities.Any()) { await NoneIntent(context, result); } var entity = result.Entities.First().Entity; […] if (entity.Equals("upcoming")) { […] } […] } }
Azure Bot Service erstellen https://portal.azure.com
Veröffentlichen aus Visual Studio
Testen in Web Chat
Kanäle konfigurieren
Beispiel: DNUGPBBot in Skype
Weitere Themen • State Data Management • Advanced Message Handling • Channel-specific Functionality • Localization • Hand-off to Human • Cortana Skills
Literatur Ausgaben 6/2017-8/2017
Vielen Dank! https://dev.botframework.com https://docs.microsoft.com/bot-framework Slides: https://www.slideshare.net/JensSiebert1 Code: https://bitbucket.org/jenssiebert/dnugpbchatbot Demo-Bot (WebChat): http://dnugpbbot.azurewebsites.net Twitter: @jens_siebert

Microsoft Bot Framework (.NET Edition)

  • 1.
    Microsoft Bot Framework .NETEdition Jens Siebert (@jens_siebert) .NET User Group Paderborn, 16. Januar 2018 https://www.slideshare.net/JensSiebert1
  • 2.
    Chatbots A chatbot isan application, often available via messaging platforms and using some form of intelligence, that interacts with a user via a conversational user interface (CUI). (Joe Mayo, Programming the Microsoft Bot Framework)
  • 3.
    Messaging Platform Chatbots Chatbot Service Service Service AI Service (z.B.NLP) Conversational UI Backend Business Logic User Interface
  • 4.
  • 5.
    Conversational User Interface VoiceUserInterface TextUserInterface Speech Speech Recognition Text Text NaturalLanguage Processing Intent Intent Intent Handling Request Response Intent Handling Text Text Speech Synthesis Speech
  • 6.
  • 7.
    Warum sollte ichmich damit beschäftigen? […] as messaging apps have grown to dominate both phones and workplaces, we see conversations with other humans being supplemented by intelligent chatbots. As these platforms improve, they will learn to understand the context and intent of conversations, making interactions more lifelike and therefore more compelling. The explosion of interest in the marketplace and mainstream media leads to a corresponding rise in developer interest […] (ThoughtWorks Technology Radar, Volume 16)
  • 8.
    Warum sollte ichmich damit beschäftigen? http://www.businessinsider.de/the-messaging-app-report-2015-11
  • 9.
    Warum sollte ichmich damit beschäftigen? https://www.twilio.com/learn/commerce-communications/how-consumers-use-messaging
  • 10.
    Warum sollte ichmich damit beschäftigen? https://www.twilio.com/learn/commerce-communications/how-consumers-use-messaging
  • 11.
    Warum sollte ichmich damit beschäftigen? https://www.gartner.com/smarterwithgartner/top-trends-in-the-gartner-hype-cycle-for-emerging-technologies-2017/
  • 12.
    Anwendungsfälle für Chatbots •E-Commerce • Information • Enterprise Productivity • Intelligent Assistant • IoT
  • 13.
    Vorteile und Nachteile •Konversation: CUIs bieten, durch Nutzung geschriebener oder gesprochener Sprache, einen natürlicheren Zugang zu Informationen. • Kontext: Es finden keine Kontextwechsel (z.B. unterschiedliche Bedienparadigmen bei mobilen Apps) statt. • Bereitstellung: Die Bereitstellung eines Chatbots ist für den Anwender transparent. Keine Installation, keine Updates, immer aktuell. • Geräte-unabhängig: Die Interaktion mit dem Chatbot kann mit allen Geräten erfolgen, die von einer Messaging-Plattform unterstützt werden. • Plattform-unabhängig: Die Interaktion mit dem Chatbot kann mit allen Plattformen erfolgen, die von einer Messaging-Plattform unterstützt werden. • Notwendigkeit: Es gibt bereits eine erfolgreiche mobile App für einen Service. Welche Vorteile bringt ein zusätzlicher Chatbot? • Angemessenheit: Ist ein CUI die angemessene Benutzerschnittstelle für einen Service? • Kritikalität: Bietet ein Chatbot die richtige Form der Interaktion für einen Service?
  • 14.
    Bot Builder SDK DasMicrosoft Bot Framework Bot Builder .NET Bot Builder NodeJS Bot Connector Channels Azure Bot Service Chatbot (ASP.NET/NodeJS) Backend Services AI Services (LUIS)
  • 15.
    Das Microsoft BotFramework Bot Connector Channel Chatbot Backend Service AI Service Activity Route Message Query Query Response Response Response Route Response
  • 16.
    Das Microsoft BotFramework • Bot Connector Client • Messages/Activities • Dialog-Management • Dialog-Framework (FormFlow) • State-Management • GUI-Elemente • Anbindung an AI-Services (LUIS, Cognitive Services)
  • 17.
  • 18.
    Quickstart File > NewProject > Visual C# > Bot Application
  • 19.
    Quickstart • Template: ASP.NETMVC Projekt • NuGet-Pakete: Microsoft.Bot.Builder, Microsoft.Bot.Connector • Es gibt auch NuGet-Pakete für ASP.NET Core (Projekt manuell anlegen)
  • 20.
    MessagesController-Klasse public class MessagesController: ApiController { public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { await Conversation.SendAsync(activity, () => new Dialogs.RootDialog()); } else { HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; } […] } ActivityTypes.Message ActivityTypes.ConversationUpdate ActivityTypes.ContactRelationUpdate ActivityTypes.Typing ActivityTypes.Ping ActivityTypes.EndOfConversation ActivityTypes.Trigger ActivityTypes.Event ActivityTypes.Invoke ActivityTypes.DeleteUserData ActivityTypes.InstallationUpdate ActivityTypes.MessageReaction
  • 21.
  • 22.
  • 23.
    RootDialog-Klasse [Serializable] public class RootDialog: IDialog<object> { public Task StartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); return Task.CompletedTask; } private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var activity = await result as Activity; int length = (activity.Text ?? string.Empty).Length; await context.PostAsync($"You sent {activity.Text} which was {length} characters"); context.Wait(MessageReceivedAsync); } }
  • 24.
    Dialog-basierte Interaktion [Serializable] public classRootDialog : IDialog<object> { public Task StartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); […] } private async Task MessageReceivedAsync(IDialogContext ctx, IAwaitable<object> result) { var activity = await result as Activity; […] IDialogContext IDialogStackIBotContext Suspended Resumed StartedStartAsync() ctx.Wait() ctx.Wait() await result as Activity ctx.Done()
  • 25.
  • 26.
    Dialog-basierte Interaktion public TaskStartAsync(IDialogContext context) { context.Wait(MessageReceivedAsync); […] } private Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var options = new[] { "Search for Events", "Register for Event", „Create Profile" }; PromptDialog.Choice( options: options, resume: ResumeAfterChoiceAsync, […]); […] } private async Task ResumeAfterChoiceAsync(IDialogContext context, IAwaitable<string> result) { […] PromptDialog.Choice( resume: ResumeAfterSearchChoiceAsync, […]); } […] PromptDialog.Attachment PromptDialog.Choice PromptDialog.Confirm PromptDialog.Number PromptDialog.Text
  • 27.
    Der Dialog-Stack DialogStack RootDialog new RootDialog() DialogStack RootDialog SearchDialog ctx.Call( newSearchDialog(),…) DialogStack RootDialog SearchDialog ctx.Done(result)
  • 28.
    Der Dialog-Stack public classRootDialogStack : IDialog<object> { […] private async Task ResumeAfterChoiceAsync(IDialogContext context, IAwaitable<string> result) { […] if (choice.ToLower().StartsWith("search")) { context.Call(new SearchDialog(), ResumeAfterSearchDialogAsync); } […] } private async Task ResumeAfterSearchDialogAsync(IDialogContext context, IAwaitable<int> result) { […] } […] } public class SearchDialog : IDialog<int> { […] context.Done(result); […] } IDialog<out TResult>
  • 29.
    Der Dialog-Stack DialogStack RootDialog SearchDialog ctx.Call( new SearchDialog(),…) DialogStack RootDialog SearchDialog DialogStack RootDialog SearchDialog ctx.Done(result) RegDialog ctx.Forward( newRegDialog(), eventId,…) RegDialog ctx.Done(result) IDialogStack.Wait IDialogStack.Call IDialogStack.Forward IDialogStack.Done IDialogStack.Fail IDialogStack.Reset Weitere interessante Themen: Dialog-Chaining, Scorables
  • 30.
    Deklarative Dialog-Programmierung Enter firstname Enter last name Enter e-mail Enter company name back() back() back() quit() quit() quit() quit() help() reset() status() switch() ?
  • 31.
    FormFlow [Serializable] public class ProfileDialogFormFlow { [Prompt("Pleaseenter your {&}.")] public string FirstName { get; set; } [Prompt("Please enter your {&}.")] public string LastName { get; set; } [Describe("E-Mail")] [Prompt("Please enter your {&}.")] [Pattern(@".+@.+..+")] public string EMail { get; set; } [Describe("Company Name")] [Prompt("Please enter your {&}. (Current value: "{}")")] [Optional] public string Company { get; set; } public IForm<ProfileDialogFormFlow> BuildForm() { return new FormBuilder<ProfileDialogFormFlow>() .Message("Create a new profile...") .OnCompletion(ResumeAfterProfileCreationAsync) .Build(); } […] } reflection
  • 32.
  • 33.
    Message Attachments &Rich Cards • Animation Card • Audio Card • Video Card • Hero Card • Thumbnail Card • Receipt Card • SignIn Card • Adaptive Card Message Attachment Rich Card Media Entity Speech
  • 34.
    Adaptive Cards var adaptiveCard= new AdaptiveCard(); adaptiveCard.Body.Add(new TextBlock() { Text = $"### {eventDetails.Name}", }); adaptiveCard.Body.Add(new TextBlock() { Text = converter.Convert(eventDetails.ShortDescription) }); adaptiveCard.Body.Add(new Image() { Url = $"https://dev.virtualearth.net/REST/v1/Imagery/Map/CanvasLight/{latitude},{longitude}/15? [...], Size = ImageSize.Stretch }); adaptiveCard.Body.Add(new TextBlock() { Text = $"{eventLocation.Name}, {eventLocation.Street}, {eventLocation.PLZ} {eventLocation.City}" }); var attachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = adaptiveCard }; message.Attachments.Add(attachment);
  • 35.
    Natural Language Processing(NLP) private Task StartAsync(IDialogContext context) { var options = new[] { „All Events", „Upcoming Events", „Past Events" }; PromptDialog.Choice( options: options, resume: ResumeAfterSearchChoiceAsync, […]); […] } private async Task ResumeAfterSearchChoiceAsync(IDialogContext context, IAwaitable<string> result) { string selection = await result; if (selection.ToLower().StartsWith(“upcoming")) { […] } else if (selection.ToLower().StartsWith(“past")) { […] } } […] - „Kommando-artig“ - Keine natürliche Sprache
  • 36.
    Language Understanding IntelligentService https://www.luis.ai Utterances „Show me a list of upcoming events“ Intents „Search“ Entities SearchOptions
  • 37.
  • 38.
  • 39.
    LUIS Modell imCode einbinden [LuisModel(modelID: "a3caa935-baf8-4e5f-8c3d-…", subscriptionKey: "90f221afa6b4413995e99868a…")] [Serializable] public class SearchDialogLUIS : LuisDialog<int> { [LuisIntent("")] public async Task NoneIntent(IDialogContext context, LuisResult result) { var message = @"Sorry, I didn't get that. […]"; await context.PostAsync(message); context.Wait(MessageReceived); } [LuisIntent("Search")] public async Task SearchIntent(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result) { if (!result.Entities.Any()) { await NoneIntent(context, result); } var entity = result.Entities.First().Entity; […] if (entity.Equals("upcoming")) { […] } […] } }
  • 40.
    Azure Bot Serviceerstellen https://portal.azure.com
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
    Weitere Themen • StateData Management • Advanced Message Handling • Channel-specific Functionality • Localization • Hand-off to Human • Cortana Skills
  • 46.
  • 47.
    Vielen Dank! https://dev.botframework.com https://docs.microsoft.com/bot-framework Slides: https://www.slideshare.net/JensSiebert1 Code:https://bitbucket.org/jenssiebert/dnugpbchatbot Demo-Bot (WebChat): http://dnugpbbot.azurewebsites.net Twitter: @jens_siebert