Name
global.AutoResolutionPredictionHelper
Description
A helper for AutoResolution prediction result processing
Script
var AutoResolutionPredictionHelper = Class.create();
AutoResolutionPredictionHelper.prototype = {
initialize: function(configId, notificationUserId) {
this.configId = configId;
this.notificationUserId = notificationUserId;
},
/**
* @param intents - list of intent maps returned by predictAPI
* @return {intents: [], nluIntent: , matchedTopic: , intentTopicState: , intentTopicStateReason: , predictionConfidence: }
**/
getIntentAndTopicDetails: function(intents) {
var returnObject = {intents: []};
if (!gs.nil(intents) && JSON.stringify(intents) !== '{}' && intents.length > 0) {
returnObject.intents = intents;
var objs = [];
//For Q consider only the Top-1 intent
var intent = returnObject.intents[0];
var nluIntent = intent['predictedValue'];
returnObject.predictionConfidence = intent['confidence'];
if (nluIntent) {
if (this._isIntentUnsupported(nluIntent)) {
returnObject.nluIntent = nluIntent;
returnObject.matchedTopic = '';
returnObject.intentTopicState = AutoResolutionConstants.INTENT_TOPIC_STATE['NO_MATCHED_TOPIC'];
returnObject.intentTopicStateReason = AutoResolutionConstants.NO_MATCHED_TOPIC_REASON['UNSUPPORTED_INTENT'];
return returnObject;
}
return this.processIntent(nluIntent);
}
}
// case when no intents are returned from the predictAPI
returnObject.nluIntent = '';
returnObject.matchedTopic = '';
returnObject.intentTopicState = AutoResolutionConstants.INTENT_TOPIC_STATE['NO_INTENT'];
returnObject.intentTopicStateReason = AutoResolutionConstants.NO_INTENT_REASON['NO_INTENT_FROM_API'];
return returnObject;
},
/**
*
* @param intent - String name of a valid intent
* @returns {{"nluIntent": string, "matchedTopic": string,
* "intentTopicState": string, "intentTopicStateReason": string}}
*/
processIntent: function(intent) {
var intentTopicRetObj = this.getMatchedTopicFromIntentMapTable(intent);
if (!intentTopicRetObj.intentExists)
return {
nluIntent: intent,
matchedTopic: '',
intentTopicState: AutoResolutionConstants.INTENT_TOPIC_STATE['NO_INTENT'],
intentTopicStateReason: AutoResolutionConstants.NO_INTENT_REASON['NO_INTENT_TOPIC_MAPPING'],
};
var matchedTopicId = intentTopicRetObj.matchedTopicSysId;
var isTopicActive = this._isTopicActive(matchedTopicId);
var isIntentTopicMapActive = intentTopicRetObj.activeIntentMap === '1';
var isTopicAccessible = this._isTopicAccessible(matchedTopicId);
// Issue Auto-Resolution topic
var isIARWrapperTopicAccessible = this._isTopicAccessible('86cf6a4e5316101055eeddeeff7b12ba');
var intentAndTopicDetails = {
nluIntent: intent,
matchedTopic: '',
intentTopicState: AutoResolutionConstants.INTENT_TOPIC_STATE['FOUND_MATCHED_TOPIC'],
intentTopicStateReason: '',
};
if (!isIntentTopicMapActive)
intentAndTopicDetails.intentTopicStateReason = AutoResolutionConstants.NO_MATCHED_TOPIC_REASON['INTENT_TOPIC_MAP_INACTIVE'];
else if (!isTopicActive)
intentAndTopicDetails.intentTopicStateReason = AutoResolutionConstants.NO_MATCHED_TOPIC_REASON['INACTIVE_TOPIC'];
else if (!isTopicAccessible || !isIARWrapperTopicAccessible)
intentAndTopicDetails.intentTopicStateReason = AutoResolutionConstants.NO_MATCHED_TOPIC_REASON['TOPIC_INACCESSIBLE'];
else if (!gs.nil(matchedTopicId))
intentAndTopicDetails.matchedTopic = matchedTopicId;
return intentAndTopicDetails;
},
getMatchedTopicFromIntentMapTable: function(intent) {
var intentMapRetObj = {};
var intentTopicMapGr = new GlideRecord(AutoResolutionConstants.INTENT_TOPIC_MAP_TABLE_NAME);
intentTopicMapGr.addQuery('ar_intent', intent);
intentTopicMapGr.addQuery('ar_configuration', this.configId);
intentTopicMapGr.query();
if (intentTopicMapGr.next()) {
intentMapRetObj.intentExists = true;
intentMapRetObj.activeIntentMap = intentTopicMapGr.getValue('active');
intentMapRetObj.matchedTopicSysId = intentTopicMapGr.getValue('matched_topic');
return intentMapRetObj;
}
intentMapRetObj.intentExists = false;
intentMapRetObj.matchedTopicSysId = '';
return intentMapRetObj;
},
_isIntentUnsupported: function(nluIntent) {
var intentArr = nluIntent.split(AutoResolutionConstants.UNSUPPORTED_MATCHED_INTENT_SEPARATOR);
if (!gs.nil(intentArr) && intentArr.length > 0)
return intentArr.indexOf(AutoResolutionConstants.UNSUPPORTED_INTENT_STRING) >= 0;
return false;
},
_isTopicActive: function(topicId) {
var grTopic = new GlideRecord('sys_cs_topic');
grTopic.get(topicId);
return grTopic.active;
},
_isTopicAccessible: function(topicId) {
if (gs.nil(this.notificationUserId)) return true; // simulation
var grTopic = new GlideRecord('sys_cs_topic');
grTopic.get(topicId);
var topicRoles = grTopic.roles + '';
topicRoles = topicRoles.split(',');
var notificationUser = gs.getUser().getUserByID(this.notificationUserId);
var isGuestUser = notificationUser.name === 'guest';
var hasRole = false;
for (var i = 0; i < topicRoles.length; i++) {
if (topicRoles[i] === 'public') {
hasRole = true;
break;
}
if (!isGuestUser && notificationUser.hasRole(topicRoles[i])) {
hasRole = true;
break;
}
}
return hasRole;
},
};
/**
* Processes the prediction results. This method creates one prediction record and output records.
*
* @param logger
* @param contextId
* @param solutionName
* @param languageXResult the languageX result in JSON format
*
* eg: {
* "schemaVersion": "1.0",
* "status": {
* "code": 200,
* "message": "SUCCESS"
* },
* "result": [
* {
* "input": {
* "id": "6e7e0ee577ac0110f14a24f1cd5a99c6",
* "tableName": "sn_hr_core_case",
* "fields": {
* "description": "I lost access to benefits portal"
* }
* },
* "output": [
* {
* "service": "languageDetection",
* "serviceOutput": "en",
* "serviceOutputScore": 0.9963439,
* "serviceOutputDetails": ""
* },
* {
* "service": "criticalityDetection",
* "serviceOutput": "Benefits-NonCritical",
* "serviceOutputScore": 0.94924694,
* "serviceOutputDetails": "{\"status\":\"success\",\"response\":{\"utterance\":\"I lost access to benefits portal\",\"intents\":[{\"intentName\":\"Benefits-NonCritical\",\"nluModelName\":\"ml_x_snc_global_global_087ad49d1b9eb0101115da01b24bcb70\",\"score\":0.94924694,\"intents\":[]}],\"properties\":{\"inference.time\":\"12\",\"nluPlatformLanguage\":\"en\",\"nluPlatformVersion\":\"3.1.2-HYB\"}}}"
* },
* {
* "service": "searchQueryGeneration",
* "serviceOutput": "",
* "serviceOutputScore": "",
* "serviceOutputDetails": "[{\"query\":\"benefits portal\",\"score\":\"0.83\"},{\"query\":\"access\",\"score\":\"0.73\"}]"
* }
* ]
* }
* ]
*}
*
* @param execTime the time taken for language-X API invocation in millisecond
*/
AutoResolutionPredictionHelper.processPredictionResults = function(logger, contextId, solutionName, languageXResult, execTime) {
if (gs.nil(languageXResult)) {
// predictionResult should exist
return createReturnObject(
AutoResolutionConstants.STATUS_ERROR,
'LanguageX prediction results are invalid or empty');
}
// create a prediction record
var predictionSysId = createPredictionRecord(contextId, solutionName, languageXResult, execTime);
var resultBlock = languageXResult.result;
if (gs.nil(resultBlock) || resultBlock.length == 0 || gs.nil(resultBlock[0].output) || resultBlock[0].output.length == 0) {
return createReturnObject(
AutoResolutionConstants.STATUS_ERROR,
"LanguageX prediction result's outputs are invalid or empty",
predictionSysId);
}
// an array of outputs
var outputs = resultBlock[0].output;
var outputSysIds = processPredictionOutputs(predictionSysId, outputs);
//if the status code is not 200, report it back to the caller
if (languageXResult.status.code != 200 ) {
return createReturnObject(
AutoResolutionConstants.STATUS_ERROR, languageXResult.message);
}
return createReturnObject(
AutoResolutionConstants.STATUS_SUCCESS, 'Successfully saved LanguageX prediction results',
predictionSysId, outputSysIds);
};
/**
* Returns the prediction output object for the passed service.
*
* The service can be one of the following: global.AutoResolutionConstants.LANGUAGE_DETECTION_SERVICE_NAME ,
* global.AutoResolutionConstants.CRITICALITY_PREDICTION_SERVICE_NAME,
* global.AutoResolutionConstants.SEARCH_QUERY_GENERATION_SERVICE_NAME
*
* @param predictionSysId : the sysId of the prediction record
* @param service : the prediction service name that is available via LanguageX
* @return {AutoResolutionPredictionOutput} a prediction output instance. Null if not found
*/
AutoResolutionPredictionHelper.getPredictionOutputByService = function(predictionSysId, service) {
var prediction = new global.AutoResolutionPrediction(predictionSysId);
return prediction.getPredictionOutputByService(service);
};
/**
* Returns the prediction output object for Criticality Service
*
* @param predictionSysId : the sysId of the prediction record
* @return {AutoResolutionPredictionOutput} a prediction output instance. Null if not found
*/
AutoResolutionPredictionHelper.getPredictionOutputByCriticalityService = function(predictionSysId) {
return global.AutoResolutionPredictionHelper.getPredictionOutputByService(
predictionSysId, global.AutoResolutionConstants.CRITICALITY_PREDICTION_SERVICE_NAME);
};
/**
* Submits a feedback for the specified service
*
* The service can be one of the following: global.AutoResolutionConstants.LANGUAGE_DETECTION_SERVICE_NAME ,
* global.AutoResolutionConstants.CRITICALITY_PREDICTION_SERVICE_NAME,
* global.AutoResolutionConstants.SEARCH_QUERY_GENERATION_SERVICE_NAME
* @param predictionSysId : the sysId of the prediction record
* @param service : the prediction service name that is available via LanguageX
* @param feedback : the feedback to sent
* @return true if the submission succeeded. false, otherwise
*/
AutoResolutionPredictionHelper.submitFeedbackForService = function(predictionSysId, service, feedback) {
var output = global.AutoResolutionPredictionHelper.getPredictionOutputByService(predictionSysId, service);
if (gs.nil(output))
return false;
var result = output.submitFeedback(feedback);
if(result)
output.update();
return result;
};
/**
* Submits a feedback for the specified service
*
* @param predictionSysId : the sysId of the prediction record
* @param feedback : the feedback to sent
* @return true the submission succeeded. false, otherwise
*/
AutoResolutionPredictionHelper.submitFeedbackForCriticalityService = function(predictionSysId, feedback) {
return global.AutoResolutionPredictionHelper.submitFeedbackForService(
predictionSysId, global.AutoResolutionConstants.CRITICALITY_PREDICTION_SERVICE_NAME, feedback);
};
/**
* Returns the search query from prediction table that is generated from LangX
*/
AutoResolutionPredictionHelper.getSearchQueryByPredictionId = function(predictionId) {
var prediction = new global.AutoResolutionPrediction(predictionId);
return prediction.getPredictedSearchQuery();
};
/**
* Returns the search query from prediction table that is generated from LangX
*/
AutoResolutionPredictionHelper.getSearchQueryByContext = function(contextRecord) {
return contextRecord.prediction.predicted_search_query || '';
};
/**
* Returns the id of the prediction record given the id of the context
* @param {string} The sys_id of the auto resolution context
* @return {string} The sys_id of the prediction record
*/
AutoResolutionPredictionHelper.getPredictionId = function(contextId) {
var predictionGr = new GlideRecord(global.AutoResolutionConstants.PREDICTION_TABLE_NAME);
predictionGr.addQuery("ar_context", contextId);
predictionGr.query();
predictionGr.next();
return predictionGr.getUniqueValue();
};
/**
* Updates the prediction table
*/
AutoResolutionPredictionHelper.updatePredictionResults = function(predictionSysId, fields, logger) {
// Update the prediction record with the result from the extension point
var predictionGr = new GlideRecord(global.AutoResolutionConstants.PREDICTION_TABLE_NAME);
if (!predictionGr.get(predictionSysId)) {
logger.error("Could not find the prediction record with the sys_id:{0}", predictionSysId);
return;
}
var needToUpdate = false;
for (var fieldName in fields) {
predictionGr.setValue(fieldName, fields[fieldName]);
needToUpdate = true;
}
predictionGr.update();
};
/**
* process prediction outputs
*/
function processPredictionOutputs(predictionSysId, outputs) {
var arr = [];
for (var i=0; i<outputs.length; i++)
arr.push(AutoResolutionPredictionOutput.create(predictionSysId, outputs[i]));
return arr;
}
/**
* Creates a return object for the passed inputs
*/
function createReturnObject( status, message, predictionId, outputIds ) {
var res = {};
if (!gs.nil(status))
res.status = status;
if (!gs.nil(message))
res.message = message;
if (!gs.nil(predictionId))
res.prediction_id = predictionId;
if (!gs.nil(outputIds) && outputIds.length > 0)
res.output_ids = outputIds;
else
res.output_ids = [];
return res;
}
/**
* Creates a new precition record
*/
function createPredictionRecord(contextId, solutionName, predictionResult, execTime) {
var gr = new GlideRecord(AutoResolutionConstants.PREDICTION_TABLE_NAME);
gr.setValue('ar_context', contextId);
gr.setValue('solution_name', solutionName);
gr.setValue('schema_version', predictionResult.schemaVersion);
gr.setValue('execution_time', execTime);
gr.setValue('status_code', predictionResult.status.code);
gr.setValue('status_message', predictionResult.status.message);
// if no result found, just return.
if(predictionResult.result.length == 0)
gr.insert();
// note that only the first element is supported.
var firstResult = predictionResult.result[0];
gr.setValue('task_table', firstResult.input.tableName);
gr.setValue('task_id', firstResult.input.id);
gr.setValue('input_fields', JSON.stringify(firstResult.input.fields));
return gr.insert();
}
Sys ID
dcf79750536901105400ddeeff7b1289