Esempio n. 1
0
        /// <summary>
        /// Prompt for Restaurant to book.
        /// </summary>
        /// <param name="sc">Waterfall Step Context.</param>
        /// <param name="cancellationToken">Cancellation Token.</param>
        /// <returns>Dialog Turn Result.</returns>
        private async Task <DialogTurnResult> AskForRestaurant(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            var state = await Accessor.GetAsync(sc.Context);

            var reservation = state.Booking;

            if (reservation.Location != null)
            {
                return(await sc.NextAsync(sc.Values, cancellationToken));
            }

            // Reset the dialog if the user hasn't confirmed the reservation.
            if (!reservation.Confirmed)
            {
                state.Booking = CreateNewReservationInfo();
                return(await sc.ReplaceDialogAsync(Id, cancellationToken : cancellationToken));
            }

            // Prompt for restaurant
            var restaurants = SeedReservationSampleData.GetListOfRestaurants(reservation.Category, "London", _urlResolver);

            state.Restaurants = restaurants;

            var restaurantOptionsForSpeak = new StringBuilder();

            for (var i = 0; i < restaurants.Count; i++)
            {
                restaurantOptionsForSpeak.Append(restaurants[i].Name);
                restaurantOptionsForSpeak.Append(i == restaurants.Count - 2 ? $" {BotStrings.Or} " : ", ");
            }

            var restaurantResponse = RestaurantBookingSharedResponses.BookRestaurantRestaurantSelectionPrompt;

            var tokens = new StringDictionary
            {
                { "RestaurantCount", (restaurants.Count - 1).ToString() },
                { "ServerUrl", _urlResolver.ServerUrl },
                { "RestaurantList", restaurantOptionsForSpeak.ToString() }
            };

            var cardData = new List <TitleImageTextButtonCardData>();

            restaurants.ForEach(r => cardData.Add(
                                    new TitleImageTextButtonCardData
            {
                ImageUrl         = r.PictureUrl,
                ImageSize        = AdaptiveImageSize.Stretch,
                ImageAlign       = AdaptiveHorizontalAlignment.Stretch,
                ButtonTitle      = r.Name,
                ButtonSubtitle   = r.Location,
                SelectedItemData = r.Name
            }));

            var reply = sc.Context.Activity.CreateAdaptiveCardGroupReply(
                restaurantResponse, @"Dialogs\RestaurantBooking\Resources\Cards\TitleImageTextButton.json", AttachmentLayoutTypes.Carousel, cardData, ResponseBuilder, tokens);

            return(await sc.PromptAsync(Actions.RestaurantPrompt, new PromptOptions { Prompt = reply }, cancellationToken));
        }
Esempio n. 2
0
        /// <summary>
        /// Prompt for the Food type if not already provided on the initial utterance.
        /// </summary>
        /// <param name="sc">Waterfall Step Context.</param>
        /// <param name="cancellationToken">Cancellation Token.</param>
        /// <returns>Dialog Turn Result.</returns>
        private async Task <DialogTurnResult> AskForFoodTypeAsync(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            var state = await ConversationStateAccessor.GetAsync(sc.Context, cancellationToken : cancellationToken);

            var reservation = state.Booking;

            // If we already have a Cuisine provided we skip to next step
            if (reservation.Category != null)
            {
                return(await sc.NextAsync(sc.Values, cancellationToken));
            }

            // Fixed test data provided at this time
            var foodTypes = SeedReservationSampleData
                            .GetListOfDefaultFoodTypes()
                            .Select(
                r => new FoodTypeInfo
            {
                TypeName = r.Category,
                ImageUrl = BotImageForFoodType(r.Category)
            }).ToList();

            var tokens = new Dictionary <string, object>
            {
                { "FoodTypeList", foodTypes.ToSpeechString(TemplateManager.GetString(BotStrings.Or), f => f.TypeName) }
            };

            state.Cuisine = foodTypes;

            var cards   = new List <Card>();
            var options = new PromptOptions()
            {
                Choices = new List <Choice>(),
            };

            foreach (var foodType in foodTypes)
            {
                cards.Add(new Card(
                              GetDivergedCardName(sc.Context, "CuisineChoiceCard"),
                              new CuisineChoiceCardData
                {
                    ImageUrl   = foodType.ImageUrl,
                    ImageSize  = AdaptiveImageSize.Stretch,
                    ImageAlign = AdaptiveHorizontalAlignment.Stretch,
                    Cuisine    = foodType.TypeName,
                }));

                options.Choices.Add(new Choice(foodType.TypeName));
            }

            var replyMessage = TemplateManager.GenerateActivity(
                RestaurantBookingSharedResponses.BookRestaurantFoodSelectionPrompt,
                cards,
                tokens);

            // Prompt for restaurant choice
            return(await sc.PromptAsync(Actions.AskForFoodType, new PromptOptions { Prompt = replyMessage, Choices = options.Choices }, cancellationToken));
        }
Esempio n. 3
0
        /// <summary>
        /// Prompt for the Food type if not already provided on the initial utterance.
        /// </summary>
        /// <param name="sc">Waterfall Step Context.</param>
        /// <param name="cancellationToken">Cancellation Token.</param>
        /// <returns>Dialog Turn Result.</returns>
        private async Task <DialogTurnResult> AskForFoodType(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            var state = await Accessor.GetAsync(sc.Context);

            var reservation = state.Booking;

            // If we already have a Cuisine provided we skip to next step
            if (reservation.Category != null)
            {
                return(await sc.NextAsync(sc.Values, cancellationToken));
            }

            // Fixed test data provided at this time
            var foodTypes = SeedReservationSampleData
                            .GetListOfDefaultFoodTypes()
                            .Select(
                r => new FoodTypeInfo
            {
                TypeName = r.Category,
                ImageUrl = BotImageForFoodType(r.Category)
            }).ToList();

            var tokens = new StringDictionary
            {
                { "FoodTypeList", foodTypes.ToSpeechString(BotStrings.Or, f => f.TypeName) }
            };

            state.Cuisine = foodTypes;

            // Create a card for each restaurant
            var cardsData = new List <TitleImageTextButtonCardData>();

            foodTypes.ForEach(ft => cardsData.Add(
                                  new TitleImageTextButtonCardData
            {
                ImageUrl         = ft.ImageUrl,
                ImageSize        = AdaptiveImageSize.Stretch,
                ImageAlign       = AdaptiveHorizontalAlignment.Stretch,
                ButtonTitle      = ft.TypeName,
                SelectedItemData = ft.TypeName
            }));

            var reply = sc.Context.Activity.CreateAdaptiveCardGroupReply(
                RestaurantBookingSharedResponses.BookRestaurantFoodSelectionPrompt,
                @"Dialogs\RestaurantBooking\Resources\Cards\TitleImageTextButton.json",
                AttachmentLayoutTypes.Carousel, cardsData, ResponseBuilder, tokens);

            // Prompt for restaurant choice
            return(await sc.PromptAsync(Actions.AskForFoodType, new PromptOptions { Prompt = reply }, cancellationToken));
        }
Esempio n. 4
0
        private async Task <bool> ValidateRestaurantSelection(PromptValidatorContext <FoundChoice> promptContext, CancellationToken cancellationToken)
        {
            var state = await ConversationStateAccessor.GetAsync(promptContext.Context, cancellationToken : cancellationToken);

            // This is a workaround to a known issue with Adaptive Card button responses and prompts whereby the "Text" of the adaptive card button response
            // is put into a Value object not the Text as expected causing prompt validation to fail.
            // If the prompt was about to fail and the Value property is set with Text set to NULL we do special handling.
            if (!promptContext.Recognized.Succeeded && (promptContext.Context.Activity.Value != null) && string.IsNullOrEmpty(promptContext.Context.Activity.Text))
            {
                dynamic value          = promptContext.Context.Activity.Value;
                string  promptResponse = value["selectedItem"];  // The property will be named after your choice set's ID

                if (!string.IsNullOrEmpty(promptResponse))
                {
                    // Override what the prompt has done
                    promptContext.Recognized.Succeeded = true;
                    var foundChoice = new FoundChoice
                    {
                        Value = promptResponse
                    };
                    promptContext.Recognized.Value = foundChoice;
                }
            }

            if (promptContext.Recognized.Succeeded)
            {
                var restaurants = SeedReservationSampleData.GetListOfRestaurants(state.Booking.Category, "London", _urlResolver);
                var restaurant  = restaurants.First(r => r.Name == promptContext.Recognized.Value.Value);
                if (restaurant != null)
                {
                    state.Booking.BookingPlace = restaurant;

                    var reply = TemplateManager.GenerateActivity(RestaurantBookingSharedResponses.BookRestaurantBookingPlaceSelectionEcho, new Dictionary <string, object> {
                        { "BookingPlaceName", restaurant.Name }
                    });
                    await promptContext.Context.SendActivityAsync(reply, cancellationToken);

                    return(true);
                }
            }

            return(false);
        }
Esempio n. 5
0
        /// <summary>
        /// Prompt for Restaurant to book.
        /// </summary>
        /// <param name="sc">Waterfall Step Context.</param>
        /// <param name="cancellationToken">Cancellation Token.</param>
        /// <returns>Dialog Turn Result.</returns>
        private async Task <DialogTurnResult> AskForRestaurantAsync(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            var state = await ConversationStateAccessor.GetAsync(sc.Context, cancellationToken : cancellationToken);

            var reservation = state.Booking;

            if (state.IsAction)
            {
                return(await sc.NextAsync(cancellationToken : cancellationToken));
            }

            // Reset the dialog if the user hasn't confirmed the reservation.
            if (!reservation.Confirmed)
            {
                state.Booking = CreateNewReservationInfo();
                return(await sc.EndDialogAsync(cancellationToken : cancellationToken));
            }

            // Prompt for restaurant
            var restaurants = SeedReservationSampleData.GetListOfRestaurants(reservation.Category, "London", _urlResolver);

            state.Restaurants = restaurants;

            var restaurantOptionsForSpeak = new StringBuilder();

            for (var i = 0; i < restaurants.Count; i++)
            {
                restaurantOptionsForSpeak.Append(restaurants[i].Name);
                restaurantOptionsForSpeak.Append(i == restaurants.Count - 2 ? $" {TemplateManager.GetString(BotStrings.Or)} " : ", ");
            }

            var tokens = new Dictionary <string, object>
            {
                { "RestaurantCount", restaurants.Count.ToString() },
                { "ServerUrl", _urlResolver.ServerUrl },
                { "RestaurantList", restaurantOptionsForSpeak.ToString() }
            };

            var cards   = new List <Card>();
            var options = new PromptOptions()
            {
                Choices = new List <Choice>(),
            };

            foreach (var restaurant in restaurants)
            {
                cards.Add(new Card(
                              GetDivergedCardName(sc.Context, "RestaurantChoiceCard"),
                              new RestaurantChoiceCardData
                {
                    ImageUrl         = restaurant.PictureUrl,
                    ImageSize        = AdaptiveImageSize.Stretch,
                    ImageAlign       = AdaptiveHorizontalAlignment.Stretch,
                    Name             = restaurant.Name,
                    Title            = restaurant.Name,
                    Location         = restaurant.Location,
                    SelectedItemData = restaurant.Name
                }));

                options.Choices.Add(new Choice(restaurant.Name));
            }

            var replyMessage = TemplateManager.GenerateActivity(RestaurantBookingSharedResponses.BookRestaurantRestaurantSelectionPrompt, cards, tokens);

            return(await sc.PromptAsync(Actions.RestaurantPrompt, new PromptOptions { Prompt = replyMessage, Choices = options.Choices }, cancellationToken));
        }