private async Task <DialogTurnResult> EndDialogAsync(WaterfallStepContext sc, CancellationToken cancellationToken) { var convState = await StateAccessor.GetAsync(sc.Context, () => new HospitalitySkillState(), cancellationToken); var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService), cancellationToken); if (userState.UserReservation.CheckOutDate == convState.UpdatedReservation.CheckOutDate) { var tokens = new Dictionary <string, object> { { "Date", userState.UserReservation.CheckOutDate } }; var cardData = userState.UserReservation; cardData.Title = TemplateManager.GetString(HospitalityStrings.UpdateReservation); // check out date moved confirmation var reply = TemplateManager.GenerateActivity(ExtendStayResponses.ExtendStaySuccess, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), tokens); await sc.Context.SendActivityAsync(reply, cancellationToken); return(await sc.EndDialogAsync(await CreateSuccessActionResultAsync(sc.Context, cancellationToken), cancellationToken)); } return(await sc.EndDialogAsync(cancellationToken : cancellationToken)); }
private async Task <bool> ValidateLateCheckOutAsync(PromptValidatorContext <bool> promptContext, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(promptContext.Context, () => new HospitalityUserSkillState(HotelService)); if (promptContext.Recognized.Succeeded) { bool response = promptContext.Recognized.Value; if (response) { // TODO process late check out request here userState.LateCheckOut = true; var convState = await StateAccessor.GetAsync(promptContext.Context, () => new HospitalitySkillState()); userState.UserReservation.CheckOutTimeData = convState.UpdatedReservation.CheckOutTimeData; // set new checkout in hotel service HotelService.UpdateReservationDetails(userState.UserReservation); } return(await Task.FromResult(true)); } return(await Task.FromResult(false)); }
private async Task <DialogTurnResult> LateCheckOutPrompt(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState()); // already requested late check out if (userState.LateCheckOut) { var cardData = userState.UserReservation; cardData.Title = string.Format(HospitalityStrings.ReservationDetails); var reply = ResponseManager.GetCardResponse(LateCheckOutResponses.HasLateCheckOut, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), null); await sc.Context.SendActivityAsync(reply); return(await sc.EndDialogAsync()); } // TODO checking availability // simulate with time delay await sc.Context.SendActivityAsync(ResponseManager.GetResponse(LateCheckOutResponses.CheckAvailability)); await Task.Delay(1600); var lateTime = await _hotelService.GetLateCheckOutAsync(); var tokens = new StringDictionary { { "Time", lateTime }, }; return(await sc.PromptAsync(DialogIds.LateCheckOutPrompt, new PromptOptions() { Prompt = ResponseManager.GetResponse(LateCheckOutResponses.MoveCheckOutPrompt, tokens), RetryPrompt = ResponseManager.GetResponse(LateCheckOutResponses.RetryMoveCheckOut), })); }
private async Task StoreListTypeIdsAsync(DialogContext dc) { var userState = await UserStateAccessor.GetAsync(dc.Context, () => new ToDoSkillUserState()); var state = await ToDoStateAccessor.GetAsync(dc.Context, () => new ToDoSkillState()); var senderMailAddress = state.UserStateId; if (!userState.ListTypeIds.ContainsKey(senderMailAddress)) { userState.ListTypeIds.Add(senderMailAddress, new Dictionary <string, string>()); foreach (var listType in state.ListTypeIds) { userState.ListTypeIds[senderMailAddress].Add(listType.Key, listType.Value); } } else { foreach (var listType in state.ListTypeIds) { if (userState.ListTypeIds[senderMailAddress].ContainsKey(listType.Key)) { userState.ListTypeIds[senderMailAddress][listType.Key] = listType.Value; } else { userState.ListTypeIds[senderMailAddress].Add(listType.Key, listType.Value); } } } }
private async Task <DialogTurnResult> LateCheckOutPromptAsync(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService), cancellationToken); // already requested late check out if (userState.LateCheckOut) { var cardData = userState.UserReservation; cardData.Title = TemplateManager.GetString(HospitalityStrings.ReservationDetails); var reply = TemplateManager.GenerateActivity(LateCheckOutResponses.HasLateCheckOut, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), null); await sc.Context.SendActivityAsync(reply, cancellationToken); return(await sc.EndDialogAsync(cancellationToken : cancellationToken)); } // TODO checking availability // simulate with time delay await sc.Context.SendActivityAsync(TemplateManager.GenerateActivity(LateCheckOutResponses.CheckAvailability), cancellationToken); await Task.Delay(1600); var lateTime = await HotelService.GetLateCheckOutAsync(); var convState = await StateAccessor.GetAsync(sc.Context, () => new HospitalitySkillState(), cancellationToken); var entities = convState?.LuisResult?.Entities; if (entities != null && entities.datetime != null && (entities.datetime[0].Type == "time" || entities.datetime[0].Type == "timerange")) { // ISO 8601 https://docs.microsoft.com/en-us/azure/cognitive-services/luis/luis-reference-prebuilt-datetimev2?tabs=1-1%2C2-1%2C3-1%2C4-1%2C5-1%2C6-1 var timexProperty = new TimexProperty(); TimexParsing.ParseString(entities.datetime[0].Expressions[0], timexProperty); var preferedTime = new TimeSpan(timexProperty.Hour ?? 0, timexProperty.Minute ?? 0, timexProperty.Second ?? 0) + new TimeSpan((int)(timexProperty.Hours ?? 0), (int)(timexProperty.Minutes ?? 0), (int)(timexProperty.Seconds ?? 0)); if (preferedTime < lateTime) { lateTime = preferedTime; } } convState.UpdatedReservation = new ReservationData { CheckOutTimeData = lateTime }; var tokens = new Dictionary <string, object> { { "Time", convState.UpdatedReservation.CheckOutTime }, }; return(await sc.PromptAsync(DialogIds.LateCheckOutPrompt, new PromptOptions() { Prompt = TemplateManager.GenerateActivity(LateCheckOutResponses.MoveCheckOutPrompt, tokens), RetryPrompt = TemplateManager.GenerateActivity(LateCheckOutResponses.RetryMoveCheckOut), }, cancellationToken)); }
private async Task <DialogTurnResult> CheckEntitiesAsync(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService), cancellationToken); var convState = await StateAccessor.GetAsync(sc.Context, () => new HospitalitySkillState(), cancellationToken); var entities = convState?.LuisResult?.Entities; convState.UpdatedReservation = userState.UserReservation.Copy(); if (entities == null) { return(await sc.NextAsync(cancellationToken : cancellationToken)); } // check for valid datetime entity if (entities.datetime != null && (entities.datetime[0].Type == "date" || entities.datetime[0].Type == "datetime" || entities.datetime[0].Type == "daterange") && await DateValidationAsync(sc.Context, entities.datetime[0].Expressions, cancellationToken)) { return(await sc.NextAsync(cancellationToken : cancellationToken)); } // check for valid number composite entity if (entities.NumNights?[0].HotelNights != null && entities.NumNights?[0].number[0] != null && await NumValidationAsync(sc.Context, entities.NumNights[0].number[0], cancellationToken)) { return(await sc.NextAsync(cancellationToken : cancellationToken)); } // need clarification on input else if (entities.datetime == null && entities.number != null) { convState.NumberEntity = entities.number[0]; var tokens = new Dictionary <string, object> { { "Number", convState.NumberEntity.ToString() } }; return(await sc.PromptAsync(DialogIds.CheckNumNights, new PromptOptions() { Prompt = TemplateManager.GenerateActivity(ExtendStayResponses.ConfirmAddNights, tokens) }, cancellationToken)); } // trying to request late check out time else if (convState.IsAction == false && entities.datetime != null && (entities.datetime[0].Type == "time" || entities.datetime[0].Type == "timerange")) { return(await sc.ReplaceDialogAsync(nameof(LateCheckOutDialog), cancellationToken : cancellationToken)); } return(await sc.NextAsync(cancellationToken : cancellationToken)); }
private async Task <DialogTurnResult> LateCheckOutPrompt(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService)); // already requested late check out if (userState.LateCheckOut) { var cardData = userState.UserReservation; cardData.Title = string.Format(HospitalityStrings.ReservationDetails); var reply = ResponseManager.GetCardResponse(LateCheckOutResponses.HasLateCheckOut, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), null); await sc.Context.SendActivityAsync(reply); return(await sc.EndDialogAsync()); } // TODO checking availability // simulate with time delay await sc.Context.SendActivityAsync(ResponseManager.GetResponse(LateCheckOutResponses.CheckAvailability)); await Task.Delay(1600); var lateTime = await HotelService.GetLateCheckOutAsync(); var convState = await StateAccessor.GetAsync(sc.Context, () => new HospitalitySkillState()); var entities = convState.LuisResult.Entities; if (entities.datetime != null && (entities.datetime[0].Type == "time" || entities.datetime[0].Type == "timerange")) { var timexProperty = new TimexProperty(); TimexParsing.ParseString(entities.datetime[0].Expressions[0], timexProperty); var preferedTime = new TimeSpan(timexProperty.Hour ?? 0, timexProperty.Minute ?? 0, timexProperty.Second ?? 0) + new TimeSpan((int)(timexProperty.Hours ?? 0), (int)(timexProperty.Minutes ?? 0), (int)(timexProperty.Seconds ?? 0)); if (preferedTime < lateTime) { lateTime = preferedTime; } } convState.UpdatedReservation = new ReservationData { CheckOutTimeData = lateTime }; var tokens = new StringDictionary { { "Time", convState.UpdatedReservation.CheckOutTime }, }; return(await sc.PromptAsync(DialogIds.LateCheckOutPrompt, new PromptOptions() { Prompt = ResponseManager.GetResponse(LateCheckOutResponses.MoveCheckOutPrompt, tokens), RetryPrompt = ResponseManager.GetResponse(LateCheckOutResponses.RetryMoveCheckOut), })); }
private async Task <DialogTurnResult> FindSimilarProductsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var userData = await UserStateAccessor.GetAsync(stepContext.Context, () => new Models.UserData(), cancellationToken); var activity = stepContext.Context.Activity; var reply = activity.CreateReply(); // Search for the uploaded picture in the attachments if (activity.Attachments != null && activity.Attachments.Any()) { var file = activity.Attachments[0]; // Using the gender from Face Recognition we can get the customer category (Women, Men, Boys, Girls...) and filter suggested products. var category = userData.Gender.Equals("female", StringComparison.InvariantCultureIgnoreCase) ? CustomerCategory.Women : CustomerCategory.Men; var similarProducts = await ProductService.GetSuggestedProductsByGenderAsync(file.ContentUrl, category); var similarProductsAttachment = new Attachment { Content = new Dictionary <string, SuggestedProductsResult> { { "products", similarProducts }, }, ContentType = "text/plain", Name = "products", }; var msg = "I found these similar products. Let me know if you have any questions."; reply.AttachmentLayout = AttachmentLayoutTypes.Carousel; reply.Text = msg; // Add audio response as an attachment var audioResponse = await SpeechService.SynthesizeSpeechAsync(msg); var audioAttachment = await BotUtils.CreateAndUploadAttachmentAsync(reply.ServiceUrl, "audio/wav", reply.Conversation.Id, audioResponse, AttachmentName, _botConfigOptions); reply.Attachments = new List <Attachment> { similarProductsAttachment, BotUtils.CreateAudioCard("Similar products", reply.Text, audioAttachment.ContentUrl).ToAttachment(), }; // Send the card(s) to the user as an attachment to the activity await stepContext.Context.SendActivityAsync(reply, cancellationToken); // We end the dialog flow on this step as we don't need any other confirmation at this point. return(await stepContext.EndDialogAsync(cancellationToken : cancellationToken)); } else { return(await stepContext.PromptAsync(UploadPicturePrompt, new PromptOptions { Prompt = MessageFactory.Text("Please upload an image") }, cancellationToken)); } }
private async Task <DialogTurnResult> ShowReservation(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState()); var cardData = userState.UserReservation; cardData.Title = string.Format(HospitalityStrings.ReservationDetails); // send card with reservation details var reply = ResponseManager.GetCardResponse(GetReservationResponses.ShowReservationDetails, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), null); await sc.Context.SendActivityAsync(reply); return(await sc.EndDialogAsync()); }
protected async Task <DialogTurnResult> HasCheckedOut(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService)); // if user has already checked out shouldn't be able to do anything else if (userState.CheckedOut) { await sc.Context.SendActivityAsync(ResponseManager.GetResponse(SharedResponses.HasCheckedOut)); return(await sc.EndDialogAsync()); } return(await sc.NextAsync()); }
private async Task <DialogTurnResult> ShowReservationAsync(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService), cancellationToken); var cardData = userState.UserReservation; cardData.Title = TemplateManager.GetString(HospitalityStrings.ReservationDetails); // send card with reservation details var reply = TemplateManager.GenerateActivity(GetReservationResponses.ShowReservationDetails, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), null); await sc.Context.SendActivityAsync(reply, cancellationToken); return(await sc.EndDialogAsync(await CreateSuccessActionResultAsync(sc.Context, cancellationToken), cancellationToken)); }
private async Task <bool> DateValidation(ITurnContext turnContext, IReadOnlyList <string> dates) { var convState = await StateAccessor.GetAsync(turnContext, () => new HospitalitySkillState()); var userState = await UserStateAccessor.GetAsync(turnContext, () => new HospitalityUserSkillState()); DateTime dateObject = new DateTime(); bool dateIsEarly = false; string[] formats = { "XXXX-MM-dd", "yyyy-MM-dd" }; foreach (var date in dates) { // try parse exact date format so it won't accept time inputs if (DateTime.TryParseExact(date, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateObject)) { if (dateObject > DateTime.Now && dateObject > DateTime.Parse(userState.UserReservation.CheckOutDate)) { // get first future date that is formatted correctly convState.UpdatedReservation.CheckOutDate = dateObject.ToString("MMMM d, yyyy"); return(await Task.FromResult(true)); } else { dateIsEarly = true; } } } // found correctly formatted date, but date is not after current check-out date if (dateIsEarly) { // same date as current check-out date if (dateObject.ToString("MMMM d, yyyy") == userState.UserReservation.CheckOutDate) { await turnContext.SendActivityAsync(ResponseManager.GetResponse(ExtendStayResponses.SameDayRequested)); } else { var tokens = new StringDictionary { { "Date", userState.UserReservation.CheckOutDate } }; await turnContext.SendActivityAsync(ResponseManager.GetResponse(ExtendStayResponses.NotFutureDateError, tokens)); } } return(await Task.FromResult(false)); }
private async Task <bool> ValidateEmailAsync(PromptValidatorContext <string> promptContext, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(promptContext.Context, () => new HospitalityUserSkillState()); // check for valid email input string response = promptContext.Recognized?.Value; if (promptContext.Recognized.Succeeded && !string.IsNullOrWhiteSpace(response) && new EmailAddressAttribute().IsValid(response)) { userState.Email = response; return(await Task.FromResult(true)); } return(await Task.FromResult(false)); }
private async Task <DialogTurnResult> EmailPrompt(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState()); if (userState.CheckedOut && string.IsNullOrWhiteSpace(userState.Email)) { // prompt for email to send receipt to return(await sc.PromptAsync(DialogIds.EmailPrompt, new PromptOptions() { Prompt = ResponseManager.GetResponse(CheckOutResponses.EmailPrompt), RetryPrompt = ResponseManager.GetResponse(CheckOutResponses.InvalidEmailPrompt) })); } return(await sc.NextAsync()); }
private async Task <bool> NumValidationAsync(ITurnContext turnContext, double extraNights, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(turnContext, () => new HospitalityUserSkillState(HotelService), cancellationToken); var convState = await StateAccessor.GetAsync(turnContext, () => new HospitalitySkillState(), cancellationToken); if (extraNights >= 1) { // add entity number to the current check out date DateTime currentDate = DateTime.Parse(userState.UserReservation.CheckOutDate); convState.UpdatedReservation.CheckOutDate = currentDate.AddDays(extraNights).ToString(ReservationData.DateFormat); return(await Task.FromResult(true)); } await turnContext.SendActivityAsync(TemplateManager.GenerateActivity(ExtendStayResponses.NumberEntityError), cancellationToken); return(await Task.FromResult(false)); }
private async Task <bool> NumValidation(ITurnContext turnContext, double extraNights) { var userState = await UserStateAccessor.GetAsync(turnContext, () => new HospitalityUserSkillState()); var convState = await StateAccessor.GetAsync(turnContext, () => new HospitalitySkillState()); if (extraNights >= 1) { // add entity number to the current check out date DateTime currentDate = DateTime.Parse(userState.UserReservation.CheckOutDate); convState.UpdatedReservation.CheckOutDate = currentDate.AddDays(extraNights).ToString("MMMM d, yyyy"); return(await Task.FromResult(true)); } await turnContext.SendActivityAsync(ResponseManager.GetResponse(ExtendStayResponses.NumberEntityError)); return(await Task.FromResult(false)); }
private async Task <bool> ValidateCheckOutAsync(PromptValidatorContext <bool> promptContext, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(promptContext.Context, () => new HospitalityUserSkillState()); if (promptContext.Recognized.Succeeded) { bool response = promptContext.Recognized.Value; if (response) { // TODO process check out request here // set checkout value userState.CheckedOut = true; } return(await Task.FromResult(true)); } return(await Task.FromResult(false)); }
private async Task <DialogTurnResult> ExtendDatePrompt(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState()); var convState = await StateAccessor.GetAsync(sc.Context, () => new HospitalitySkillState()); // if new date hasnt been set yet if (userState.UserReservation.CheckOutDate == convState.UpdatedReservation.CheckOutDate) { // get extended reservation date return(await sc.PromptAsync(DialogIds.ExtendDatePrompt, new PromptOptions() { Prompt = ResponseManager.GetResponse(ExtendStayResponses.ExtendDatePrompt), RetryPrompt = ResponseManager.GetResponse(ExtendStayResponses.RetryExtendDate) })); } return(await sc.NextAsync()); }
private async Task <DialogTurnResult> EndDialog(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState()); if (userState.CheckedOut) { var tokens = new StringDictionary { { "Email", userState.Email }, }; // TODO process request to send email receipt // checked out confirmation message await sc.Context.SendActivityAsync(ResponseManager.GetResponse(CheckOutResponses.SendEmailMessage, tokens)); await sc.Context.SendActivityAsync(ResponseManager.GetResponse(CheckOutResponses.CheckOutSuccess)); } return(await sc.EndDialogAsync()); }
private async Task <bool> RecoverListTypeIdsAsync(DialogContext dc, string senderMailAddress) { var userState = await UserStateAccessor.GetAsync(dc.Context, () => new ToDoSkillUserState()); var state = await ToDoStateAccessor.GetAsync(dc.Context, () => new ToDoSkillState()); if (userState.ListTypeIds.ContainsKey(senderMailAddress) && state.ListTypeIds.Count <= 0 && userState.ListTypeIds[senderMailAddress].Count > 0) { foreach (var listType in userState.ListTypeIds[senderMailAddress]) { state.ListTypeIds.Add(listType.Key, listType.Value); } return(true); } return(false); }
private async Task <DialogTurnResult> EndDialogAsync(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService), cancellationToken); if (userState.CheckedOut) { var tokens = new Dictionary <string, object> { { "Email", userState.Email }, }; // TODO process request to send email receipt // checked out confirmation message await sc.Context.SendActivityAsync(TemplateManager.GenerateActivity(CheckOutResponses.SendEmailMessage, tokens), cancellationToken); await sc.Context.SendActivityAsync(TemplateManager.GenerateActivity(CheckOutResponses.CheckOutSuccess), cancellationToken); return(await sc.EndDialogAsync(await CreateSuccessActionResultAsync(sc.Context, cancellationToken), cancellationToken)); } return(await sc.EndDialogAsync(cancellationToken : cancellationToken)); }
private async Task <DialogTurnResult> EndDialog(WaterfallStepContext sc, CancellationToken cancellationToken) { var userState = await UserStateAccessor.GetAsync(sc.Context, () => new HospitalityUserSkillState(HotelService)); if (userState.LateCheckOut) { var tokens = new StringDictionary { { "Time", userState.UserReservation.CheckOutTime }, { "Date", userState.UserReservation.CheckOutDate } }; var cardData = userState.UserReservation; cardData.Title = string.Format(HospitalityStrings.UpdateReservation); // check out time moved confirmation var reply = ResponseManager.GetCardResponse(LateCheckOutResponses.MoveCheckOutSuccess, new Card(GetCardName(sc.Context, "ReservationDetails"), cardData), tokens); await sc.Context.SendActivityAsync(reply); } return(await sc.EndDialogAsync()); }
private async Task <bool> ValidateConfirmExtensionAsync(PromptValidatorContext <bool> promptContext, CancellationToken cancellationToken) { var convState = await StateAccessor.GetAsync(promptContext.Context, () => new HospitalitySkillState()); var userState = await UserStateAccessor.GetAsync(promptContext.Context, () => new HospitalityUserSkillState()); if (promptContext.Recognized.Succeeded) { bool response = promptContext.Recognized.Value; if (response) { // TODO process requesting reservation extension userState.UserReservation.CheckOutDate = convState.UpdatedReservation.CheckOutDate; // set new checkout date in hotel service _hotelService.UpdateReservationDetails(userState.UserReservation); } return(await Task.FromResult(true)); } return(await Task.FromResult(false)); }