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); } }
public FuzzyMatchParser(ChatModel chatModel, FuzzyMatchService fuzzyMatchService, IChatScriptManager chatScriptManager, ChatFlowStep chatFlowStep) { this.fuzzyMatchService = fuzzyMatchService; this.chatFlowStep = chatFlowStep; this.chatModel = chatModel; this.chatScriptManager = chatScriptManager; }
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); } }
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)); }
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)); }
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(); } } }
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; } } } } }
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"); } }
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); }
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; }
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)); }
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; } }
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); }
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); }
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); } } }
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); }
protected ChatVariables GetChatVariables(ChatState state, ChatFlowStep flowStep, VariableScope scope) { return(scope == VariableScope.Local ? state.GetFlowAnswers(flowStep.Flow) : state.GlobalAnswers); }
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); }
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); }
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(); } } }