Ejemplo n.º 1
0
        private async Task <DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // If the child dialog ("BookingDialog") was cancelled, the user failed to confirm or if the intent wasn't BookFlight
            // the Result here will be null.
            if (stepContext.Result is BookingDetails result)
            {
                // Now we have all the booking details call the booking service.

                // If the call to the booking service was successful tell the user.

                var timeProperty  = new TimexProperty(result.TravelDate);
                var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
                var messageText   = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";
                var message       = MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput);
                await stepContext.Context.SendActivityAsync(message, cancellationToken);
            }

            // Restart the main dialog with a different message the second time around
            var promptMessage = "What else can I do for you?";

            return(await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken));
        }
Ejemplo n.º 2
0
        private async Task <DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // If the child dialog ("BookingDialog") was cancelled or the user failed to confirm, the Result here will be null.
            if (stepContext.Result != null)
            {
                var result = (BookingDetails)stepContext.Result;

                // Now we have all the booking details call the booking service.

                // If the call to the booking service was successful tell the user.

                var timeProperty  = new TimexProperty(result.TravelDate);
                var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
                var msg           = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";
                await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thank you."), cancellationToken);
            }
            return(await stepContext.EndDialogAsync(cancellationToken : cancellationToken));
        }
        protected async Task DigestLuisResult(DialogContext dc, ReservationLuis luisResult)
        {
            try
            {
                var state = await ConversationStateAccessor.GetAsync(dc.Context);

                // Extract entities and store in state here.
                if (luisResult != null)
                {
                    var entities = luisResult.Entities;

                    // Extract the cuisines out (already normalized to canonical form) and put in State thus slot-filling for the dialog.
                    if (entities.cuisine != null)
                    {
                        foreach (var cuisine in entities.cuisine)
                        {
                            var type = cuisine.First <string>();
                            state.Booking.Category = type;
                        }
                    }

                    if (entities.datetime != null)
                    {
                        var results = DateTimeRecognizer.RecognizeDateTime(dc.Context.Activity.Text, CultureInfo.CurrentUICulture.ToString());
                        if (results.Count > 0)
                        {
                            // We only care about presence of one DateTime
                            var result = results.First();

                            // The resolution could include two example values: one for AM and one for PM.
                            var distinctTimexExpressions = new HashSet <string>();
                            var values = (List <Dictionary <string, string> >)result.Resolution["values"];
                            foreach (var value in values)
                            {
                                // Each result includes a TIMEX expression that captures the inherent date but not time ambiguity.
                                // We are interested in the distinct set of TIMEX expressions.
                                if (value.TryGetValue("timex", out var timex))
                                {
                                    distinctTimexExpressions.Add(timex);
                                }
                            }

                            // Now we have the timex properties let's see if we have a definite date and time
                            // If so we slot-fill this and move on, if we don't we'll ignore for now meaning the user will be prompted
                            var timexProperty = new TimexProperty(distinctTimexExpressions.First());

                            if (timexProperty.Types.Contains(Constants.TimexTypes.Date) && timexProperty.Types.Contains(Constants.TimexTypes.Definite))
                            {
                                // We have definite date (no ambiguity)
                                state.Booking.ReservationDate = new DateTime(timexProperty.Year.Value, timexProperty.Month.Value, timexProperty.DayOfMonth.Value);

                                // Timex doesn't capture time ambiguity (e.g. 4 rather than 4pm)
                                if (timexProperty.Types.Contains(Constants.TimexTypes.Time))
                                {
                                    // If we have multiple TimeX
                                    if (distinctTimexExpressions.Count == 1)
                                    {
                                        // We have definite time (no ambiguity)
                                        state.Booking.ReservationTime = DateTime.Parse($"{timexProperty.Hour.Value}:{timexProperty.Minute.Value}:{timexProperty.Second.Value}");
                                    }
                                    else
                                    {
                                        // We don't have a distinct time so add the TimeEx expressions to enable disambiguation later and prepare the natural language versions
                                        foreach (var timex in distinctTimexExpressions)
                                        {
                                            var property = new TimexProperty(timex);
                                            state.AmbiguousTimexExpressions.Add(timex, property.ToNaturalLanguage(DateTime.Now));
                                        }
                                    }
                                }
                            }
                            else if (timexProperty.Types.Contains(Constants.TimexTypes.Time))
                            {
                                // We might have a time but no date (e.g. book a table for 4pm)
                                // If we have multiple timex (and time) this means we have a AM and PM component (e.g. ambiguous - book a table at 9)
                                if (distinctTimexExpressions.Count == 1)
                                {
                                    state.Booking.ReservationTime = DateTime.Parse($"{timexProperty.Hour.Value}:{timexProperty.Minute.Value}:{timexProperty.Second.Value}");
                                }
                            }
                            else
                            {
                                // We don't have a distinct time so add the TimeEx expressions to enable disambiguation later and prepare the natural language versions
                                foreach (var timex in distinctTimexExpressions)
                                {
                                    var property = new TimexProperty(timex);
                                    state.AmbiguousTimexExpressions.Add(timex, property.ToNaturalLanguage(DateTime.Now));
                                }
                            }
                        }
                    }

                    if (entities.geographyV2 != null)
                    {
                        state.Booking.Location = entities.geographyV2.First().Location;
                    }

                    // Establishing attendee count can be problematic as the number entity can be picked up for poorly qualified
                    // times, e.g. book a restaurant tomorrow at 2 for 4 people so we rely on a composite entity
                    if (entities.attendees != null)
                    {
                        var attendeesComposite = entities.attendees.First();
                        if (attendeesComposite != null)
                        {
                            int.TryParse(attendeesComposite.number.First().ToString(), out var attendeeCount);
                            if (attendeeCount > 0)
                            {
                                state.Booking.AttendeeCount = attendeeCount;
                            }
                        }
                    }
                }
            }
            catch
            {
                // put log here
            }
        }
Ejemplo n.º 4
0
        public BookTable()
            : base("BookTable")
        {
            var promptOptions = new ChoicePromptOptions
            {
                Choices = new List <Choice>
                {
                    new Choice {
                        Value = "Seattle"
                    },
                    new Choice {
                        Value = "Bellevue"
                    },
                    new Choice {
                        Value = "Renton"
                    },
                }
            };

            //Dialogs.Add("textPrompt", new TextPrompt());

            Dialogs.Add("choicePrompt", new ChoicePrompt(Culture.English)
            {
                Style = Microsoft.Bot.Builder.Prompts.ListStyle.Auto
            });
            Dialogs.Add("numberPrompt", new NumberPrompt <int>(Culture.English));
            Dialogs.Add("timexPrompt", new TimexPrompt(Culture.English, TimexValidator));
            Dialogs.Add("confirmationPrompt", new ConfirmPrompt(Culture.English));

            Dialogs.Add("BookTable",
                        new WaterfallStep[]
            {
                async(dc, args, next) =>
                {
                    dc.ActiveDialog.State = new Dictionary <string, object>();
                    // await dc.Prompt("textPrompt", "Sure. I can help with that. What City?");
                    await dc.Prompt("choicePrompt", "Which of our locations would you like?", promptOptions);
                },
                async(dc, args, next) =>
                {
                    var choiceResult = (FoundChoice)args["Value"];
                    dc.ActiveDialog.State["bookingLocation"] = choiceResult.Value;
                    await dc.Prompt("timexPrompt", $"Ok. I have {dc.ActiveDialog.State["bookingLocation"]} When would you like to arrive? (We open at 4PM.)",
                                    new PromptOptions {
                        RetryPromptString = "Sorry, we only accept reservations for the next two weeks, 4PM-8PM"
                    });
                },
                async(dc, args, next) =>
                {
                    var timexResult     = (TimexResult)args;
                    var timexResolution = timexResult.Resolutions.First();
                    var timexProperty   = new TimexProperty(timexResolution.ToString());
                    var bookingDateTime = $"{timexProperty.ToNaturalLanguage(DateTime.Now)}";
                    dc.ActiveDialog.State["bookingDateTime"] = bookingDateTime;

                    await dc.Prompt("numberPrompt", $"Ok. I have {dc.ActiveDialog.State["bookingDateTime"]}. How many in your party?");
                },
                async(dc, args, next) =>
                {
                    dc.ActiveDialog.State["bookingGuestCount"] = args["Value"];
                    var dialogState = dc.ActiveDialog.State;

                    await dc.Prompt("confirmationPrompt", $"Thanks, Should I go ahead and book a table for {dialogState["bookingGuestCount"].ToString()} guests at our {dialogState["bookingLocation"].ToString()} location for {dialogState["bookingDateTime"].ToString()} ?");
                },
                async(dc, args, next) =>
                {
                    var dialogState = dc.ActiveDialog.State;

                    // TODO: Verify user said yes to confirmation prompt

                    // TODO: book the table!

                    await dc.Context.SendActivity($"Thanks, I have {dialogState["bookingGuestCount"].ToString()} guests booked for our {dialogState["bookingLocation"].ToString()} location for {dialogState["bookingDateTime"].ToString()}.");
                }
            }
                        );
        }
Ejemplo n.º 5
0
        public BookTable()
            : base("BookTable")
        {
            var promptOptions = new ChoicePromptOptions
            {
                Choices = new List <Choice>
                {
                    new Choice {
                        Value = "Seattle"
                    },
                    new Choice {
                        Value = "Bellevue"
                    },
                    new Choice {
                        Value = "Renton"
                    },
                }
            };

            //Dialogs.Add("textPrompt", new TextPrompt());

            Dialogs.Add("choicePrompt", new ChoicePrompt(Culture.English)
            {
                Style = Microsoft.Bot.Builder.Prompts.ListStyle.Auto
            });
            Dialogs.Add("numberPrompt", new NumberPrompt <int>(Culture.English));
            Dialogs.Add("timexPrompt", new TimexPrompt(Culture.English, TimexValidator));
            Dialogs.Add("confirmationPrompt", new ConfirmPrompt(Culture.English));

            Dialogs.Add("BookTable",
                        new WaterfallStep[]
            {
                async(dc, args, next) =>
                {
                    dc.ActiveDialog.State = new Dictionary <string, object>();
                    IDictionary <string, object> state = dc.ActiveDialog.State;

                    // add any LUIS entities to active dialog state.
                    if (args.ContainsKey("luisResult"))
                    {
                        cafeLUISModel lResult = (cafeLUISModel)args["luisResult"];
                        updateContextWithLUIS(lResult, ref state);
                    }

                    // prompt if we do not already have cafelocation
                    if (state.ContainsKey("cafeLocation"))
                    {
                        state["bookingLocation"] = state["cafeLocation"];
                        await next();
                    }
                    else
                    {
                        await dc.Prompt("choicePrompt", "Which of our locations would you like?", promptOptions);
                    }
                },
                async(dc, args, next) =>
                {
                    var state = dc.ActiveDialog.State;
                    if (!state.ContainsKey("cafeLocation"))
                    {
                        var choiceResult         = (FoundChoice)args["Value"];
                        state["bookingLocation"] = choiceResult.Value;
                    }
                    bool promptForDateTime = true;
                    if (state.ContainsKey("datetime"))
                    {
                        // validate timex
                        var inputdatetime = new string[] { (string)state["datetime"] };
                        var results       = evaluateTimeX((string[])inputdatetime);
                        if (results.Count != 0)
                        {
                            var timexResolution      = results.First().TimexValue;
                            var timexProperty        = new TimexProperty(timexResolution.ToString());
                            var bookingDateTime      = $"{timexProperty.ToNaturalLanguage(DateTime.Now)}";
                            state["bookingDateTime"] = bookingDateTime;
                            promptForDateTime        = false;
                        }
                    }
                    // prompt if we do not already have date and time
                    if (promptForDateTime)
                    {
                        await dc.Prompt("timexPrompt", "When would you like to arrive? (We open at 4PM.)",
                                        new PromptOptions {
                            RetryPromptString = "We only accept reservations for the next 2 weeks and in the evenings between 4PM - 8PM"
                        });
                    }
                    else
                    {
                        await next();
                    }
                },
                async(dc, args, next) =>
                {
                    var state = dc.ActiveDialog.State;
                    if (!state.ContainsKey("datetime"))
                    {
                        var timexResult          = (TimexResult)args;
                        var timexResolution      = timexResult.Resolutions.First();
                        var timexProperty        = new TimexProperty(timexResolution.ToString());
                        var bookingDateTime      = $"{timexProperty.ToNaturalLanguage(DateTime.Now)}";
                        state["bookingDateTime"] = bookingDateTime;
                    }
                    // prompt if we already do not have party size
                    if (state.ContainsKey("partySize"))
                    {
                        state["bookingGuestCount"] = state["partySize"];
                        await next();
                    }
                    else
                    {
                        await dc.Prompt("numberPrompt", "How many in your party?");
                    }
                },
                async(dc, args, next) =>
                {
                    var state = dc.ActiveDialog.State;
                    if (!state.ContainsKey("partySize"))
                    {
                        state["bookingGuestCount"] = args["Value"];
                    }

                    await dc.Prompt("confirmationPrompt", $"Thanks, Should I go ahead and book a table for {state["bookingGuestCount"].ToString()} guests at our {state["bookingLocation"].ToString()} location for {state["bookingDateTime"].ToString()} ?");
                },
                async(dc, args, next) =>
                {
                    var dialogState = dc.ActiveDialog.State;

                    // TODO: Verify user said yes to confirmation prompt

                    // TODO: book the table!

                    await dc.Context.SendActivity($"Thanks, I have {dialogState["bookingGuestCount"].ToString()} guests booked for our {dialogState["bookingLocation"].ToString()} location for {dialogState["bookingDateTime"].ToString()}.");
                }
            }
                        );
        }
Ejemplo n.º 6
0
        private async Task <DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // If the child dialog ("BookingDialog") was cancelled, the user failed to confirm or if the intent wasn't BookFlight
            // the Result here will be null.
            if (stepContext.Result is BookingDetails result)
            {
                // Now we have all the booking details call the booking service.

                // If the call to the booking service was successful tell the user.

                var timeProperty  = new TimexProperty(result.TravelDate);
                var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
                var messageText   = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";
                var message       = MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput);

                var model = new FlightitineraryModel
                {
                    Places = new Cards.Place[] {
                        new Cards.Place {
                            Name = result.Origin, Code = result.Origin, Id = 13554, Type = "Airport"
                        },
                        new Cards.Place {
                            Name = result.Destination, Code = result.Destination, Id = 11235, Type = "Airport"
                        }
                    },
                    Segments = new Segment[]
                    {
                        new Segment {
                            Id = 1, ArrivalDateTime = DateTime.Parse(result.TravelDate), DepartureDateTime = DateTime.Parse(result.TravelDate), OriginStation = 13554, DestinationStation = 11235
                        },
                        new Segment {
                            Id = 2, ArrivalDateTime = DateTime.Parse(result.TravelDate), DepartureDateTime = DateTime.Parse(result.TravelDate), OriginStation = 11235, DestinationStation = 13554
                        }
                    },
                    Query = new Query
                    {
                        DestinationPlace = "11235",
                        OriginPlace      = "13554",
                        InboundDate      = result.TravelDate,
                        OutboundDate     = result.TravelDate,
                        LocationSchema   = "Default",
                        CabinClass       = "Economy",
                        GroupPricing     = false,
                        Country          = "GB",
                        Currency         = "GBP",
                        Locale           = "en-gb",
                        Adults           = 3,
                        Children         = 0,
                        Infants          = 0,
                    },
                    BookingOptions = new Bookingoption[]
                    {
                        new Bookingoption
                        {
                            BookingItems = new Bookingitem[]
                            {
                                new Bookingitem
                                {
                                    Price = new Random().Next(200, 5000), SegmentIds = new int[] { 1, 2 }
                                }
                            }
                        }
                    }
                };

                var confirmationCard = CreateBookingConfimrationCardAttachment(model);
                message.Attachments.Add(confirmationCard);

                await stepContext.Context.SendActivityAsync(message, cancellationToken);
            }

            // Restart the main dialog with a different message the second time around
            var promptMessage = "What else can I do for you?";

            return(await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken));
        }