Name
global.AutoResolutionLanguageX
Description
LanguageX API integration for Auto-Resolution flow
Script
var AutoResolutionLanguageX = Class.create();
AutoResolutionLanguageX.ERROR_CODE = 500;
AutoResolutionLanguageX.prototype = Object.extendsObject(AutoResolutionMLBase, {
contextSysId : '',
capability : '',
initialize: function(configSysId, contextSysId) {
this.setConfigSysId(configSysId);
this.contextSysId = contextSysId;
this.setCapability();
this.LOGGER = new AutoResolutionLoggingUtils()
.withName(this.type)
.withConfiguration(this.getConfigSysId())
.createLogger();
},
/**
* Adds a solution definition for languageX and updates the ml_capability_definition_base table.
* @param {string} inputSolutionName The name of the input solution that the LanguageX solution will wrap around.
@ @return {string} The LanguageX Solution name, or an empty string.
*/
addSolutionDefinition: function(inputSolutionName) {
var languageXSolutionTemplate = this.getLanguageXSolutionTemplate(inputSolutionName,
AutoResolutionConstants.ML_CAPBILITIES.AGENT_ZERO_WORKFLOW);
if (gs.nil(languageXSolutionTemplate)) {
return '';
}
var languageXSolutionName;
try {
languageXSolutionName = sn_ml.LanguageXSolutionStore.add(languageXSolutionTemplate);
} catch (error) {
this.LOGGER.error("Failed to add a LanguageX solution definition. Error: {0}", error);
languageXSolutionName = '';
}
return languageXSolutionName;
},
/**
* Creates a new LanguageX solution or updates an existing one.
* @param {string} inputLanguageConfigGr GlideRecord of the input language configuration used to trigger the creation or update of its
* corresponding LanguageX solution language configuration.
*/
createOrUpdateLanguageXSolution: function(inputLanguageConfigGr) {
var inputSolutionName = inputLanguageConfigGr.getValue("ml_solution_name");
var languageCode = inputLanguageConfigGr.getValue("training_language");
var isConfigActive = AutoResolutionUtil.isConfigurationActive(this.getConfigSysId());
var languageConfigGr;
// Check if there exists a LanguageX solution name
var languageXSolutionName;
try {
languageXSolutionName = AutoResolutionLanguageHelper.getSolutionNameForLanguage(languageCode,
this.getConfigSysId(), this.getCapability());
} catch (error) {
// Creating a new language config record because there does not exist a language config record with the LanguageX
languageXSolutionName = '';
}
var isUpdateSuccessful = true;
if (gs.nil(languageXSolutionName)) {
// If the solution name does not exist, create a new solution
languageXSolutionName = this.addSolutionDefinition(inputSolutionName);
var capability = AutoResolutionConstants.ML_CAPBILITIES.LANGUAGEX;
languageConfigGr = AutoResolutionLanguageHelper.createLanguageConfigRecord(this.getConfigSysId(), languageCode,
capability, languageXSolutionName);
} else {
// If the solution name does exist, update an existing solution
isUpdateSuccessful = this.updateSolutionDefinition(languageXSolutionName);
languageConfigGr = AutoResolutionLanguageHelper.getLanguageConfigRecordBySolutionName(this.getConfigSysId(), this.getCapability(), languageXSolutionName);
}
if (gs.nil(languageXSolutionName)) {
this.LOGGER.error("Failed to create the LanguageX solution because the LanguageX solution name does not exist.");
return;
}
if (!isUpdateSuccessful) {
this.LOGGER.error("Failed to update LanguageX solution.");
return;
}
if (gs.nil(languageConfigGr)) {
this.LOGGER.error("Failed to create or update the LanguageX solution because the language configuration record does not exist.");
return;
}
// Set the input solution to be inactive
inputLanguageConfigGr.active = false;
inputLanguageConfigGr.update();
// Update the training results on the language config record
var trainingResults = this._getDefaultTrainingResults(languageXSolutionName);
AutoResolutionLanguageHelper.updateLanguageConfigRecord(languageConfigGr, trainingResults);
// Restore the active value of IAR configuration record to which may have been altered due to training
if (isConfigActive)
AutoResolutionUtil.updateConfigRecord(this.getConfigSysId(), {"active": isConfigActive});
// Set BR for language configuration active check to active if not so already
AutoResolutionUtil.setBRActive(AutoResolutionConstants.LANGUAGE_CONFIG_ACTIVE_CHECK_BR);
},
/**
* Calls the LangX predict API using the current solution name by default
* @param taskGr - the GlideRecord of the task
* @param predictionInputFields - fields from taskGr with its value that needs to be sent to LangX for prediction
* @returns {{message: string, status: string, payload: object}}
*/
predict: function(taskGr, predictionInputFields, options) {
var solutionName = this.getSolutionName();
return this.predictBase(sn_ml.LanguageXSolutionStore, solutionName, taskGr, predictionInputFields, options);
},
/**
* Returns solution name for the configSysId
*/
getSolutionName: function() {
return AutoResolutionLanguageHelper.getSolutionNameForLanguage("en", this.getConfigSysId(), this.getCapability());
},
hasActiveVersion: function(solutionName) {
try {
if (!this.checkSolutionExists(solutionName))
return false;
var mlSolution = sn_ml.LanguageXSolutionStore.get(solutionName);
var solutionVersion = mlSolution.getActiveVersion();
return !gs.nil(solutionVersion);
} catch(ex) {
this.LOGGER.warn('Error checking for ML solution active version: {0}', ex.getMessage());
return false;
}
},
checkSolutionExists: function(solutionName) {
try {
if (!gs.nil(solutionName)) {
var autoResolutionPISolution = sn_ml.LanguageXSolutionStore.get(solutionName);
return !gs.nil(autoResolutionPISolution);
}
return false;
} catch(ex) {
this.LOGGER.warn('Error checking ML solution exists: name={0}: {1}', solutionName, ex);
return false;
}
},
// For languageX capability we don't need to show train UI Action
showTrainButton: function() {
return false;
},
// For languageX capability we don't need to show refresh or cancel training UI actions
showRefreshOrCancelTrainingButton: function() {
return false;
},
setCapability: function() {
this.capability = AutoResolutionConstants.ML_CAPBILITIES.LANGUAGEX;
},
getCapability: function() {
return this.capability;
},
/**
* Gets the LanguageX solution template, by an existing configJSON from the ML solution if it exists, or
* by creating a new configJSON if not.
* @param {string} inputSolutionName The solution name of a Workflow or LanguageX solution.
* @return {Object} The LanguageX Solution template.
*/
getLanguageXSolutionTemplate: function(inputSolutionName, capability) {
// Get list of all config sys_ids that use the same LanguageX solution name
var configIdList = AutoResolutionUtil.getConfigIdsWithSameSolutionName(inputSolutionName);
var completeNluModelNameList = [];
// Use the list of config sys_ids to create a set of NLU model names
var arrayUtil = new ArrayUtil();
configIdList.forEach(function(configId) {
var partialNluModelNameList = AutoResolutionUtil.getNLUModelNameListFromConfig(configId);
completeNluModelNameList = arrayUtil.concat(completeNluModelNameList, partialNluModelNameList);
});
completeNluModelNameList = arrayUtil.unique(completeNluModelNameList);
// Get existing LanguageX config, if the inputSolutionName refers to a LanguageX solution
// Otherwise, treat the inputSolutionName as a Workflow solution name and create a new config object using this
var configJSON = (capability === AutoResolutionConstants.ML_CAPBILITIES.LANGUAGEX)
? this._getConfigJSONFromMLCapabilitySolutionBaseRecord(inputSolutionName)
: this._getDefaultConfigJSON(inputSolutionName);
// Add all the NLU model names to the list of custom intents in the configJSON object
configJSON.options.customIntents = [];
completeNluModelNameList.forEach(function(name) {
var obj = {
"solutionName": name,
};
configJSON.options.customIntents.push(obj);
});
var solutionTemplate;
try {
solutionTemplate = new sn_ml.LanguageXSolution(configJSON);
} catch (error) {
this.LOGGER.error("Failed to create a new LanguageXSolution template. Error: {0}", error);
solutionTemplate = null;
}
return solutionTemplate;
},
/**
* Updates the LanguageX solution definition in the ml_capability_definition_base table. Should increase the version number by 1.
* @param {string} languageXSolutionName The name of the LanguageX solution.
* @return Whether the solution definition has been successfully updated.
*/
updateSolutionDefinition: function(languageXSolutionName) {
try {
var languageXSolutionTemplate = this.getLanguageXSolutionTemplate(languageXSolutionName,
AutoResolutionConstants.ML_CAPBILITIES.LANGUAGEX);
sn_ml.LanguageXSolutionStore.update(languageXSolutionName, languageXSolutionTemplate);
return true;
} catch (error) {
this.LOGGER.error("Failed to update the LanguageX solution definition. Error: {0}", error);
}
return false;
},
/**
* Updates all solution definitions for all languages that use the LanguageX capability.
*/
updateSolutionDefinitionsForAllLanguages: function() {
var languageXSolutionNameList = AutoResolutionLanguageHelper.getAllSolutionNamesByCapability(this.getConfigSysId(),
this.getCapability());
// For each solution name, update the solution definition
for (var i = 0; i < languageXSolutionNameList.length; i += 1) {
var languageXSolutionName = languageXSolutionNameList[i];
var isUpdateSuccessful = this.updateSolutionDefinition(languageXSolutionName);
if (!isUpdateSuccessful) {
continue;
}
// Update the training results on the language config record
var trainingResults = this._getDefaultTrainingResults(languageXSolutionName);
var languageConfigGr = AutoResolutionLanguageHelper.getLanguageConfigRecordBySolutionName(
this.getConfigSysId(), this.getCapability(), languageXSolutionName);
AutoResolutionLanguageHelper.updateLanguageConfigRecord(languageConfigGr, trainingResults);
}
},
/**
* Perform bulk LanguageX prediction
* @param {string} autoResConfigSysID - the sys_id of IAR Configuration GlideRecord
* @param {Object} requestObjectList - JSON with input parameters for LanguageX prediction
* @return {Object} The LanguageX bulk prediction results
*/
getBulkPrediction: function(requestObjectList) {
var predictionResults;
try {
var languageXSolutionName = this.getSolutionName();
var languageXSolution = sn_ml.LanguageXSolutionStore.get(languageXSolutionName);
predictionResults = JSON.parse(languageXSolution.getActiveVersion().predict(requestObjectList));
}
catch (error) {
this.LOGGER.error("Failed to perform bulk prediction for the configuration {0} with the LanguageX solution name {1}",
this.getConfigSysId(), languageXSolutionName);
predictionResults = null;
}
return predictionResults;
},
/**
* Gets the configuration JSON object from the existing LanguageX solution definition given the solution name.
* @param {string} languageXSolutionName The name of the LanguageX solution.
* @return {Object} JSON object for configuring the LanguageX solution definition.
* @private
*/
_getConfigJSONFromMLCapabilitySolutionBaseRecord: function(languageXSolutionName) {
var mlDefinitionGr = new GlideRecord("ml_capability_definition_base");
mlDefinitionGr.addQuery("solution_name", languageXSolutionName);
mlDefinitionGr.query();
if (!mlDefinitionGr.next()) {
this.LOGGER.error("Failed to update the LanguageX solution definitions for the configuration {0} because there does not exist a Solution Definition record for the LanguageX solution name {1}",
this.getConfigSysId(), languageXSolutionName);
return "";
}
// Solution properties will contain the configuration object used to create the LanguageX solution with
var solutionProperties = mlDefinitionGr.getValue("solution_properties");
if (gs.nil(solutionProperties)) {
this.LOGGER.error("Failed to update the LanguageX solution definitions for the configuration {0} because the solution properties is empty in the Solution Definition record for the LanguageX solution name {1}",
this.getConfigSysId(), languageXSolutionName);
return "";
}
var configJSON;
try {
configJSON = JSON.parse(solutionProperties);
} catch (error) {
this.LOGGER.error("Failed to update the LanguageX solution definitions for the configuration {0} because the solution properties is invalid in the Solution Definition record for the LanguageX solution name {1}",
this.getConfigSysId(), languageXSolutionName);
configJSON = "";
}
return configJSON;
},
/**
* Creates the configuration JSON object for creating or updating the LanguageX solution definition with.
* @param {string} inputSolutionName The name of the input solution that the LanguageX solution will wrap around.
* @return {Object} JSON object for configuring the LanguageX solution definition.
* @private
*/
_getDefaultConfigJSON: function(inputSolutionName) {
var configJSON = {
"schemaVersion": "1.0",
"label": "Issue Auto Resolution",
"templates": [{
"templateName": "AGENT_ZERO_TEMPLATE",
"templateVersion": "1.0",
"templateConfig": {
"services": [{
"serviceName": "agent_zero_trainer",
"serviceConfig": {
"solutionName": inputSolutionName,
},
}]
},
"templateOptions": {},
}],
"options": {
"customIntents": [],
},
};
return configJSON;
},
/**
* Creates the object of training result values to set the language configuration record of a LanguageX solution to. Although it
* doesn't take any time or have a status output because the solution doesn't need to be trained, we still need to make these values
* non-empty to be consistent with the other solutions that do need to be trained.
* @param {string} languageXSolutionName Name of the LanguageX solution.
* @return {Object} JSON object containing a map of the column names on a language configuration record to their corresponding training
* status values that need to be updated on the record.
* @private
*/
_getDefaultTrainingResults: function(languageXSolutionName) {
var trainingResults = {};
trainingResults.active = true;
trainingResults.ml_training_state = "solution_complete";
trainingResults.ml_training_progress = 100;
trainingResults.ml_status_last_updated = new GlideDateTime();
trainingResults.latest_trained_version =
this.getActiveSolutionVersionNumberForSolutionName(sn_ml.LanguageXSolutionStore, languageXSolutionName);
return trainingResults;
},
type: 'AutoResolutionLanguageX'
});
Sys ID
a631bfcd77110110f14a24f1cd5a995b