Ejemplo n.º 1
0
        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);
            }
        }
Ejemplo n.º 2
0
 public FuzzyMatchParser(ChatModel chatModel, FuzzyMatchService fuzzyMatchService, IChatScriptManager chatScriptManager, ChatFlowStep chatFlowStep)
 {
     this.fuzzyMatchService = fuzzyMatchService;
     this.chatFlowStep      = chatFlowStep;
     this.chatModel         = chatModel;
     this.chatScriptManager = chatScriptManager;
 }
Ejemplo n.º 3
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);
            }
        }
Ejemplo n.º 4
0
        public Task <bool> IsConditionMet(ChatModel chatModel, ChatFlowStep chatFlowStep, Chat_ChildRef childRef)
        {
            if (!initialized)
            {
                throw new ApplicationException("ChatScriptManager is not initialized.  Call Initialize()");
            }

            if (String.IsNullOrEmpty(childRef.Condition))
            {
                return(Task.FromResult(true));
            }

            ChatVariables globalFields = chatModel.CurrentState.GlobalAnswers;
            ChatVariables flowFields   = chatModel.CurrentState.GetFlowAnswers(chatFlowStep.Flow);

            if (AwsUtilityMethods.IsRunningOnAWS)
            {
                AWSXRayRecorder.Instance.BeginSubsegment("Script: Evaluate Condition");
            }
            try
            {
                //logger.DebugFormat("Script: IsConditionMet Start. '{0}'", childRef.Condition);

                return(Task.FromResult(
                           RunScript <bool>((engine, globalValues, flowValues) =>
                {
                    var result = engine.Evaluate(childRef.Condition);

                    if (!(result is bool))
                    {
                        logger.WarnFormat("Script: IsCondition did not return true/false.  Evaluating with Javascript rules. '{0}', result: '{1}'", childRef.Condition, result);
                    }

                    return UtilityMethods.ParseJavascriptBoolean(result);
                }, globalFields, flowFields, null)
                           ));
            }
            catch (Exception ex)
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.AddException(ex);
                }
                logger.ErrorFormat("Script: IsConditionMet Error. '{0}' '{1}'", childRef.Condition, ex.Message);
            }
            finally
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.EndSubsegment();
                }
            }

            return(Task.FromResult(false));
        }
Ejemplo n.º 5
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;
            }
        }
        public async Task CheckEmptyObject()
        {
            ChatModel    chatModel    = new ChatModel();
            ChatFlowStep chatFlowStep = new ChatFlowStep()
            {
                Actions = new List <string> {
                    "s.AAA = JSON.parse('{}');"
                }
            };

            await scriptManager.ProcessActions(chatModel, chatFlowStep, null, false);

            Assert.IsInstanceOfType(chatModel.CurrentState.GlobalAnswers.FieldAnswers["AAA"], typeof(object));
        }
Ejemplo n.º 7
0
        public Task <ErrorHandlerResult> ProcessErrorHandler(ChatModel chatModel, ChatFlowStep chatFlowStep)
        {
            if (!initialized)
            {
                throw new ApplicationException("ChatScriptManager is not initialized.  Call Initialize()");
            }

            string        script       = chatFlowStep.ErrorHandler;
            ChatVariables globalFields = chatModel.CurrentState.GlobalAnswers;
            ChatVariables flowFields   = chatModel.CurrentState.GetFlowAnswers(chatFlowStep.Flow);

            if (AwsUtilityMethods.IsRunningOnAWS)
            {
                AWSXRayRecorder.Instance.BeginSubsegment("Script: Process Parser Error Handler");
            }
            try
            {
                return(Task.FromResult(
                           RunScript <ErrorHandlerResult>((engine, globalValues, flowValues) =>
                {
                    dynamic result = engine.Evaluate(script);
                    if (result == null)
                    {
                        return null;
                    }

                    ConvertFieldsToNative(globalFields, globalValues, true);
                    ConvertFieldsToNative(flowFields, flowValues, false);

                    return ScriptHelpers.ConvertToType <ErrorHandlerResult>(result);
                }, globalFields, flowFields, null)
                           ));
            }
            catch (Exception ex)
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.AddException(ex);
                }
                logger.ErrorFormat("Script: Process Parser Error Handler Error. '{0}'", ex.Message);
                throw;
            }
            finally
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.EndSubsegment();
                }
            }
        }
Ejemplo n.º 8
0
        private async Task PostProcessResults(ClassificationResults results, ChatFlowStep postFlowStep)
        {
            if (results.ClassifierResults == null)
            {
                return;
            }

            foreach (var classification in results.ClassifierResults)
            {
                if (classification.Source != "intentgateway")
                {
                    continue;
                }

                if (classification.RawResponse == null)
                {
                    continue;
                }

                object postProcessResult = await chatScriptManager.ProcessActions(chatModel, postFlowStep, JsonConvert.DeserializeObject <dynamic>(classification.RawResponse), true);

                if (postProcessResult == null)
                {
                    continue;
                }

                if (postProcessResult is string text)
                {
                    classification.Result = text;
                    classification.Intent = text;
                }
                else
                {
                    classification.Result = postProcessResult.FromScriptValue();

                    if (classification.Result is Dictionary <string, object> dictionaryResults)
                    {
                        if (dictionaryResults.ContainsKey("intent"))
                        {
                            classification.Intent = dictionaryResults["intent"] as string;
                        }
                        if (dictionaryResults.ContainsKey("score") && dictionaryResults["score"] is double score)
                        {
                            classification.Probability = score;
                        }
                    }
                }
            }
        }
Ejemplo n.º 9
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");
            }
        }
Ejemplo n.º 10
0
        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";
            }
        }
        public async Task CheckObject()
        {
            ChatModel    chatModel    = new ChatModel();
            ChatFlowStep chatFlowStep = new ChatFlowStep()
            {
                Actions = new List <string> {
                    "s.AAA = JSON.parse('{ \"abc\" : 5 }');"
                }
            };

            await scriptManager.ProcessActions(chatModel, chatFlowStep, null, false);

            Assert.IsInstanceOfType(chatModel.CurrentState.GlobalAnswers.FieldAnswers["AAA"], typeof(Dictionary <string, object>));
            Dictionary <string, object> aaa = chatModel.CurrentState.GlobalAnswers.FieldAnswers["AAA"] as Dictionary <string, object>;

            Assert.AreEqual(aaa.Keys.Count, 1);
            Assert.AreEqual(aaa["abc"], 5);
        }
Ejemplo n.º 12
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;
        }
Ejemplo n.º 13
0
        public static string FormatMessage(ChatState state, ChatFlowStep step)
        {
            string text = null;

            // Check for carrier override text
            if (step.CarrierMessages != null)
            {
                string partner = state.GlobalAnswers.GetFieldAnswer <string>(ChatStandardField.Partner);
                text = (from m in step.CarrierMessages
                        where m.CarrierName == partner
                        select m.Message).FirstOrDefault();
            }

            if (String.IsNullOrEmpty(text))
            {
                text = step.GetText();
            }

            return(FormatMessage(state, step.Flow, text));
        }
Ejemplo n.º 14
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;
            }
        }
Ejemplo n.º 15
0
        public async Task <bool> IsConditionMet(ChatModel chatModel, ChatFlowStep chatFlowStep, Chat_ChildRef childRef)
        {
            if (String.IsNullOrEmpty(childRef.Condition))
            {
                return(true);
            }

            logger.DebugFormat("Script: IsConditionMet Start. '{0}'", childRef.Condition);

            var functionName = String.Format($"cond{chatFlowStep.Id}_{childRef.Id}");

            var result = await ExecuteNode(chatModel, chatFlowStep.Flow, functionName, null);

            if (!UtilityMethods.IsNullOrEmpty(result) && result[0] is NodeConditionResponse conditionResponse)
            {
                return(conditionResponse.Result);
            }

            return(false);
        }
Ejemplo n.º 16
0
        public async Task SendFailToUnderstandEvent(ChatModel chat, ChatFlowStep flowStep)
        {
            if (chat == null)
            {
                return;
            }

            var lastMessage = chat.CurrentState.GetLastMessage();

            var properties = new Dictionary <string, object>();

            AddStandardProperties(chat.CurrentState.SessionData, properties);

            KinesisLogEvent logEvent = new KinesisLogEvent
            {
                Session_id       = chat.SessionLogId,
                Logger_info      = String.Format("flow_engine:{0}:{1}", flowStep.Flow, flowStep.Id),
                Application_info = chat.CurrentState.SessionData.PartnerContext,
                Data             = "",
                Log           = "",
                To_index      = true,
                Index_type    = "engine_flowfailure",
                Index_name    = "flow_failures",
                Index_content = new
                {
                    chat_id    = chat.ChatId,
                    session_id = chat.SessionLogId,
                    // Can't use standard "o" format, since it provides 6 digit milliseconds, which causes errors when its saved to Dynamo
                    timestamp           = AWSDynamoService.ToDynamoDateString(DateTime.UtcNow),
                    step                = new ChatStepId(flowStep),
                    chat_text           = filterService.FilterUserData(chat.CurrentState, lastMessage.UserInput),
                    chat_corrected_text = filterService.FilterUserData(chat.CurrentState, lastMessage.CorrectedUserInput),
                    bot_text            = filterService.FilterUserData(chat.CurrentState, lastMessage.BotQuestionsText),
                    properties
                }
            };

            await PutRecordInternalAsync(logEvent);
        }
Ejemplo n.º 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);

                if (foundBadNumber)
                {
                    variables[$"{chatParseField.FieldName}_Bad"] = true;
                }
                else
                {
                    var rawNumber = StripToNumber(result.Answer as string);

                    variables[chatParseField.FieldName]          = rawNumber;
                    variables[$"{chatParseField.FieldName}_Bad"] = null;

                    // Set both exact user input, and parsed raw number as pii
                    CheckIfAnswerHasPII(state, PIIType, rawNumber, PIIMask);
                    CheckIfAnswerHasPII(state, PIIType, result.Answer as string, PIIMask);
                }
            }
        }
Ejemplo n.º 18
0
        public async Task <ErrorHandlerResult> ProcessErrorHandler(ChatModel chatModel, ChatFlowStep chatFlowStep)
        {
            logger.DebugFormat("Script: ProcessErrorHandler Start - Remote NodeJS. {0}:{1}", chatFlowStep.Flow, chatFlowStep.Id);

            var functionName = String.Format($"ErrorHandler{chatFlowStep.Id}_{FormatFunctionName(chatFlowStep.Name)}");

            var result = await ExecuteNode(chatModel, chatFlowStep.Flow, functionName, null);

            logger.DebugFormat("Script: ProcessErrorHandler End - Remote NodeJS. {0}:{1}", chatFlowStep.Flow, chatFlowStep.Id);

            return(null);
        }
Ejemplo n.º 19
0
 protected ChatVariables GetChatVariables(ChatState state, ChatFlowStep flowStep, VariableScope scope)
 {
     return(scope == VariableScope.Local ? state.GetFlowAnswers(flowStep.Flow) : state.GlobalAnswers);
 }
Ejemplo n.º 20
0
        public async Task <object> ProcessActions(ChatModel chatModel, ChatFlowStep chatFlowStep, object functionParams, bool expectResult)
        {
            ScriptHost.ClearProperties();

            if (chatFlowStep.Actions == null &&
                chatFlowStep.ObjectType != ChatObjectType.Message &&
                chatFlowStep.ObjectType != ChatObjectType.StaticMessage)
            {
                return(null);
            }

            logger.DebugFormat("Script: ProcessActions Start - Remote NodeJS. {0}:{1}", chatFlowStep.Flow, chatFlowStep.Id);

            object result       = null;
            var    functionName = $"{chatFlowStep.ObjectType}{chatFlowStep.Id}_{FormatFunctionName(chatFlowStep.Name)}";

            var response = await ExecuteNode(chatModel, chatFlowStep.Flow, functionName, functionParams);

            if (!UtilityMethods.IsNullOrEmpty(response))
            {
                foreach (var item in response)
                {
                    switch (item)
                    {
                    case NodeAbortResponse abortResponse: ChatScriptHost.Abort(abortResponse.Result); break;

                    // TODO: Check if actionResponse is different meaning than nodeVariableResponse
                    case NodeActionResponse actionResponse: result = actionResponse.Result?.FromScriptValue(); break;

                    case NodeAddPiiTextResponse addPiiTextResponse:
                    {
                        ChatScriptHost.AddPiiText(addPiiTextResponse.Result.PiiType,
                                                  addPiiTextResponse.Result.Text,
                                                  addPiiTextResponse.Result.Mask);
                        break;
                    }

                    case NodeCallFlowResponse callFlowResponse: ChatScriptHost.CallFlow(callFlowResponse.Result.FlowName, callFlowResponse.Result.Params); break;

                    case NodeChangeContextResponse changeContextResponse: ChatScriptHost.ChangeContext(changeContextResponse.Result.Partner, changeContextResponse.Result.Context); break;

                    case NodeErrorResponse errorResponse: throw new ScriptException(errorResponse.Stack, chatFlowStep.Flow, chatFlowStep.Id);

                    case NodeIncreaseFailureCountResponse increaseFailureCountResponse: ChatScriptHost.IncreaseFailureCount(); break;

                    case NodeLogResponse logResponse: ChatScriptHost.LogInfoMessage(logResponse.Result); break;

                    case NodeMessageResponse messageResponse: ChatScriptHost.UI("", messageResponse.Result); break;

                    case NodeSendEmailResponse sendEmailResponse:
                    {
                        ChatScriptHost.SendEmail(sendEmailResponse.Result.From,
                                                 sendEmailResponse.Result.Recipients,
                                                 sendEmailResponse.Result.Subject,
                                                 sendEmailResponse.Result.Body,
                                                 sendEmailResponse.Result.IsBodyHtml);
                        break;
                    }

                    case NodeSendTagEventResponse sendTagEventResponse: ChatScriptHost.SendTagEvent(sendTagEventResponse.Result.TagName, sendTagEventResponse.Result.Properties); break;

                    case NodePutKinesisEventResponse putKinesisEventResponse:
                    {
                        ChatScriptHost.PutKinesisEvent(putKinesisEventResponse.Result.Arn,
                                                       putKinesisEventResponse.Result.StreamName,
                                                       putKinesisEventResponse.Result.StsRoleSessionName,
                                                       putKinesisEventResponse.Result.PartitionKey,
                                                       putKinesisEventResponse.Result.EventData);
                        break;
                    }

                    case NodeSetQuickRepliesResponse setQuickRepliesResponse: ChatScriptHost.SetQuickReplies(setQuickRepliesResponse.Result.Choices); break;

                    case NodeTransferToAgentResponse transferToAgentResponse:
                    {
                        ChatScriptHost.TransferToAgent(transferToAgentResponse.Result.TransferInfo, transferToAgentResponse.Result.Skill);
                        break;
                    }

                    case NodeUiResponse uiResponse: ChatScriptHost.UI(uiResponse.Result.CustomMarkup, uiResponse.Result.PlainText); break;

                    case NodeVariableResponse variableResponse: result = variableResponse.Result; break;
                    }
                }
            }

            logger.DebugFormat("Script: ProcessActions End - Remote NodeJS. {0}:{1}", chatFlowStep.Flow, chatFlowStep.Id);

            return(result);
        }
Ejemplo n.º 21
0
        private async Task <FuzzyMatchParserData[]> GetPossibleMatches(ChatState state, ChatFlowStep chatFlowStep, Chat_ParseField chatParseField)
        {
            FuzzyMatchParserData[] possibleMatches = null;

            var data = await chatScriptManager.GetVariable(chatModel, chatFlowStep.Flow, chatParseField.SourceData);

            if (data == null)
            {
                // Direct string array entered in source data
                possibleMatches = (from rd in chatParseField.SourceData.Split(',')
                                   select new FuzzyMatchParserData {
                    text = rd, value = rd
                }).ToArray();
            }
            else if (data is string stringData)
            {
                // Rule data variable set to just a string
                possibleMatches = (from rd in ((string)stringData).Split(',')
                                   select new FuzzyMatchParserData {
                    text = rd, value = rd
                }).ToArray();
            }
            else if (data is Newtonsoft.Json.Linq.JValue valueData)
            {
                // Rule data variable set to just a string
                possibleMatches = (from rd in ((string)valueData.Value).Split(',')
                                   select new FuzzyMatchParserData {
                    text = rd, value = rd
                }).ToArray();
            }
            else
            {
                // Convert script dictionary array to actual object
                var x = JsonConvert.SerializeObject(data);

                // TODO: Detect deserialization errors in case script gives bad data.
                // We want a nice error back in the response so its easier to figure out.
                possibleMatches = JsonConvert.DeserializeObject <FuzzyMatchParserData[]>(x);
                possibleMatches = possibleMatches.Where(m => !String.IsNullOrEmpty(m.text)).ToArray();
            }

            return(possibleMatches);
        }
Ejemplo n.º 22
0
        public Task <object> ProcessActions(ChatModel chatModel, ChatFlowStep chatFlowStep, object functionParams, bool expectResult)
        {
            if (!initialized)
            {
                throw new ApplicationException("ChatScriptManager is not initialized.  Call Initialize()");
            }

            ChatVariables globalFields = chatModel.CurrentState.GlobalAnswers;
            ChatVariables flowFields   = chatModel.CurrentState.GetFlowAnswers(chatFlowStep.Flow);

            ScriptHost.ClearProperties();

            if (chatFlowStep.Actions == null)
            {
                return(Task.FromResult <object>(null));
            }

            //logger.DebugFormat("Script: ProcessActions Start JScriptEngine. {0}:{1}", chatFlowStep.Flow, chatFlowStep.Id);

            object result = null;

            if (AwsUtilityMethods.IsRunningOnAWS)
            {
                AWSXRayRecorder.Instance.BeginSubsegment("Script: ProcessActions");
            }
            try
            {
                return(Task.FromResult(
                           RunScript <object>((engine, globalValues, flowValues) =>
                {
                    // Performance optimization for ClearScript.
                    // If we dont want the result, we dont need to marshal the result back.
                    chatFlowStep.Actions.ForEach(action => result = RunAction(engine, action, expectResult));

                    ConvertFieldsToNative(globalFields, globalValues, true);
                    ConvertFieldsToNative(flowFields, flowValues, false);
                    return result;
                }, globalFields, flowFields, functionParams)
                           ));
            }
            catch (Exception ex)
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.AddException(ex);
                }

                if (ex is Microsoft.ClearScript.ScriptEngineException scriptEx)
                {
                    logger.ErrorFormat("Script: ProcessActions Error. '{0}'", scriptEx.ErrorDetails);
                    throw new ScriptException(scriptEx.ErrorDetails, ex, chatFlowStep.Flow, chatFlowStep.Id);
                }

                logger.ErrorFormat("Script: ProcessActions Error. '{0}'", ex.Message);
                throw;
            }
            finally
            {
                if (AwsUtilityMethods.IsRunningOnAWS)
                {
                    AWSXRayRecorder.Instance.EndSubsegment();
                }
            }
        }