Name

global.cxs_MLSearchHelper

Description

No description available

Script

var cxs_MLSearchHelper = Class.create();
cxs_MLSearchHelper.prototype = Object.extendsObject(cxs_BaseMLHelper, {
  DEFAULT_THRESHOLD: 1,
  TABLE_ML_SOLUTION_DEFINITION: 'ml_capability_definition_base',
  
  processSearch: function () {
  	//gs.log('******* inputs' + arguments[0]);
  	var inputs = JSON.parse(arguments[0]);
  	
  	//Initialize
  	if (!inputs['tableName'] || !inputs['solutionDefinition'])
  		return;
  	
  	this.threshold = this.DEFAULT_THRESHOLD;
  	this.solutionName = this.getSolutionName(inputs['solutionDefinition'].toString());
  	this.tableName = inputs['tableName'].toString();
  	this.count = Number(inputs['count'] ? inputs['count'].toString() : this.DEFAULT_COUNT) + 1;
  	
  	//gs.log('******* this.threshold' + this.threshold + this.tableName + this.count + this.request.formId + this.request.formTable + this.request.uiType);
  	
  	//Cannot do ML search if there are no form details
  	if (!this.request.formId || !this.request.formTable || !this.solutionName)
  		return;
  	
  	var formGr = this.getFormGr();
  	
  	//Invalid form details
  	if (!formGr)
  		formGr = new GlideRecord(this.request.formTable);
  	
  	formGr = this.updateSearchText(formGr);
  	// Empty search text for now should not go to ML API
  	if (!formGr)
  		return;

  	//Call ML serivce
  	var MLResults = this.callMLService(formGr);
  	
  	while (this.response.results.length < this.count) {
  		//Return if no results
  		if (!MLResults || MLResults.length <= 0)
  			return;
  		
  		//Process results from ML predictions
  		this.processResults(MLResults);
  	}
  	//gs.log('********* response *********' + JSON.stringify(this.response));
  },
  
  updateSearchText: function (formGr) {
  	var searchText = this.getSearchText();
  	if (!searchText)
  		return null;

  	var fieldGr = this.getTableConfigDefaultField();
  	var currentSearchField = this.getCurrentSearchField();
  	//gs.log('******* fieldGr.field' + fieldGr.field);
  	//gs.log('******* currentSearchField' + currentSearchField + formGr.isValidField(currentSearchField));
  	if (currentSearchField && formGr.isValidField(currentSearchField))
  		formGr.setValue(currentSearchField, searchText);
  	else if (fieldGr && fieldGr.field && formGr.isValidField(fieldGr.field))
  		formGr.setValue(fieldGr.field, searchText);

  	return formGr;
  },
  
  getSearchText: function () {
  	return this.request.query && this.request.query.freetext ? this.request.query.freetext : '';
  },
  
  getTableConfigDefaultField: function () {
  	var tableConfig = this.getTableConfig();
  	if (tableConfig) {
  		return this.getDefaultField(tableConfig.sys_id);
  	}
  	return '';
  },
  
  getCurrentSearchField: function () {
  	return this.request.meta && this.request.meta['sourceField'];
  },
  
  getSolutionName: function(defn) {
  	var gr = new GlideRecord(this.TABLE_ML_SOLUTION_DEFINITION);
  	if (gr.get(defn)) {
  		return gr.getValue('solution_name');
  	}
  	return null;
  },
  
  getFormGr: function () {
  	var gr = new GlideRecord(this.request.formTable);
  	if (gr.get(this.request.formId)) {
  		return gr;
  	}
  	return null;
  },
  
  callMLService: function (formGr) {
  	var predictor = new MLPredictor();
  	var info = "";
  	var solution = predictor.findActiveSolution(this.solutionName);
  	if (!solution)
  		return;
  	var outcomeArray = predictor.getPredictions(formGr, solution); //Threshold is default which is 1
  	return outcomeArray;
  },
  
  processResults: function (results) {
  	var currentSetResults = results.splice(0, this.count+1);
  	var formatedResults = this.formatResults(currentSetResults);
  	//var formatedResults = this.formatResultsDummyData(); //Until ML API is available
  	var sysIdsInOrder = formatedResults.sysIdsInOrder;
  	if (sysIdsInOrder && sysIdsInOrder.length > 0) {
  		// Get records that are readable by the user
  		var resultsGr = this.getResultsGr(sysIdsInOrder);
  		if (resultsGr.hasNext()) {
  			// Assimilate response
  			this.assimilateResults(formatedResults.resultsJson, resultsGr, sysIdsInOrder);
  		} 
  	}
  },
  
  formatResults: function (results) {
  	var resultsJson = {};
  	var sysIdsInOrder = [];
  	if (results) {
  		for (var i=0; i< results.length; i++) {
  			if (results[i].hasPrediction()) {
  				var predictionObj = {};
  				var sysId = results[i].predictedValue().length === 32 ? results[i].predictedValue(): results[i].predictedValueSysId();
  				predictionObj['predictedValue'] = results[i].predictedValue(); //int/case number
  				predictionObj['predictedValueSysId'] = sysId; //sys_id for similarity
  				predictionObj['confidence'] = results[i].confidence(); //similarity score
  				resultsJson[sysId] = predictionObj;
  				sysIdsInOrder.push(sysId);
  			}
  		}
  	}
  	return {'sysIdsInOrder': sysIdsInOrder, 'resultsJson': resultsJson};
  },
  		
  getResultsGr: function (sysIds) {
  	var gr = new GlideRecordSecure(this.tableName);
  	gr.addQuery('sys_id', 'IN', sysIds);
  	gr.query();
  	return gr;
  },

  assimilateResults: function (formatedResults, resultsGr, sysIdsInOrder) {
  	if (!formatedResults)
  		return;

  	var combinedResults = {};
  	while (resultsGr.next()) {
  		var sysId = resultsGr.getUniqueValue();
  		if (sysId === this.request.formId)
  			continue;

  		var srdc = new SNC.SearchResultDisplayConfiguration(resultsGr.getTableName(), this.request.getUiType(), this.request.getFormTable());
  		var res = new SNC.SearchResult();
  		res[this.RESULT_TITLE] = srdc.getCardTitle(resultsGr);
  		res[this.RESULT_SNIPPET] = SNC.SearchService.snippet(this.getSearchText(), srdc.getCardSnippet(resultsGr));
  		res[this.ID] = resultsGr.getTableName() + ':' + resultsGr.getUniqueValue();
  		if(resultsGr.getTableName() === 'kb_knowledge')
  			res[this.RESULT_LINK] = "kb_view.do?sysparm_article="+resultsGr.getValue('number');
  		else 
  			res[this.RESULT_LINK] = resultsGr.getLink();
  		res.meta[this.META_SCORE] = -1;
  		res.meta[this.CONFIDENCE] = formatedResults[this.CONFIDENCE];
  		res.meta.setDisplayConfiguration(srdc, resultsGr);
  		combinedResults[sysId] = res;
  	}

  	for (var i = 0; i < sysIdsInOrder.length; i ++) {
  		if (sysIdsInOrder[i] === this.request.formId)
  			continue;

  		var searchResult = combinedResults[sysIdsInOrder[i]];
  		this.response.results.push(searchResult);
  		if (this.response.results.length >= this.count)
  			break;
  	}
  },

  type: 'cxs_MLSearchHelper'
});

Sys ID

06b080c073002300d144234ffff6a74b

Offical Documentation

Official Docs: