Beispiel #1
0
        private static (object value, string error) Evaluator(Expression expression, IMemory state, Options options)
        {
            TimexProperty parsed = null;
            string        result = null;
            string        error  = null;

            var(validHour, validMinute, validSecond) = (0, 0, 0);
            var formatRegex       = new Regex("TXX:[0-5][0-9]:[0-5][0-9]");
            var currentUtcTime    = DateTime.UtcNow;
            var convertedDateTime = currentUtcTime;
            IReadOnlyList <object> args;

            (args, error) = FunctionUtils.EvaluateChildren(expression, state, options);
            if (error == null)
            {
                if (!formatRegex.IsMatch(args[0] as string))
                {
                    error = $"{args[0]}  must be a timex string which only contains minutes and seconds, for example: 'TXX:15:28'";
                }
            }

            if (error == null)
            {
                if (args.Count == 2 && args[1] is string timezone)
                {
                    object convertedTimeZone = null;
                    (convertedTimeZone, error) = FunctionUtils.ConvertTimeZoneFormat(timezone);
                    if (error == null)
                    {
                        convertedDateTime = TimeZoneInfo.ConvertTimeFromUtc(currentUtcTime, (TimeZoneInfo)convertedTimeZone);
                    }
                }
                else
                {
                    convertedDateTime = currentUtcTime.ToLocalTime();
                }
            }

            if (error == null)
            {
                (parsed, error) = FunctionUtils.ParseTimexProperty((args[0] as string).Replace("XX", "00"));
            }

            if (error == null)
            {
                var(hour, minute, second) = (convertedDateTime.Hour, convertedDateTime.Minute, convertedDateTime.Second);
                if (parsed.Minute > minute || (parsed.Minute == minute && parsed.Second >= second))
                {
                    validHour = hour;
                }
                else
                {
                    validHour = hour + 1;
                }

                validMinute = parsed.Minute ?? 0;
                validSecond = parsed.Second ?? 0;
                result      = TimexProperty.FromTime(new Time(validHour, validMinute, validSecond)).TimexValue;
            }

            return(result, error);
        }
 public void DataTypes_Timex_FromTime()
 {
     Assert.AreEqual("T23:59:30", TimexProperty.FromTime(new Time(23, 59, 30)).TimexValue);
 }
Beispiel #3
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", "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"
                    });
                },
                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", "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()}.");
                }
            }
                        );
        }
Beispiel #4
0
 public void DataTypes_Convert_Last5Minutes()
 {
     // date + time + duration
     var timex = new TimexProperty("(2017-09-08T21:19:29,2017-09-08T21:24:29,PT5M)");
     // TODO
 }
 public void DataTypes_Timex_FromDateTime()
 {
     Assert.AreEqual("2017-12-05T23:57:35", TimexProperty.FromDateTime(new System.DateTime(2017, 12, 5, 23, 57, 35)).TimexValue);
 }
        private async Task <DialogTurnResult> AfterGetNewEventTimePrompt(WaterfallStepContext sc, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                var state = await Accessor.GetAsync(sc.Context);

                if (state.UpdateMeetingInfor.NewStartDate.Any() || state.UpdateMeetingInfor.NewStartTime.Any() || state.UpdateMeetingInfor.MoveTimeSpan != 0)
                {
                    var originalEvent         = state.ShowMeetingInfor.FocusedEvents[0];
                    var originalStartDateTime = TimeConverter.ConvertUtcToUserTime(originalEvent.StartTime, state.GetUserTimeZone());
                    var userNow = TimeConverter.ConvertUtcToUserTime(DateTime.UtcNow, state.GetUserTimeZone());

                    if (state.UpdateMeetingInfor.NewStartDate.Any() || state.UpdateMeetingInfor.NewStartTime.Any())
                    {
                        var newStartDate = state.UpdateMeetingInfor.NewStartDate.Any() ?
                                           state.UpdateMeetingInfor.NewStartDate.Last() :
                                           originalStartDateTime;

                        var newStartTime = new List <DateTime>();
                        if (state.UpdateMeetingInfor.NewStartTime.Any())
                        {
                            foreach (var time in state.UpdateMeetingInfor.NewStartTime)
                            {
                                var newStartDateTime = new DateTime(
                                    newStartDate.Year,
                                    newStartDate.Month,
                                    newStartDate.Day,
                                    time.Hour,
                                    time.Minute,
                                    time.Second);

                                if (state.UpdateMeetingInfor.NewStartDateTime == null)
                                {
                                    state.UpdateMeetingInfor.NewStartDateTime = newStartDateTime;
                                }

                                if (newStartDateTime >= userNow)
                                {
                                    state.UpdateMeetingInfor.NewStartDateTime = newStartDateTime;
                                    break;
                                }
                            }
                        }
                    }
                    else if (state.UpdateMeetingInfor.MoveTimeSpan != 0)
                    {
                        state.UpdateMeetingInfor.NewStartDateTime = originalStartDateTime.AddSeconds(state.UpdateMeetingInfor.MoveTimeSpan);
                    }
                    else
                    {
                        return(await sc.BeginDialogAsync(Actions.GetNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotFound)));
                    }

                    state.UpdateMeetingInfor.NewStartDateTime = TimeZoneInfo.ConvertTimeToUtc(state.UpdateMeetingInfor.NewStartDateTime.Value, state.GetUserTimeZone());

                    return(await sc.EndDialogAsync());
                }
                else if (sc.Result != null)
                {
                    IList <DateTimeResolution> dateTimeResolutions = sc.Result as List <DateTimeResolution>;

                    DateTime?newStartTime = null;

                    foreach (var resolution in dateTimeResolutions)
                    {
                        var utcNow = DateTime.UtcNow;
                        var dateTimeConvertTypeString = resolution.Timex;
                        var dateTimeConvertType       = new TimexProperty(dateTimeConvertTypeString);
                        var dateTimeValue             = DateTime.Parse(resolution.Value);
                        if (dateTimeValue == null)
                        {
                            continue;
                        }

                        var originalStartDateTime = TimeConverter.ConvertUtcToUserTime(state.ShowMeetingInfor.FocusedEvents[0].StartTime, state.GetUserTimeZone());
                        if (dateTimeConvertType.Types.Contains(Constants.TimexTypes.Date) && !dateTimeConvertType.Types.Contains(Constants.TimexTypes.DateTime))
                        {
                            dateTimeValue = new DateTime(
                                dateTimeValue.Year,
                                dateTimeValue.Month,
                                dateTimeValue.Day,
                                originalStartDateTime.Hour,
                                originalStartDateTime.Minute,
                                originalStartDateTime.Second);
                        }
                        else if (dateTimeConvertType.Types.Contains(Constants.TimexTypes.Time) && !dateTimeConvertType.Types.Contains(Constants.TimexTypes.DateTime))
                        {
                            dateTimeValue = new DateTime(
                                originalStartDateTime.Year,
                                originalStartDateTime.Month,
                                originalStartDateTime.Day,
                                dateTimeValue.Hour,
                                dateTimeValue.Minute,
                                dateTimeValue.Second);
                        }

                        dateTimeValue = TimeZoneInfo.ConvertTimeToUtc(dateTimeValue, state.GetUserTimeZone());

                        if (newStartTime == null)
                        {
                            newStartTime = dateTimeValue;
                        }

                        if (dateTimeValue >= utcNow)
                        {
                            newStartTime = dateTimeValue;
                            break;
                        }
                    }

                    if (newStartTime != null)
                    {
                        state.UpdateMeetingInfor.NewStartDateTime = newStartTime;

                        return(await sc.EndDialogAsync());
                    }
                    else
                    {
                        return(await sc.BeginDialogAsync(Actions.GetNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotADateTime)));
                    }
                }
                else
                {
                    return(await sc.BeginDialogAsync(Actions.GetNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotADateTime)));
                }
            }
            catch (Exception ex)
            {
                await HandleDialogExceptions(sc, ex);

                return(new DialogTurnResult(DialogTurnStatus.Cancelled, CommonUtil.DialogTurnResultCancelAllDialogs));
            }
        }
Beispiel #7
0
        public async Task <DialogTurnResult> CallReadEventDialog(WaterfallStepContext sc, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                var state = await Accessor.GetAsync(sc.Context);

                var luisResult = state.LuisResult;
                var topIntent  = luisResult?.TopIntent().intent;

                var generalLuisResult = state.GeneralLuisResult;
                var generalTopIntent  = generalLuisResult?.TopIntent().intent;

                if (topIntent == null)
                {
                    state.Clear();
                    return(await sc.CancelAllDialogsAsync());
                }

                if ((generalTopIntent == General.Intent.Next || topIntent == CalendarLU.Intent.ShowNextCalendar) && state.SummaryEvents != null)
                {
                    if ((state.ShowEventIndex + 1) * state.PageSize < state.SummaryEvents.Count)
                    {
                        state.ShowEventIndex++;
                    }
                    else
                    {
                        await sc.Context.SendActivityAsync(ResponseManager.GetResponse(SummaryResponses.CalendarNoMoreEvent));
                    }

                    return(await sc.ReplaceDialogAsync(Actions.ShowEventsSummary, sc.Options));
                }
                else if ((generalTopIntent == General.Intent.Previous || topIntent == CalendarLU.Intent.ShowPreviousCalendar) && state.SummaryEvents != null)
                {
                    if (state.ShowEventIndex > 0)
                    {
                        state.ShowEventIndex--;
                    }
                    else
                    {
                        await sc.Context.SendActivityAsync(ResponseManager.GetResponse(SummaryResponses.CalendarNoPreviousEvent));
                    }

                    return(await sc.ReplaceDialogAsync(Actions.ShowEventsSummary, sc.Options));
                }

                sc.Context.Activity.Properties.TryGetValue("OriginText", out var content);
                var userInput = content != null?content.ToString() : sc.Context.Activity.Text;

                var promptRecognizerResult = ConfirmRecognizerHelper.ConfirmYesOrNo(userInput, sc.Context.Activity.Locale);
                if (promptRecognizerResult.Succeeded && promptRecognizerResult.Value == false)
                {
                    state.Clear();
                    return(await sc.CancelAllDialogsAsync());
                }
                else if (promptRecognizerResult.Succeeded && promptRecognizerResult.Value == true)
                {
                    state.ReadOutEvents = new List <EventModel>()
                    {
                        state.SummaryEvents[0]
                    };
                }
                else if (state.SummaryEvents.Count == 1)
                {
                    state.Clear();
                    return(await sc.CancelAllDialogsAsync());
                }

                if (state.SummaryEvents.Count > 1 && (state.ReadOutEvents == null || state.ReadOutEvents.Count <= 0))
                {
                    var filteredMeetingList = new List <EventModel>();

                    // filter meetings with number
                    if (luisResult.Entities.ordinal != null)
                    {
                        var value       = luisResult.Entities.ordinal[0];
                        var num         = int.Parse(value.ToString());
                        var currentList = GetCurrentPageMeetings(state.SummaryEvents, state);
                        if (num > 0 && num <= currentList.Count)
                        {
                            filteredMeetingList.Add(currentList[num - 1]);
                        }
                    }

                    if (filteredMeetingList.Count <= 0 && luisResult.Entities.number != null && (luisResult.Entities.ordinal == null || luisResult.Entities.ordinal.Length == 0))
                    {
                        var value       = luisResult.Entities.number[0];
                        var num         = int.Parse(value.ToString());
                        var currentList = GetCurrentPageMeetings(state.SummaryEvents, state);
                        if (num > 0 && num <= currentList.Count)
                        {
                            filteredMeetingList.Add(currentList[num - 1]);
                        }
                    }

                    // filter meetings with start time
                    var timeResult = RecognizeDateTime(userInput, sc.Context.Activity.Locale ?? English);
                    if (filteredMeetingList.Count <= 0 && timeResult != null)
                    {
                        foreach (var result in timeResult)
                        {
                            var dateTimeConvertTypeString = result.Timex;
                            var dateTimeConvertType       = new TimexProperty(dateTimeConvertTypeString);
                            if (result.Value != null || (dateTimeConvertType.Types.Contains(Constants.TimexTypes.Time) || dateTimeConvertType.Types.Contains(Constants.TimexTypes.DateTime)))
                            {
                                var dateTime = DateTime.Parse(result.Value);

                                if (dateTime != null)
                                {
                                    var utcStartTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, state.GetUserTimeZone());
                                    foreach (var meeting in GetCurrentPageMeetings(state.SummaryEvents, state))
                                    {
                                        if (meeting.StartTime.TimeOfDay == utcStartTime.TimeOfDay)
                                        {
                                            filteredMeetingList.Add(meeting);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // filter meetings with subject
                    var subject = userInput;
                    if (filteredMeetingList.Count <= 0 && luisResult.Entities.Subject != null)
                    {
                        subject = GetSubjectFromEntity(luisResult.Entities);
                    }

                    foreach (var meeting in GetCurrentPageMeetings(state.SummaryEvents, state))
                    {
                        if (meeting.Title.ToLower().Contains(subject.ToLower()))
                        {
                            filteredMeetingList.Add(meeting);
                        }
                    }

                    // filter meetings with contact name
                    var contactNameList = new List <string>()
                    {
                        userInput
                    };
                    if (filteredMeetingList.Count <= 0 && luisResult.Entities.personName != null)
                    {
                        contactNameList = GetAttendeesFromEntity(luisResult.Entities, userInput);
                    }

                    foreach (var meeting in GetCurrentPageMeetings(state.SummaryEvents, state))
                    {
                        var containsAllContacts = true;
                        foreach (var contactName in contactNameList)
                        {
                            if (!meeting.ContainsAttendee(contactName))
                            {
                                containsAllContacts = false;
                                break;
                            }
                        }

                        if (containsAllContacts)
                        {
                            filteredMeetingList.Add(meeting);
                        }
                    }

                    if (filteredMeetingList.Count == 1)
                    {
                        state.ReadOutEvents = filteredMeetingList;
                        return(await sc.BeginDialogAsync(Actions.Read, sc.Options));
                    }
                    else if (filteredMeetingList.Count > 1)
                    {
                        state.SummaryEvents = filteredMeetingList;
                        return(await sc.ReplaceDialogAsync(Actions.ShowEventsSummary, new ShowMeetingsDialogOptions(ShowMeetingReason.ShowFilteredMeetings, sc.Options)));
                    }
                }

                if (state.ReadOutEvents != null && state.ReadOutEvents.Count > 0)
                {
                    return(await sc.BeginDialogAsync(Actions.Read, sc.Options));
                }
                else
                {
                    state.Clear();
                    return(await sc.CancelAllDialogsAsync());
                }
            }
            catch (Exception ex)
            {
                await HandleDialogExceptions(sc, ex);

                return(new DialogTurnResult(DialogTurnStatus.Cancelled, CommonUtil.DialogTurnResultCancelAllDialogs));
            }
        }
Beispiel #8
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));
        }
Beispiel #9
0
        public async Task <DialogTurnResult> AfterGetNewEventTime(WaterfallStepContext sc, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                var state = await Accessor.GetAsync(sc.Context);

                if (state.StartDate.Any() || state.StartTime.Any() || state.MoveTimeSpan != 0)
                {
                    var originalEvent         = state.Events[0];
                    var originalStartDateTime = TimeConverter.ConvertUtcToUserTime(originalEvent.StartTime, state.GetUserTimeZone());
                    var userNow = TimeConverter.ConvertUtcToUserTime(DateTime.UtcNow, state.GetUserTimeZone());

                    if (state.StartDate.Any() || state.StartTime.Any())
                    {
                        var newStartDate = state.StartDate.Any() ?
                                           state.StartDate.Last() :
                                           originalStartDateTime;

                        var newStartTime = new List <DateTime>();
                        if (state.StartTime.Any())
                        {
                            foreach (var time in state.StartTime)
                            {
                                var newStartDateTime = new DateTime(
                                    newStartDate.Year,
                                    newStartDate.Month,
                                    newStartDate.Day,
                                    time.Hour,
                                    time.Minute,
                                    time.Second);

                                if (state.NewStartDateTime == null)
                                {
                                    state.NewStartDateTime = newStartDateTime;
                                }

                                if (newStartDateTime >= userNow)
                                {
                                    state.NewStartDateTime = newStartDateTime;
                                    break;
                                }
                            }
                        }
                    }
                    else if (state.MoveTimeSpan != 0)
                    {
                        state.NewStartDateTime = originalStartDateTime.AddSeconds(state.MoveTimeSpan);
                    }
                    else
                    {
                        return(await sc.BeginDialogAsync(Actions.UpdateNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotFound)));
                    }

                    state.NewStartDateTime = TimeZoneInfo.ConvertTimeToUtc(state.NewStartDateTime.Value, state.GetUserTimeZone());

                    return(await sc.ContinueDialogAsync());
                }
                else if (sc.Result != null)
                {
                    IList <DateTimeResolution> dateTimeResolutions = sc.Result as List <DateTimeResolution>;

                    DateTime?newStartTime = null;

                    foreach (var resolution in dateTimeResolutions)
                    {
                        var utcNow = DateTime.UtcNow;
                        var dateTimeConvertTypeString = resolution.Timex;
                        var dateTimeConvertType       = new TimexProperty(dateTimeConvertTypeString);
                        var dateTimeValue             = DateTime.Parse(resolution.Value);
                        if (dateTimeValue == null)
                        {
                            continue;
                        }

                        var isRelativeTime = IsRelativeTime(sc.Context.Activity.Text, resolution.Value, dateTimeConvertTypeString);
                        if (isRelativeTime)
                        {
                            dateTimeValue = DateTime.SpecifyKind(dateTimeValue, DateTimeKind.Local);
                        }

                        dateTimeValue = isRelativeTime ? TimeZoneInfo.ConvertTime(dateTimeValue, TimeZoneInfo.Local, state.GetUserTimeZone()) : dateTimeValue;
                        var originalStartDateTime = TimeConverter.ConvertUtcToUserTime(state.Events[0].StartTime, state.GetUserTimeZone());
                        if (dateTimeConvertType.Types.Contains(Constants.TimexTypes.Date) && !dateTimeConvertType.Types.Contains(Constants.TimexTypes.DateTime))
                        {
                            dateTimeValue = new DateTime(
                                dateTimeValue.Year,
                                dateTimeValue.Month,
                                dateTimeValue.Day,
                                originalStartDateTime.Hour,
                                originalStartDateTime.Minute,
                                originalStartDateTime.Second);
                        }
                        else if (dateTimeConvertType.Types.Contains(Constants.TimexTypes.Time) && !dateTimeConvertType.Types.Contains(Constants.TimexTypes.DateTime))
                        {
                            dateTimeValue = new DateTime(
                                originalStartDateTime.Year,
                                originalStartDateTime.Month,
                                originalStartDateTime.Day,
                                dateTimeValue.Hour,
                                dateTimeValue.Minute,
                                dateTimeValue.Second);
                        }

                        dateTimeValue = TimeZoneInfo.ConvertTimeToUtc(dateTimeValue, state.GetUserTimeZone());

                        if (newStartTime == null)
                        {
                            newStartTime = dateTimeValue;
                        }

                        if (dateTimeValue >= utcNow)
                        {
                            newStartTime = dateTimeValue;
                            break;
                        }
                    }

                    if (newStartTime != null)
                    {
                        state.NewStartDateTime = newStartTime;

                        return(await sc.ContinueDialogAsync());
                    }
                    else
                    {
                        return(await sc.BeginDialogAsync(Actions.UpdateNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotADateTime)));
                    }
                }
                else
                {
                    return(await sc.BeginDialogAsync(Actions.UpdateNewStartTime, new UpdateDateTimeDialogOptions(UpdateDateTimeDialogOptions.UpdateReason.NotADateTime)));
                }
            }
            catch
            {
                await HandleDialogExceptions(sc);

                throw;
            }
        }
Beispiel #10
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 = "Please pick a date in the future and a time in the evening."
                        });
                    }
                    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()}.");
                }
            }
                        );
        }
Beispiel #11
0
        private async Task <DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var timex           = (string)stepContext.Options;
            var time            = DateRange(timex);
            var promptMessage   = MessageFactory.Text(PromptMsgText, PromptMsgText, InputHints.ExpectingInput);
            var repromptMessage = MessageFactory.Text(RepromptMsgText, RepromptMsgText, InputHints.ExpectingInput);
            // We have a Date we just need to check it is unambiguous.
            var timexProperty = new TimexProperty(time);

            if (!IsDateRange(time))
            {
                var getFeedback     = stepContext.Context.Activity.CreateReply();
                var feedbackChoices = new HeroCard
                {
                    // Text = "We could not identify the valid date . Please select any of the below.",
                    Buttons = new List <CardAction>
                    {
                        new CardAction()
                        {
                            Title = "Next week", Type = ActionTypes.ImBack, Value = "next week"
                        },
                        new CardAction()
                        {
                            Title = "Next weekend", Type = ActionTypes.ImBack, Value = "next weekend"
                        },
                        new CardAction()
                        {
                            Title = "Tomorrow", Type = ActionTypes.ImBack, Value = "tomorrow"
                        },
                        new CardAction()
                        {
                            Title = "Today", Type = ActionTypes.ImBack, Value = "today"
                        },
                        new CardAction()
                        {
                            Title = "Last week", Type = ActionTypes.ImBack, Value = "last week"
                        },
                        new CardAction()
                        {
                            Title = "Last weekend", Type = ActionTypes.ImBack, Value = "last weekend"
                        },
                        new CardAction()
                        {
                            Title = "Yesterday", Type = ActionTypes.ImBack, Value = "yesterday"
                        }
                    },
                };

                // Add the card to our reply to user.
                getFeedback.Attachments = new List <Attachment>()
                {
                    feedbackChoices.ToAttachment()
                };

                await stepContext.Context.SendActivityAsync(getFeedback, cancellationToken);

                return(await stepContext.PromptAsync(nameof(DateTimePrompt),
                                                     new PromptOptions
                {
                    Prompt = repromptMessage,
                }, cancellationToken));
            }
            return(await stepContext.NextAsync(new List <DateTimeResolution> {
                new DateTimeResolution {
                    Timex = time
                }
            }, cancellationToken));
        }
Beispiel #12
0
        public static ReservationResult Validate(OnTurnProperty onTurnProperty, ReservationResult returnResult)
        {
            if (onTurnProperty == null || onTurnProperty.Entities.Count == 0)
            {
                return(returnResult);
            }

            // We only will pull number -> party size, datetimeV2 -> date and time, cafeLocation -> location.
            var numberEntity       = onTurnProperty.Entities.Find(item => item.EntityName.Equals(PartySizeEntity));
            var dateTimeEntity     = onTurnProperty.Entities.Find(item => item.EntityName.Equals(ReservationProperty.DateTimeEntity));
            var locationEntity     = onTurnProperty.Entities.Find(item => item.EntityName.Equals(LocationEntity));
            var confirmationEntity = onTurnProperty.Entities.Find(item => item.EntityName.Equals(ConfirmationEntity));

            if (numberEntity != null)
            {
                // We only accept MaxPartySize in a reservation.
                if (int.Parse(numberEntity.Value as string) > MaxPartySize)
                {
                    returnResult.Outcome.Add(new ReservationOutcome("Sorry. " + int.Parse(numberEntity.Value as string) + " does not work. I can only accept up to 10 guests in a reservation.", PartySizeEntity));
                    returnResult.Status = ReservationStatus.Incomplete;
                }
                else
                {
                    returnResult.NewReservation.PartySize = (int)numberEntity.Value;
                }
            }

            if (dateTimeEntity != null)
            {
                // Get parsed date time from TIMEX
                // LUIS returns a timex expression and so get and un-wrap that.
                // Take the first date time since book table scenario does not have to deal with multiple date times or date time ranges.
                var timeProp = dateTimeEntity.Value as string;
                if (timeProp != null)
                {
                    var today       = DateTime.Now;
                    var parsedTimex = new TimexProperty(timeProp);

                    // See if the date meets our constraints.
                    if (parsedTimex.DayOfMonth != null && parsedTimex.Year != null && parsedTimex.Month != null)
                    {
                        var date = DateTimeOffset.Parse($"{parsedTimex.Year}-${parsedTimex.Month}-${parsedTimex.DayOfMonth}");
                        returnResult.NewReservation.Date         = date.UtcDateTime.ToString("o").Split("T")[0];
                        returnResult.NewReservation.DateLGString = new TimexProperty(returnResult.NewReservation.Date).ToNaturalLanguage(today);
                        var validDate = TimexRangeResolver.Evaluate(dateTimeEntity.Value as string[], reservationDateConstraints);
                        if (validDate != null || (validDate.Count == 0))
                        {
                            // Validation failed!
                            returnResult.Outcome.Add(new ReservationOutcome(
                                                         $"Sorry. {returnResult.NewReservation.DateLGString} does not work.  "
                                                         + "I can only make reservations for the next 4 weeks.", ReservationProperty.DateTimeEntity));
                            returnResult.NewReservation.Date = string.Empty;
                            returnResult.Status = ReservationStatus.Incomplete;
                        }
                    }

                    // See if the time meets our constraints.
                    if (parsedTimex.Hour != null &&
                        parsedTimex.Minute != null &&
                        parsedTimex.Second != null)
                    {
                        var validtime = TimexRangeResolver.Evaluate(dateTimeEntity.Value as string[], reservationTimeConstraints);

                        returnResult.NewReservation.Time  = ((int)parsedTimex.Hour).ToString("D2");
                        returnResult.NewReservation.Time += ":";
                        returnResult.NewReservation.Time += ((int)parsedTimex.Minute).ToString("D2");
                        returnResult.NewReservation.Time += ":";
                        returnResult.NewReservation.Time += ((int)parsedTimex.Second).ToString("D2");

                        if (validtime != null || (validtime.Count == 0))
                        {
                            // Validation failed!
                            returnResult.Outcome.Add(new ReservationOutcome("Sorry, that time does not work. I can only make reservations that are in the daytime (6AM - 6PM)", ReservationProperty.DateTimeEntity));
                            returnResult.NewReservation.Time = string.Empty;
                            returnResult.Status = ReservationStatus.Incomplete;
                        }
                    }

                    // Get date time LG string if we have both date and time.
                    if (string.IsNullOrWhiteSpace(returnResult.NewReservation.Date) && string.IsNullOrWhiteSpace(returnResult.NewReservation.Time))
                    {
                        returnResult.NewReservation.DateTimeLGString = new TimexProperty(returnResult.NewReservation.Date + "T" + returnResult.NewReservation.Time).ToNaturalLanguage(today);
                    }
                }
            }

            // Take the first found value.
            if (locationEntity != null)
            {
                var cafeLocation = ((JObject)locationEntity.Value)[0][0];

                // Capitalize cafe location.
                returnResult.NewReservation.Location = char.ToUpper(((string)cafeLocation)[0]) + ((string)cafeLocation).Substring(1);
            }

            // Accept confirmation entity if available only if we have a complete reservation
            if (confirmationEntity != null)
            {
                if ((string)((JObject)confirmationEntity.Value)[0][0] == "yes")
                {
                    returnResult.NewReservation.ReservationConfirmed = true;
                    returnResult.NewReservation.NeedsChange          = false;
                }
                else
                {
                    returnResult.NewReservation.NeedsChange          = true;
                    returnResult.NewReservation.ReservationConfirmed = false;
                }
            }

            return(returnResult);
        }
Beispiel #13
0
 public static string ConvertTimexToString(TimexProperty timex)
 {
     return(TimexConvertEnglish.ConvertTimexToString(timex));
 }
Beispiel #14
0
 public void DataTypes_Convert_WednesdayToSaturday()
 {
     // date + duration
     var timex = new TimexProperty("(XXXX-WXX-3,XXXX-WXX-6,P3D)");
     // TODO
 }
Beispiel #15
0
        private static (object value, string error) Evaluator(Expression expression, IMemory state, Options options)
        {
            TimexProperty parsed = null;
            string        result = null;
            string        error  = null;

            var(validYear, validMonth, validDay) = (0, 0, 0);
            var currentUtcTime    = DateTime.UtcNow;
            var convertedDateTime = currentUtcTime;
            IReadOnlyList <object> args;

            (args, error) = FunctionUtils.EvaluateChildren(expression, state, options);
            if (error == null)
            {
                (parsed, error) = FunctionUtils.ParseTimexProperty(args[0]);
            }

            if (error == null)
            {
                if (parsed.Year != null || parsed.Month == null || parsed.DayOfMonth == null)
                {
                    error = $"{args[0]} must be a timex string which only contains month and day-of-month, for example: 'XXXX-10-31'.";
                }
            }

            if (error == null)
            {
                if (args.Count == 2 && args[1] is string timezone)
                {
                    object convertedTimeZone = null;
                    (convertedTimeZone, error) = FunctionUtils.ConvertTimeZoneFormat(timezone);
                    if (error == null)
                    {
                        convertedDateTime = TimeZoneInfo.ConvertTimeFromUtc(currentUtcTime, (TimeZoneInfo)convertedTimeZone);
                    }
                }
                else
                {
                    convertedDateTime = currentUtcTime.ToLocalTime();
                }
            }

            if (error == null)
            {
                var(year, month, day) = (convertedDateTime.Year, convertedDateTime.Month, convertedDateTime.Day);
                if (parsed.Month <= month || (parsed.Month == month && parsed.DayOfMonth < day))
                {
                    validYear = year;
                }
                else
                {
                    validYear = year - 1;
                }

                validMonth = parsed.Month ?? 0;
                validDay   = parsed.DayOfMonth ?? 0;
                if (validMonth == 2 && validDay == 29)
                {
                    while (!DateTime.IsLeapYear(validYear))
                    {
                        validYear -= 1;
                    }
                }

                result = TimexProperty.FromDate(new DateTime(validYear, validMonth, validDay)).TimexValue;
            }

            return(result, error);
        }
Beispiel #16
0
        // </AttendeesValidatorSnippet>

        // <StartValidatorSnippet>
        private static bool TimexHasDateAndTime(TimexProperty timex)
        {
            return(timex.Now ?? false ||
                   (timex.Types.Contains(TimexTypes.DateTime) &&
                    timex.Types.Contains(TimexTypes.Definite)));
        }
Beispiel #17
0
    public static bool IsTimeRange(string timex)
    {
        TimexProperty timexProperty = new TimexProperty(timex);

        return(timexProperty.Types.Contains(Constants.TimexTypes.TimeRange) || timexProperty.Types.Contains(Constants.TimexTypes.DateTimeRange));
    }
Beispiel #18
0
        private async Task <DialogTurnResult> RecommendSlotsStepAsync(WaterfallStepContext step, CancellationToken cancellationToken)
        {
            var state = await _stateAccessor.GetAsync(step.Context, cancellationToken : cancellationToken);

            if (state.Services.Count == 0)
            {
                state.Services = ParseServiceSelectionCardResponse(step.Context.Activity);
                await _stateAccessor.SetAsync(step.Context, state, cancellationToken);
            }

            // Check whether we already know something about the date.
            if (state.StartDate != null)
            {
                return(await step.NextAsync(cancellationToken : cancellationToken));
            }

            List <DateTime> recommendedSlots;

            try
            {
                var api = new CarwashService(step, _telemetryClient, cancellationToken);

                var notAvailable = await api.GetNotAvailableDatesAndTimesAsync(cancellationToken);

                recommendedSlots = GetRecommendedSlots(notAvailable);
            }
            catch (AuthenticationException)
            {
                await step.Context.SendActivityAsync(AuthDialog.NotAuthenticatedMessage, cancellationToken : cancellationToken);

                return(await step.ClearStateAndEndDialogAsync(_stateAccessor, cancellationToken : cancellationToken));
            }
            catch (Exception e)
            {
                _telemetryClient.TrackException(e);
                await step.Context.SendActivityAsync(e.Message, cancellationToken : cancellationToken);

                return(await step.ClearStateAndEndDialogAsync(_stateAccessor, cancellationToken : cancellationToken));
            }

            // Save recommendations to state
            state.RecommendedSlots = recommendedSlots;
            await _stateAccessor.SetAsync(step.Context, state, cancellationToken);

            var choices = new List <Choice>();

            foreach (var slot in recommendedSlots)
            {
                var timex = TimexProperty.FromDateTime(slot);
                choices.Add(new Choice(timex.ToNaturalLanguage(DateTime.Now)));
            }

            return(await step.PromptAsync(
                       RecommendedSlotsPromptName,
                       new PromptOptions
            {
                Prompt = MessageFactory.Text("Can I recommend you one of these slots? If you want to choose something else, just type skip."),
                Choices = choices,
            },
                       cancellationToken));
        }
Beispiel #19
0
        private static bool IsAmbiguous(string timex)
        {
            var timexProperty = new TimexProperty(timex);

            return(!timexProperty.Types.Contains(Constants.TimexTypes.Definite));
        }
Beispiel #20
0
        private async Task <DialogTurnResult> PromptForSlotStepAsync(WaterfallStepContext step, CancellationToken cancellationToken)
        {
            var state = await _stateAccessor.GetAsync(step.Context, cancellationToken : cancellationToken);

            if (state.StartDate == null && step.Result is IList <DateTimeResolution> resolution)
            {
                var timex = new TimexProperty(resolution[0].Timex);
                state.Timex = timex;
                var hour = timex.Hour ?? 0;
                state.StartDate = new DateTime(
                    timex.Year.Value,
                    timex.Month.Value,
                    timex.DayOfMonth.Value,
                    hour,
                    0,
                    0);
                await _stateAccessor.SetAsync(step.Context, state, cancellationToken);
            }

            var reservationCapacity = new List <CarwashService.ReservationCapacity>();

            try
            {
                var api = new CarwashService(step, _telemetryClient, cancellationToken);

                reservationCapacity = (List <CarwashService.ReservationCapacity>) await api.GetReservationCapacityAsync(state.StartDate.Value, cancellationToken);
            }
            catch (AuthenticationException)
            {
                await step.Context.SendActivityAsync(AuthDialog.NotAuthenticatedMessage, cancellationToken : cancellationToken);

                return(await step.ClearStateAndEndDialogAsync(_stateAccessor, cancellationToken : cancellationToken));
            }
            catch (Exception e)
            {
                _telemetryClient.TrackException(e);
                await step.Context.SendActivityAsync(e.Message, cancellationToken : cancellationToken);

                return(await step.ClearStateAndEndDialogAsync(_stateAccessor, cancellationToken : cancellationToken));
            }

            // Check whether we already know the slot.
            if (Slots.Any(s => s.StartTime == state.StartDate?.Hour))
            {
                // Check if slot is available.
                if (!reservationCapacity.Any(c => c.StartTime == state.StartDate && c.FreeCapacity > 0))
                {
                    await step.Context.SendActivityAsync("Sorry, this slot is already full.", cancellationToken : cancellationToken);
                }
                else
                {
                    return(await step.NextAsync(cancellationToken : cancellationToken));
                }
            }
            else if (!string.IsNullOrEmpty(state.Timex?.PartOfDay))
            {
                // Check whether we can find out the slot from timex.
                Slot slot = null;
                switch (state.Timex.PartOfDay)
                {
                case "MO":
                    slot = Slots[0];
                    break;

                case "AF":
                    slot = Slots[1];
                    break;

                case "EV":
                    slot = Slots[2];
                    break;
                }

                if (slot != null)
                {
                    state.StartDate = new DateTime(
                        state.StartDate.Value.Year,
                        state.StartDate.Value.Month,
                        state.StartDate.Value.Day,
                        slot.StartTime,
                        0,
                        0);

                    await _stateAccessor.SetAsync(step.Context, state, cancellationToken);

                    return(await step.NextAsync(cancellationToken : cancellationToken));
                }
            }

            var choices = new List <Choice>();

            state.SlotChoices = new List <DateTime>();
            foreach (var slot in reservationCapacity)
            {
                if (slot.FreeCapacity < 1)
                {
                    continue;
                }

                choices.Add(new Choice($"{slot.StartTime.ToNaturalLanguage()} ({slot.StartTime.Hour}-{Slots.Single(s => s.StartTime == slot.StartTime.Hour).EndTime})"));

                // Save recommendations to state
                state.SlotChoices.Add(slot.StartTime);
            }

            await _stateAccessor.SetAsync(step.Context, state, cancellationToken);

            return(await step.PromptAsync(
                       SlotPromptName,
                       new PromptOptions
            {
                Prompt = MessageFactory.Text("Please choose one of these slots:"),
                Choices = choices,
            },
                       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
            }
        }
Beispiel #22
0
        public static string TimexDurationToFrench(TimexProperty timex)
        {
            if (timex.Years != null)
            {
                if (timex.Years == 1)
                {
                    return($"{timex.Years} an");
                }
                return($"{timex.Years} ans");
            }

            if (timex.Months != null)
            {
                return($"{timex.Months} mois");
            }

            if (timex.Weeks != null)
            {
                if (timex.Weeks == 1)
                {
                    return($"{timex.Weeks} semaine");
                }
                return($"{timex.Weeks} semaines");
            }

            if (timex.Days != null)
            {
                if (timex.Days == 1)
                {
                    return($"{timex.Days} jour");
                }
                return($"{timex.Days} jours");
            }

            if (timex.Hours != null)
            {
                if (timex.Hours == 1)
                {
                    return($"{timex.Hours} heure");
                }
                return($"{timex.Hours} heures");
            }

            if (timex.Minutes != null)
            {
                if (timex.Minutes == 1)
                {
                    return($"{timex.Minutes} minute");
                }
                return($"{timex.Minutes} minutes");
            }

            if (timex.Seconds != null)
            {
                if (timex.Seconds == 1)
                {
                    return($"{timex.Seconds} seconde");
                }
                return($"{timex.Seconds} secondes");
            }

            return(string.Empty);
        }