コード例 #1
0
        public override async Task <ParseResult> ParseAsync(ChatState chatState, Chat_ParseField chatParseField, ChatMessage message)
        {
            var preFlowName  = chatParseField.GetProperty("preFlowName");
            var preStepId    = chatParseField.GetProperty("preStepId");
            var postFlowName = chatParseField.GetProperty("postFlowName");
            var postStepId   = chatParseField.GetProperty("postStepId");

            if (String.IsNullOrEmpty(preFlowName) ||
                String.IsNullOrEmpty(preStepId) ||
                String.IsNullOrEmpty(postFlowName) ||
                String.IsNullOrEmpty(postStepId))
            {
                throw new ApplicationException("Parse: Missing rule data for IntentGateway Parser.");
            }

            message.Classifications = await ClassifyText(message.CorrectedUserInput, preFlowName, preStepId, postFlowName, postStepId, chatState.SessionData.IsSmsChannel);

            chatState.UpdateLastClassification(message.Classifications);

            if (!message.Classifications.IsSuccessful)
            {
                return(ParseResult.Failed);
            }

            // We don't want common chat intent's here.
            var intent = chatState.LastClassification.GetBestResult().Intent;

            if (intent != null && intent.StartsWith("commonchat-"))
            {
                return(ParseResult.Failed);
            }

            return(ParseResult.CreateSuccess(message.Classifications.GetBestResult().Result));
        }
コード例 #2
0
ファイル: NameParser.cs プロジェクト: asurionlabs/chatengine
        public override async Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            string agentName = state.GlobalAnswers.GetFieldAnswer <string>(ChatStandardField.AgentName);

            (var names, var tokens) = await GetNamesAndTokens(message.UserInput, agentName);

            if (tokens == null)
            {
                logger.Error("Network: Failed to call text parser service.");
                return(ParseResult.Failed);
            }

            // If we didnt detect any names, and the user entered only 2 or 3 words (possible names),
            // and no look behind (to cut down on false positives), we retry with "My name is " prepended
            // since the NLP is better at picking up names in a sentence.
            if ((names.Count == 0) && (tokens.Count <= 3) && (!chatParseField.CheckPreviousMessages))
            {
                (names, tokens) = await GetNamesAndTokens("My name is " + message.UserInput, agentName);
            }

            names.AddRange(GetUndetectedNames(message.UserInput));

            // Add our test name if detected
            if (message.UserInput.ToUpper().Contains(TestName.ToUpper()))
            {
                names.AddRange(TestName.Split(' '));
            }

            if (names.Count > 0)
            {
                return(ParseResult.CreateSuccess(names.Distinct().ToArray()));
            }

            return(ParseResult.Failed);
        }
コード例 #3
0
        KinesisParseEventContent CreateParseEventContent(ChatModel chatModel, Chat_ParseField field, bool success, bool searchMode)
        {
            var step          = chatModel.CurrentState.Steps.LastOrDefault();
            var lastMessage   = chatModel.CurrentState.GetLastMessage();
            var properties    = new Dictionary <string, object>();
            var interactionId = log4net.LogicalThreadContext.Properties["interactionId"] as string;

            AddStandardProperties(chatModel.CurrentState.SessionData, properties);

            return(new KinesisParseEventContent()
            {
                Chat_id = chatModel.ChatId,
                Interaction_id = interactionId,
                Session_id = chatModel.SessionLogId,
                Session_date = DateTime.UtcNow.ToString("o"),
                Variable_name = field?.FieldName,
                FlowStep = new ChatStepId(step),
                Chat_text = filterService.FilterUserData(chatModel.CurrentState, lastMessage.UserInput),
                Chat_corrected_text = filterService.FilterUserData(chatModel.CurrentState, lastMessage.CorrectedUserInput),
                Bot_text = filterService.FilterUserData(chatModel.CurrentState, lastMessage.BotQuestionsText),
                Success = success,
                SearchMode = searchMode,
                Properties = properties
            });
        }
コード例 #4
0
ファイル: NameParser.cs プロジェクト: asurionlabs/chatengine
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            if (result.Success)
            {
                string[] names = result.Answer as string[];

                var variables = GetChatVariables(state, flowStep, chatParseField.VarScope);

                // Set subvariables for first and last name
                if (names.Length > 0)
                {
                    variables[$"{chatParseField.FieldName}_First"] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(names[0]);
                    CheckIfAnswerHasPII(state, PIIType, names[0], PIIMask);
                }

                if (names.Length > 1)
                {
                    variables[$"{chatParseField.FieldName}_Last"] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(names.Last());
                    CheckIfAnswerHasPII(state, PIIType, names[1], PIIMask);
                }

                // TODO: Use parse dependencies to join them properly.  They will be marked as "compound".
                variables[chatParseField.FieldName] = String.Join(" ", names);
            }
        }
コード例 #5
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            string text = GetTextSource(chatParseField, message);

            // Shortcut for common case where flow tries to take all user input.
            // .* regex means all characters EXCEPT newlines. But the flow wants all including newlines
            // so running regex to collect all data doesn't make sense. So we just set the variable to everything.
            if (chatParseField.RuleData == ".*")
            {
                return(Task.FromResult(ParseResult.CreateSuccess(text)));
            }

            string regex = chatParseField?.GetProperty("Regex") ?? chatParseField.RuleData;

            try
            {
                var match = Regex.Match(text, regex, RegexOptions.IgnoreCase, ChatConfiguration.RegexTimeout);
                if (match.Success)
                {
                    if (String.IsNullOrEmpty(chatParseField.Answer))
                    {
                        return(Task.FromResult(ParseResult.CreateSuccess(match.Value)));
                    }

                    return(Task.FromResult(ParseResult.CreateSuccess(chatParseField.Answer)));
                }
            }
            catch (RegexMatchTimeoutException)
            {
                logger.ErrorFormat("Regex timed out. {0}", regex);
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #6
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var tokens = TextClassificationService.Tokenize(message.UserInput);

            // HTC One and iPhone match words quite easily
            var cleanedTokens = (from t in tokens
                                 where t != "phone" && t != "phones" && t != "phone's" && t != "the" && t != "tone"
                                 select t.ToLower()).ToArray();

            (string matchedText, int matchedIndex, float ratio) = MatchService.FindMatch(cleanedTokens, 1, 4, deviceCatalog.MatchCharacters);
            var device = deviceCatalog.MakeModelList[matchedIndex];

            var deviceMatch = new DeviceMatchResult
            {
                Id          = device.Id,
                Make        = device.Make,
                Model       = device.Model,
                DisplayName = device.DisplayName,
                IsUncommon  = device.IsUncommon,
                Ratio       = ratio
            };

            double minConfidence = ChatConfiguration.MinimumDeviceConfidence;

            if (device.IsUncommon)
            {
                minConfidence = ChatConfiguration.MinimumUncommonDeviceConfidence;
            }
            if (deviceMatch.Ratio > minConfidence)
            {
                return(Task.FromResult(ParseResult.CreateSuccess(deviceMatch)));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #7
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var matches = Regex.Matches(message.UserInput, @"\d+")
                          .Cast <Match>()
                          .Select(m => m.Value)
                          .ToArray();

            if (matches.Length == 0)
            {
                return(Task.FromResult(ParseResult.Failed));
            }

            var setting = chatParseField?.GetProperty("AllowedValues");

            if (String.IsNullOrEmpty(setting))
            {
                return(Task.FromResult(ParseResult.CreateSuccess(int.Parse(matches[0]))));
            }

            var allowedValues = setting.Split(',', ' ');

            var foundValue = allowedValues.Where(b => matches.Any(a => b.Contains(a))).FirstOrDefault();

            if (foundValue == null)
            {
                return(Task.FromResult(ParseResult.Failed));
            }

            return(Task.FromResult(ParseResult.CreateSuccess(int.Parse(foundValue))));
        }
コード例 #8
0
        public async Task SendClassificationEvent(ChatModel chat, Chat_ParseField field, bool success, bool searchMode, ClassificationResults classification)
        {
            var content = CreateParseEventContent(chat, field, success, searchMode);

            var bestResult = classification.GetBestResult();

            if (bestResult != null)
            {
                content.Source            = bestResult.Source;
                content.Result            = bestResult.Intent;
                content.ResultData        = bestResult.Result;
                content.ResultProbability = bestResult.Probability;
            }

            content.Classifications = (from c in classification.AllResults
                                       select new KinesisClassification
            {
                Model_source = c.Source,
                Model_prediction = c.Intent,
                Model_score = c.Probability,
                Model_rawResponse = c.RawResponse
            }).ToArray();

            await InternalSendKinesisParseEvent("classification", "intent_classifier", chat, content);
        }
コード例 #9
0
        public override async Task <ParseResult> ParseAsync(ChatState chatState, Chat_ParseField chatParseField, ChatMessage message)
        {
            int timezoneOffset = chatState.GetUserTimeZoneOffset();

            if (message.LuisDateOutput == null)
            {
                message.LuisDateOutput = await luisService.Parse(message.UserInput, timezoneOffset);
            }

            var assumeFuture = false;

            if (bool.TryParse(chatParseField?.GetProperty("AssumeFuture"), out bool test))
            {
                assumeFuture = test;
            }

            var results = ExtractDateResults(chatState, message.LuisDateOutput, assumeFuture);

            if ((results == null) || (results.Length == 0))
            {
                logger.InfoFormat("Parse: luis date parser got nothing. - {0}", (message.LuisDateOutput != null) ? JsonConvert.SerializeObject(message.LuisDateOutput) : "null");
                return(ParseResult.Failed);
            }

            if (version == 1)
            {
                return(ProcessAsV1Date(message, timezoneOffset, results));
            }

            return(ParseResult.CreateSuccess(results));
        }
コード例 #10
0
        public virtual void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            if (result.Success)
            {
                GetChatVariables(state, flowStep, chatParseField.VarScope)[chatParseField.FieldName] = result.Answer;

                CheckIfAnswerHasPII(state, chatParseField, result.Answer.ToString(), PIIMask);
            }
        }
コード例 #11
0
        public virtual string GetTextSource(Chat_ParseField chatParseField, ChatMessage chatMessage)
        {
            if (chatParseField.SourceData == ChatSource.CorrectedInput)
            {
                return(chatMessage.CorrectedUserInput?.Trim());
            }

            return(chatMessage.UserInput?.Trim());
        }
コード例 #12
0
        private void UpdateV1State(ChatState state, Chat_ParseField chatParseField, ParseResult result, ChatVariables variables)
        {
            DateTime date   = (DateTime)result.Answer;
            int      offset = state.GetUserTimeZoneOffset();

            variables[chatParseField.FieldName]           = date.AddHours(offset).ToShortDateString();
            variables[chatParseField.FieldName + "_Date"] = date;

            CheckIfAnswerHasPII(state, chatParseField, date.ToString(), PIIMask);
        }
コード例 #13
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            string text = GetTextSource(chatParseField, message);

            if (Regex.IsMatch(text, DontKnowRegex, RegexOptions.IgnoreCase))
            {
                return(Task.FromResult(ParseResultDontKnow));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #14
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var match = Regex.Match(GetTextSource(chatParseField, message), ZipCodeRegex);

            if (match.Success)
            {
                return(Task.FromResult(ParseResult.CreateSuccess(match.Captures[0].Value)));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #15
0
        public override async Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var output = await addressParseService.Parse(chatId, state, GetTextSource(chatParseField, message));

            if (output?.addresses?.Length > 0)
            {
                return(ParseResult.CreateSuccess(output.addresses));
            }

            return(ParseResult.Failed);
        }
コード例 #16
0
        protected virtual void CheckIfAnswerHasPII(ChatState state, Chat_ParseField chatParseField, string answer, string mask)
        {
            var piiType = chatParseField.PIIType;

            if (piiType == PIIType.None)
            {
                piiType = PIIType;
            }

            CheckIfAnswerHasPII(state, piiType, answer, mask);
        }
コード例 #17
0
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            if (result.Success)
            {
                var variables = GetChatVariables(state, flowStep, chatParseField.VarScope);

                var intents = result.Answer as string[];
                variables[chatParseField.FieldName]          = intents[0];
                variables[chatParseField.FieldName + "List"] = intents;
            }
        }
コード例 #18
0
 private void CheckIfDatesHavePII(ChatState state, Chat_ParseField chatParseField, ParseResult parseResult)
 {
     DateTimeParseResult[] results = (DateTimeParseResult[])parseResult.Answer;
     foreach (var result in results)
     {
         if (result.DateTime.HasValue)
         {
             CheckIfAnswerHasPII(state, chatParseField, result.DateTime.Value.ToShortDateString(), PIIMask);
         }
     }
 }
コード例 #19
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            foreach (var provider in BackupProviders.ProviderNames)
            {
                if (BackupProviders.IsMatch(message.CorrectedUserInput, provider))
                {
                    return(Task.FromResult(ParseResult.CreateSuccess(provider)));
                }
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #20
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            // Check both corrected and original input, since our spell checker can't handle at&t properly.
            var result = Match(message.CorrectedUserInput);

            if (result.Success)
            {
                return(Task.FromResult(result));
            }

            return(Task.FromResult(Match(message.UserInput)));
        }
コード例 #21
0
ファイル: EmailParser.cs プロジェクト: asurionlabs/chatengine
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            var variables = GetChatVariables(state, flowStep, chatParseField.VarScope);

            if (result.Success)
            {
                variables[chatParseField.FieldName] = result.Answer;
                CheckIfAnswerHasPII(state, PIIType, result.Answer.ToString(), PIIMask);
            }

            if (!String.IsNullOrEmpty(foundPartial))
            {
                variables[$"{chatParseField.FieldName}_Try"] = foundPartial + ".com";
            }
        }
コード例 #22
0
ファイル: ColorParser.cs プロジェクト: asurionlabs/chatengine
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var(text, index, ratio) = MatchService.FindMatch(message.UserInput.ToLower(), 1, MaxTokenMatch, colorCatalog.ColorCodeChars);

            if (ratio < ChatConfiguration.MinimumColorMatchRatio)
            {
                return(Task.FromResult(ParseResult.Failed));
            }

            var color = colorCatalog.Colors[index];

            return(Task.FromResult(ParseResult.CreateSuccess(new ColorResult {
                Name = color.name, Ratio = ratio
            })));
        }
コード例 #23
0
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            base.UpdateState(state, flowStep, chatParseField, result);

            if (result.Success)
            {
                var addresses = result.Answer as AddressPart[];

                CheckIfAnswerHasPII(state, PIIType, addresses[0].address1, "ADDRESS");
                CheckIfAnswerHasPII(state, PIIType, addresses[0].address2, "ADDRESS");
                CheckIfAnswerHasPII(state, PIIType, addresses[0].city, "CITY");
                CheckIfAnswerHasPII(state, PIIType, addresses[0].region, "STATE");
                CheckIfAnswerHasPII(state, PIIType, addresses[0].postalCode, "ZIPCODE");
            }
        }
コード例 #24
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            if (String.Compare(message.CorrectedUserInput, "view solution", true) == 0)
            {
                return(Task.FromResult(ParseResult.CreateSuccess("viewedSolution")));
            }
            else if (Regex.IsMatch(message.CorrectedUserInput, ContinueRegex, RegexOptions.IgnoreCase))
            {
                return(Task.FromResult(ParseResultYes));
            }
            else if (Regex.IsMatch(message.CorrectedUserInput, YesNoParser.NoRegex, RegexOptions.IgnoreCase))
            {
                return(Task.FromResult(ParseResultNo));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #25
0
        public override async Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            if (message.LuisDamageClassifierOutput == null)
            {
                message.LuisDamageClassifierOutput = await luisService.Parse(message.CorrectedUserInput, 0);
            }

            string[] intents = message.LuisDamageClassifierOutput.GetIntents(ChatConfiguration.MinLuisConfidenceRatio);

            if (intents?.Length > 0)
            {
                return(ParseResult.CreateSuccess(intents));
            }

            // AVA-997: Always use None if we didn't parse anything.
            return(ParseResultNoneList);
        }
コード例 #26
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var matches = Regex.Matches(GetTextSource(chatParseField, message), AppNamesRegex, RegexOptions.IgnoreCase);

            if (matches.Count > 0)
            {
                string[] apps = new string[matches.Count];

                for (int i = 0; i < matches.Count; i++)
                {
                    apps[i] = matches[i].Value;
                }

                return(Task.FromResult(ParseResult.CreateSuccess(apps)));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #27
0
        public override Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            var matches = Regex.Matches(message.CorrectedUserInput, BluetoothDeviceNoRegex, RegexOptions.IgnoreCase);

            if (matches.Count > 0)
            {
                string[] apps = new string[matches.Count];

                for (int i = 0; i < matches.Count; i++)
                {
                    apps[i] = matches[i].Value;
                }

                return(Task.FromResult(ParseResult.CreateSuccess(apps)));
            }

            return(Task.FromResult(ParseResult.Failed));
        }
コード例 #28
0
        public override async Task <ParseResult> ParseAsync(ChatState state, Chat_ParseField chatParseField, ChatMessage message)
        {
            int matchThreshold = ChatConfiguration.FuzzyNameMatchThreshold;

            if (!String.IsNullOrEmpty(chatParseField.RuleData))
            {
                matchThreshold = Convert.ToInt32(chatParseField.RuleData);
            }

            FuzzyMatchParserData[] possibleMatches = await GetPossibleMatches(state, chatFlowStep, chatParseField);

            if (UtilityMethods.IsNullOrEmpty(possibleMatches))
            {
                logger.WarnFormat("Parse: Invalid field data for fuzzy match. {0} - {1}", chatParseField.FieldName, chatParseField.SourceData);
                return(ParseResult.Failed);
            }

            // Get list of test values for API
            var testVals = possibleMatches.Select(x => x.text).ToArray();
            var response = await fuzzyMatchService.Match(GetTextSource(chatParseField, message), testVals);

            if (response == null)
            {
                logger.Error("Network: Failed to call fuzzy match service.");
                return(ParseResult.Failed);
            }

            if (response.Output?.Length > 0)
            {
                IEnumerable <FuzzyMatchParserResult> matches = FindMatches(matchThreshold, possibleMatches, response);

                if (matches.Count() > 0)
                {
                    return(ParseResult.CreateSuccess(matches.First()));
                }
            }
            else
            {
                logger.Debug("Parse: No fuzzy matches found.");
            }

            // Always return true that we processed the text even if we didnt find a matching name.
            return(ParseResult.CreateSuccess(null));
        }
コード例 #29
0
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult parseResult)
        {
            if (!parseResult.Success)
            {
                return;
            }

            var variables = GetChatVariables(state, flowStep, chatParseField.VarScope);

            if (version == 1)
            {
                UpdateV1State(state, chatParseField, parseResult, variables);
                return;
            }

            CheckIfDatesHavePII(state, chatParseField, parseResult);

            variables[chatParseField.FieldName] = parseResult.Answer;
        }
コード例 #30
0
        public override void UpdateState(ChatState state, ChatFlowStep flowStep, Chat_ParseField chatParseField, ParseResult result)
        {
            var variables = GetChatVariables(state, flowStep, chatParseField.VarScope);

            if (result.Success && (result.Answer is FuzzyMatchParserResult answer))
            {
                // Convert back to Dictionary for proper formatting, and script access
                var x = JsonConvert.SerializeObject(answer);
                variables[chatParseField.FieldName + "_MatchInfo"] = JsonConvert.DeserializeObject <Dictionary <string, object> >(x);
                variables[chatParseField.FieldName] = true;

                // Send both user's input and matched input as PII.
                CheckIfAnswerHasPII(state, chatParseField, answer.match.ToString(), PIIMask);
                CheckIfAnswerHasPII(state, chatParseField, answer.text.ToString(), PIIMask);
            }
            else
            {
                variables[chatParseField.FieldName] = false;
            }
        }