Name
global.AutoResolutionSimulationRunBlock
Description
No description available
Script
var AutoResolutionSimulationRunBlock = Class.create();
AutoResolutionSimulationRunBlock.prototype = {
initialize: function(sysID) {
this.LANGUAGE_CODE = 'en';
this._continueOnBatchError = true;
this._state = AutoResolutionSimulationHelper.STATE_COMPLETE;
this._gr = new GlideRecord(AutoResolutionConstants.SIMULATION_RUN_BLOCK_TABLE_NAME);
this._gr.get(sysID);
var autoResolutionConfigGr = this._gr.simulation_run.config.auto_res_config.getRefRecord();
this._autoResConfigSysID = autoResolutionConfigGr.getValue('sys_id');
this._targetTable = autoResolutionConfigGr.getValue(AutoResolutionConstants.CONFIGURATION_TABLENAME_FIELD_NAME);
this._composite = new AutoResolutionComposite(autoResolutionConfigGr.getValue('sys_id'));
this._totalRecordsInBlock = this._getTotalRecordsInBlock();
this._languageCode = this._gr.getValue('language_code');
this._taskSysIDList = this._getTaskSysIDsInCurrentBlock();
this._predictionFields = autoResolutionConfigGr.prediction_fields.toString().split(',');
this.LOGGER = new AutoResolutionLoggingUtils()
.withName(this.type)
.withSimulation(this._gr.getValue('simulation_run'))
.withSimulationConfiguration(this._autoResConfigSysID)
.createLogger();
},
setBatchSize: function(batchSize) {
this._batchSize = batchSize;
},
continueOnBatchError: function(flag) {
this._continueOnBatchError = flag;
},
process: function() {
var errorMessage;
var startTime;
var endTime;
var i;
try {
this._validateParameters();
this._info('Processing started for block');
startTime = new Date().getTime();
var endIndex;
for (i = 0; i < this._taskSysIDList.length; i += this._batchSize) {
endIndex = i + this._batchSize;
if (endIndex > this._taskSysIDList.length)
endIndex = this._taskSysIDList.length;
this._processBatch(i, endIndex);
this._info('Finished processing ' + (i + 1) + ' records');
}
// If all the contexts belonging to this block are API errors, it means that whole block has error
this._evaluateAndSetStateIfAllAPIErrors();
this._gr.setValue('state', this._state);
this._gr.update();
endTime = new Date().getTime();
this._printSummary(startTime, endTime, this._totalRecordsInBlock);
this._info('Processing ended successfully for block');
} catch(error) {
this._updateErrorMessageOnBlockRecord(error);
this._gr.setValue('state', AutoResolutionSimulationHelper.STATE_ERROR);
this._gr.update();
endTime = new Date().getTime();
this._printSummary(startTime, endTime, (i + 1));
this._info('Processing ended for block due to error');
this.LOGGER.error('Error processing block: {0}', error);
throw 'Error processing simulation run block with sys id ' + this._gr.getValue('sys_id') + ': ' + error;
}
},
_processBatch: function(taskSysIDStartIndex, taskSysIDEndIndex) {
try {
//Prepare request object for LanguageX prediction
var requestObjectList = this._getRequestObjectForTaskSysIDs(taskSysIDStartIndex, taskSysIDEndIndex);
//LanguageX bulk prediction
var predictionResults = this._composite.getBulkPrediction(requestObjectList, this._languageCode);
if (gs.nil(predictionResults)) {
this._markNonSimulatedContextsInBatchWithAPIError(taskSysIDStartIndex, taskSysIDEndIndex);
return;
}
var intentAndTopicDetails;
var intentMatch;
var unsupportedMatchedIntent;
var simulationContextGr = new GlideRecord(AutoResolutionConstants.SIMULATION_CONTEXT_TABLE_NAME);
var intent;
var confidenceScore;
var serviceModel;
var taskCount = taskSysIDEndIndex - taskSysIDStartIndex;
for (var taskSysIDIndex = 0; taskSysIDIndex < taskCount; taskSysIDIndex++) {
simulationContextGr.initialize();
simulationContextGr.addQuery('task', predictionResults['result'][taskSysIDIndex]['input']['id']);
simulationContextGr.addQuery('simulation_run_block', this._gr.getValue('sys_id'));
simulationContextGr.query();
if (!simulationContextGr.next()) {
this.LOGGER.info('Simulation context record not found for task: {0}, for simulation run block: {1}', simulationContextGr.getValue('task'), this._gr.getValue('sys_id'));
continue;
}
//LanguageX API prediction error
if (predictionResults['status']['message'] === AutoResolutionConstants.STATUS_ERROR){
this.LOGGER.error('API prediction error for task: {0}, for simulation run block: {1}', simulationContextGr.getValue('task'), this._gr.getValue('sys_id'));
this._markSingleNonSimulatedContextRecordWithAPIError(simulationContextGr);
continue;
}
//Save payload values from LanguageX response
//TODO: Assume output[0] is always AgentZero service, will refactor once more services are supported
intent = predictionResults['result'][taskSysIDIndex]['output'][0]['serviceOutput'];
confidenceScore = predictionResults['result'][taskSysIDIndex]['output'][0]['serviceOutputScore'];
serviceModel = predictionResults['result'][taskSysIDIndex]['output'][0]['serviceModelUsed'];
serviceModelSolutionName = predictionResults['result'][taskSysIDIndex]['output'][0]['serviceModelSolutionName'];
serviceModelSolutionVersion = predictionResults['result'][taskSysIDIndex]['output'][0]['serviceModelSolutionVersion'];
intentAndTopicDetails = new AutoResolutionPredictionHelper(this._autoResConfigSysID).processIntent(intent);
intentMatch = (intentAndTopicDetails.intentTopicState !== AutoResolutionConstants.INTENT_TOPIC_STATE.NO_INTENT);
simulationContextGr.setValue('configuration', this._autoResConfigSysID);
simulationContextGr.setValue('nlu_intent', intentAndTopicDetails.nluIntent || '');
simulationContextGr.setValue('matched_topic', intentAndTopicDetails.matchedTopic || '');
simulationContextGr.setValue('intent_topic_state', intentAndTopicDetails.intentTopicState || '');
simulationContextGr.setValue('reason', intentAndTopicDetails.intentTopicStateReason || '');
simulationContextGr.setValue('intent_match', intentMatch);
simulationContextGr.setValue('active', false); // Since this is for simulation, we set this as false
simulationContextGr.setValue('prediction_confidence', confidenceScore || 0);
simulationContextGr.setValue('service_model_used', serviceModel || '');
simulationContextGr.setValue('service_model_solution_name', serviceModelSolutionName || '');
simulationContextGr.setValue('service_model_solution_version', serviceModelSolutionVersion || '');
if (!intentMatch) {
unsupportedMatchedIntent = intentAndTopicDetails.nluIntent.split(AutoResolutionConstants.UNSUPPORTED_MATCHED_INTENT_SEPARATOR)[1];
simulationContextGr.setValue('unsupported_matched_intent', unsupportedMatchedIntent || '');
}
simulationContextGr.update();
}
} catch(error) {
this._markNonSimulatedContextsInBatchWithAPIError(taskSysIDStartIndex, taskSysIDEndIndex);
// If continue on batch error is true, we would like to continue
if (this._continueOnBatchError) {
this._state = AutoResolutionSimulationHelper.STATE_PARTIALLY_COMPLETE;
this._updateErrorMessageOnBlockRecord(error);
} else {
throw error;
}
}
},
_validateParameters: function() {
if (gs.nil(this._batchSize))
throw this.type + '.process: Please set the batch size before calling processNextBatch method';
if (gs.nil(this._languageCode))
throw this.type + '.process: Could not find language code for block: ' + this._gr.getValue('name');
},
_getRequestObjectForTaskSysIDs: function(taskSysIDStartIndex, taskSysIDEndIndex) {
var requestObjectList = [];
for (var i = taskSysIDStartIndex; i < taskSysIDEndIndex; i++)
requestObjectList.push(this._getRequestObjectForTaskSysID(this._taskSysIDList[i]));
return requestObjectList;
},
_getRequestObjectForTaskSysID: function(taskSysID) {
var requestObject = {
'id': taskSysID,
'tableName': this._targetTable,
'userID': gs.getUserId(),
};
var targetGr = new GlideRecord(this._targetTable);
targetGr.get(taskSysID);
if (gs.nil(targetGr)) {
this._info('Cannot find task with sys id: ' + taskSysID);
return requestObject;
}
var columnName;
for (var columnNameIndex in this._predictionFields) {
columnName = this._predictionFields[columnNameIndex];
requestObject[columnName] = targetGr.getValue(columnName);
}
return requestObject;
},
_getTotalRecordsInBlock: function() {
var simulationContextGa = new GlideAggregate(AutoResolutionConstants.SIMULATION_CONTEXT_TABLE_NAME);
simulationContextGa.addQuery('simulation_run_block', this._gr.getValue('sys_id'));
simulationContextGa.addAggregate('COUNT');
simulationContextGa.query();
return simulationContextGa.next() ? parseInt(simulationContextGa.getAggregate('COUNT')) : 0;
},
_markNonSimulatedContextsInBatchWithAPIError: function(taskSysIDStartIndex, taskSysIDEndIndex) {
// Construct an array to be more efficient for update multiple case
var taskSysIDList = [];
for (var i = taskSysIDStartIndex; i < taskSysIDEndIndex; i++)
taskSysIDList.push(this._taskSysIDList[i]);
var simulationContextGr = new GlideRecord(AutoResolutionConstants.SIMULATION_CONTEXT_TABLE_NAME);
simulationContextGr.addQuery('task', 'IN', taskSysIDList.join(','));
simulationContextGr.addQuery('intent_topic_state', '');
simulationContextGr.addQuery('simulation_run_block', this._gr.getValue('sys_id'));
// Set all the values and updateMultiple
simulationContextGr.setValue('intent_topic_state', AutoResolutionConstants.INTENT_TOPIC_STATE.NO_INTENT);
simulationContextGr.setValue('intent_match', false);
simulationContextGr.setValue('reason', AutoResolutionConstants.NO_INTENT_REASON.API_ERROR);
simulationContextGr.updateMultiple();
},
_markSingleNonSimulatedContextRecordWithAPIError: function(simulationContextGr) {
simulationContextGr.setValue('intent_topic_state', AutoResolutionConstants.INTENT_TOPIC_STATE.NO_INTENT);
simulationContextGr.setValue('intent_match', false);
simulationContextGr.setValue('reason', AutoResolutionConstants.NO_INTENT_REASON.API_ERROR);
simulationContextGr.update();
},
_getTaskSysIDsInCurrentBlock: function() {
var taskSysIDs = [];
var simulationContextGr = new GlideRecord(AutoResolutionConstants.SIMULATION_CONTEXT_TABLE_NAME);
simulationContextGr.addQuery('simulation_run_block', this._gr.getValue('sys_id'));
simulationContextGr.addNullQuery('intent_topic_state');
simulationContextGr.query();
while (simulationContextGr.next())
taskSysIDs.push(simulationContextGr.getValue('task'));
return taskSysIDs;
},
_updateErrorMessageOnBlockRecord: function(errorMessage) {
var existingErrorMessage = this._gr.getValue('message');
var errorMessageToAppend = errorMessage;
if (gs.nil(existingErrorMessage))
existingErrorMessage = errorMessageToAppend;
else
errorMessageToAppend = existingErrorMessage + '\n' + errorMessageToAppend;
this._gr.setValue('message', errorMessageToAppend);
this._gr.update();
},
_evaluateAndSetStateIfAllAPIErrors: function() {
var totalAPIErrors = 0;
var simContextGa = new GlideAggregate(AutoResolutionConstants.SIMULATION_CONTEXT_TABLE_NAME);
simContextGa.addQuery('reason', AutoResolutionConstants.NO_INTENT_REASON.API_ERROR);
simContextGa.addQuery('simulation_run_block', this._gr.getValue('sys_id'));
simContextGa.addAggregate('COUNT');
simContextGa.query();
if (simContextGa.next())
totalAPIErrors = simContextGa.getAggregate('COUNT');
if (totalAPIErrors == this._taskSysIDList.length)
this._state = AutoResolutionSimulationHelper.STATE_ERROR;
},
_info: function(message) {
this.LOGGER.info('Message for run block={0}: {1}', this._gr.getValue('name'), message);
},
_printSummary: function(startTime, endTime, numOfRecordsProcessed) {
var totalTimeTaken = (endTime - startTime) / 1000;
var numberOfRequests = Math.ceil(numOfRecordsProcessed / this._batchSize);
var summaryString = 'Total records processed: ' + numOfRecordsProcessed + '\n';
summaryString += 'Total requests sent to prediction server: ' + numberOfRequests + '\n';
summaryString += 'Total time taken: ' + totalTimeTaken + ' seconds';
this._info(summaryString);
},
type: 'AutoResolutionSimulationRunBlock'
};
Sys ID
dffc69dbffa22010635f056d793bf197