public static async Task Run( [QueueTrigger("sms-received-messages")] dynamic incomingSms, TraceWriter log, ExecutionContext context) { currentContext = context; try { string mobileNumber = incomingSms?.Value?.source_number; BotConversation conversation = await GetConversationByMobileNumber(mobileNumber); if (conversation == null) { await StartNewConversation(incomingSms, log); } else { await PostToConversation(incomingSms, conversation, log); } } catch (Exception e) { log.Info($"Bot Connector Exception: {e.Message}"); DirectLineClient.CancelPendingRequests(); throw new BotConnectorException( "Something went wrong when relaying the message to the bot framework", e); } }
private static async Task <BotConversation> GetConversationByMobileNumber(string mobileNumber) { // TODO: extract this and inject an instance of IBotConversationProvider DocumentCollection collection = await DocumentClient.GetDocumentCollectionAsync(); BotConversation conversation = await DocumentClient.GetItemAsync <BotConversation>(c => c.MobileNumber == mobileNumber); return(conversation); }
public static Conversation ToConversation(this BotConversation botConversation) { return(new Conversation { Id = botConversation.ConversationId, ActivityId = botConversation.ActivityId, TurnId = botConversation.TurnId }); }
private static async Task PostToConversation(dynamic incomingSms, BotConversation conversation, TraceWriter log) { log.Info($"Received response from {incomingSms?.Value?.source_number}"); dynamic from = new ExpandoObject(); from.id = incomingSms?.Value?.source_number; from.name = incomingSms?.Value?.source_number; from.role = null; dynamic channelData = new ExpandoObject(); channelData.NotifyMessage = new NotifyMessage() { Id = incomingSms?.Value?.id, DateReceived = incomingSms?.Value?.date_received, DestinationNumber = incomingSms?.Value?.destination_number, SourceNumber = incomingSms?.Value?.source_number, Message = incomingSms?.Value?.message, Type = "callback", }; var messageContent = new BotConversationMessage() { Type = "message", From = from, Text = incomingSms?.Value?.message, ChannelData = channelData }; var json = JsonConvert.SerializeObject(messageContent); HttpContent content = new StringContent(json); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); HttpResponseMessage postMessageTask = await DirectLineClient.PostAsync($"/v3/directline/conversations/{conversation.ConversationId}/activities", content); if (postMessageTask.IsSuccessStatusCode) { string response = await postMessageTask.Content.ReadAsStringAsync(); dynamic jsonResponse = JsonConvert.DeserializeObject(response); log.Info($"Received response from Bot Client: {jsonResponse.id}"); } else { log.Info($"Could not post conversation. {postMessageTask.StatusCode}: {postMessageTask.ReasonPhrase}"); log.Info($"{JsonConvert.SerializeObject(postMessageTask)}"); } }
public async Task <string> CreateSupplierAsync(BotConversation conversation, string supplierName = null) { supplierName = fixture.Create <string>().Replace("-", ""); var response = await CommandExecutor.ExecuteAndWaitForResponseAsync( conversation, $"#nowyDostawca {supplierName}", fixture.Create <TestUser>()); if (response != $"Nowy dostawca: '{supplierName}'") { throw new OperationFailedException($"Failed to create supplier {supplierName}. Received response: {response}"); } return(supplierName); }
public async Task PickRandomOperatorAsync( BotConversation conversation, string supplierName, TestUser user = null) { user = user ?? fixture.Create <TestUser>(); var response = await CommandExecutor.ExecuteAndWaitForResponseAsync( conversation, $"#losuj {supplierName}", user); if (!response.Contains("Dokonano losowania")) { throw new OperationFailedException( $"Failed to pick random operator. Supplier: {supplierName}, User: {user.Name}. Received response: {response}"); } }
public async Task AddOrderItemAsync( BotConversation conversation, string supplierName, string orderText = null, TestUser user = null) { orderText = orderText ?? fixture.Create <string>(); user = user ?? fixture.Create <TestUser>(); var response = await CommandExecutor.ExecuteAndWaitForResponseAsync( conversation, $"[{supplierName}] {orderText}", user); if (!response.Contains($"'{user.Name}' -> '{supplierName}'")) { throw new OperationFailedException( $"Failed to add order item. Supplier: {supplierName}, User: {user.Name}, Order text: {orderText}. Received response: {response}"); } }
private static async Task StartNewConversation(dynamic incomingSms, TraceWriter log) { log.Info($"Starting new conversation with {incomingSms?.Value?.source_number}"); var content = new StringContent(string.Empty); var startConversationTask = await DirectLineClient.PostAsync("/v3/directline/conversations", content); var conversation = new BotConversation(); if (startConversationTask.IsSuccessStatusCode) { string response = await startConversationTask.Content.ReadAsStringAsync(); dynamic jsonResponse = JsonConvert.DeserializeObject(response); log.Info($"Started new conversation with id {jsonResponse.conversationId}"); // TODO: write the conversation ID to a session log with the mobile phone number conversation.MobileNumber = incomingSms?.Value.source_number; conversation.ConversationId = jsonResponse.conversationId; BotConversation newSession = await DocumentClient.UpsertItemAsync(conversation); if (newSession.IsNull()) { throw new BotConnectorException($"Could not create session object for conversation id {conversation.ConversationId}"); } if (incomingSms != null) { await PostToConversation(incomingSms, conversation, log); } } else { log.Info($"Could not start new conversation. {startConversationTask.StatusCode}: {startConversationTask.ReasonPhrase}"); log.Info($"{JsonConvert.SerializeObject(startConversationTask)}"); } }
static void Main(string[] args) { IBotConversationTalkingPoint defaultTalkingPoint = new BotConversationTalkingPoint(); // Handle Conversation About An Item IBotConversationTalkingPoint askAboutItemTalkingPoint = new BotConversationTalkingPoint(); // Handle Conversation About An Items' Details. IBotConversationTalkingPoint askAboutItemDetailsTalkingPoint = new BotConversationTalkingPoint(); // Fallback IBotConversationTalkingPoint fallBackTalkingPoint = new BotConversationTalkingPoint { Text = "Sorry, I could not understand." }; // Bot Conversation Handle IBotConversation botConversation = new BotConversation(defaultTalkingPoint, fallBackTalkingPoint) { TalkingPoints = new List <IBotConversationTalkingPoint>() { defaultTalkingPoint, askAboutItemTalkingPoint } }; defaultTalkingPoint.Transitions = new List <IBotConversationTalkingPoint>() { askAboutItemTalkingPoint }; defaultTalkingPoint.TransitionPriorities = new Dictionary <IBotConversationTalkingPoint, int>() { { askAboutItemTalkingPoint, 1 } }; defaultTalkingPoint.ActivateOn = new Func <EchoState, IBotConversationTalkingPoint, LuisResult, (bool success, Action <object> callback)>((EchoState state, IBotConversationTalkingPoint contextTalkingPoint, LuisResult luisResult) => { return(success: true, callback: null); }); askAboutItemDetailsTalkingPoint.Transitions = new List <IBotConversationTalkingPoint>() { askAboutItemDetailsTalkingPoint }; askAboutItemDetailsTalkingPoint.ActivateOn = new Func <EchoState, IBotConversationTalkingPoint, LuisResult, (bool success, Action <object> callback)>((EchoState state, IBotConversationTalkingPoint contextTalkingPoint, LuisResult luisResult) => { var intentAskAboutItemSize = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Size"); var intentAskAboutItemColor = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Color"); var intentAskAboutItemObject = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Item" && entity.Entity != state.ItemContext); if (intentAskAboutItemObject != null) { if (intentAskAboutItemSize != null) { askAboutItemDetailsTalkingPoint.Text = $"I thought we were talking about the size of my '{state.ItemContext}' ? Ok, let's talk about my '{intentAskAboutItemObject.Entity}'!"; return(true, ((object sender) => { state.ItemContext = intentAskAboutItemObject.Entity; })); } else if (intentAskAboutItemColor != null) { askAboutItemDetailsTalkingPoint.Text = $"I thought we were talking about the color of my '{state.ItemContext}' ? Ok, let's talk about my '{intentAskAboutItemObject.Entity}'!"; return(true, ((object sender) => { state.ItemContext = intentAskAboutItemObject.Entity; })); } else { askAboutItemDetailsTalkingPoint.Text = $"Did you have a question about my '{state.ItemContext}'? (Size/Color)"; } //return false; } else if (intentAskAboutItemSize != null) { askAboutItemDetailsTalkingPoint.Text = $"The size of my {state.ItemContext} is small!"; } else if (intentAskAboutItemColor != null) { askAboutItemDetailsTalkingPoint.Text = $"The color of my {state.ItemContext} is red!"; } return(success: true, callback: null); }); askAboutItemTalkingPoint.Transitions = new List <IBotConversationTalkingPoint>() { askAboutItemDetailsTalkingPoint }; askAboutItemTalkingPoint.ActivateOn = new Func <EchoState, IBotConversationTalkingPoint, LuisResult, (bool success, Action <object> callback)>((EchoState state, IBotConversationTalkingPoint contextTalkingPoint, LuisResult luisResult) => { var intentAskAboutItem = luisResult.Intents.FirstOrDefault().Intent == "AskAboutItem"; var intentAskAboutItemSize = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Size"); var intentAskAboutItemColor = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Color"); var intentAskAboutItemObject = luisResult.Entities.FirstOrDefault(entity => entity.Type == "MyItems::Item"); if (intentAskAboutItem && intentAskAboutItemSize != null && intentAskAboutItemObject != null) { state.ItemContext = intentAskAboutItemObject.Entity; askAboutItemTalkingPoint.Text = $"The size of my {state.ItemContext} is small!"; } else if (intentAskAboutItem && intentAskAboutItemColor != null && intentAskAboutItemObject != null) { state.ItemContext = intentAskAboutItemObject.Entity; askAboutItemTalkingPoint.Text = $"The color of my {state.ItemContext} is red!"; } return(success: true, callback: null); }); // Speak To Bot // Context: Cat // Response: The color of my cat is red! Task botTask = botConversation.Say("What size is your cat?"); botTask.Wait(); // Context: Cat // Response: The color of my cat is red! Task botTask2 = botConversation.Say("What color is he?"); botTask2.Wait(); // Context: Cat => Dog // Response: I thought we were talking about the color of my 'cat' ? Ok, let's talk about my 'dog'! Task botTask3 = botConversation.Say("What color is your dog?"); botTask3.Wait(); // Context: Dog // Response: The color of my dog is red! Task botTask4 = botConversation.Say("What color is he?"); botTask4.Wait(); // Context: Dog // Response: The color of my dog is red // Note: We are still aware that the context is about the dog's size Task botTask5 = botConversation.Say("What about the dog?"); botTask5.Wait(); // Context: Dog // Response: I thought we were talking about the size of my 'dog' ? Ok, let's talk about my 'cat'! Task botTask6 = botConversation.Say("What color is your cat?"); botTask6.Wait(); }
public OutgoingSmsBuilder WithConversation(BotConversation conversation) { _conversation = conversation; return(this); }