Name
global.AutoResolutionAISearchHelper
Description
A Helper script for AutoResolution AI Search result handling
Script
var AutoResolutionAISearchHelper = Class.create();
/**
* Returns the result found by context Id
* @param contextId Auto-Resolution context Id
* @param geniusSearchMaxLimit the max limit for Genius search optional.
* @param searchMaxLimit the max limit for regular search. optional.
* @return the results found by the context Id. null if not found.
*/
AutoResolutionAISearchHelper.getSearchResultByContextId = function(contextId, geniusSearchMaxLimit, searchMaxLimit) {
var searchResult = AutoResolutionAISearchResult.getByContextId(contextId);
// if the search result is null, return null.
if(gs.nil(searchResult))
return null;
// enforce the max limits if provided from outside.
if (!gs.nil(geniusSearchMaxLimit))
searchResult.setGeniusSearchMaxLimit(geniusSearchMaxLimit);
if (!gs.nil(searchMaxLimit))
searchResult.setSearchMaxLimit(searchMaxLimit);
return searchResult;
};
/**
* Returns the available values for the positive feedbacks. The values come from choice list.
* @return [{value:'<value>', lable:'<lable>, sequence:<sequence>'}]
*/
AutoResolutionAISearchHelper.getAvailablePositiveFeedbackValues = function() {
return AutoResolutionAISearchResultLineItem.getAvailablePositiveFeedbackValues();
};
/**
* Returns the available values for the negative feedbacks. The values come from choice list.
* @return [{value:'<value>', lable:'<lable>, sequence:<sequence>'}]
*/
AutoResolutionAISearchHelper.getAvailableNegativeFeedbackValues = function() {
return AutoResolutionAISearchResultLineItem.getAvailableNegativeFeedbackValues();
};
/**
* Returns the available result status. The values come from choice list.
* @return [{value:'<value>', lable:'<lable>, sequence:<sequence>'}]
*/
AutoResolutionAISearchHelper.getAvailableResultStatus = function() {
return AutoResolutionAISearchResultLineItem.getAvailableResultStatus();
};
/**
* Updates the result status of the line item.
*/
AutoResolutionAISearchHelper.updateResultLineItemResultStatus = function(lineItemSysId, resultStatus) {
// if the sysId should not be null.
if (gs.nil(lineItemSysId))
return null;
var lineItem = new AutoResolutionAISearchResultLineItem(lineItemSysId);
lineItem.setResultStatus(resultStatus);
lineItem.update();
};
/**
* Updates the specific result line item with the feedback and sets the Feedback provider to be the current session user.
*
* @param lineItemSysId AISearchResultLineItem sysId
* @param feedbackType - either positive or negative
* @param feedbackValue - It should be one of the positive or negative feedback values
* @param processFeedbacks - If omitted or false, feedback won't be processed. Instead, processFeedbacks method needs to be called explicitly.
*. If true is passed, this feedback will be processed.
*/
AutoResolutionAISearchHelper.updateResultLineItemFeedback = function(lineItemSysId, feedbackType, feedbackValue, processFeedbacks) {
// if the sysId should not be null.
if (gs.nil(lineItemSysId))
return null;
var lineItem = new AutoResolutionAISearchResultLineItem(lineItemSysId);
lineItem.setFeedback(feedbackType, feedbackValue);
lineItem.setFeedbackProviderPersona(AutoResolutionAISearchResultLineItem.FEEDBACK_PROVIDER_PERSONA_REQUESTER);
lineItem.setFeedbackProvider(gs.getUserID());
lineItem.update();
// call the result.
if (processFeedbacks)
AutoResolutionAISearchHelper.processFeedbacks(lineItem.getAISearchResultId());
};
/**
* All unsubmitted feedback will be collected and submitted to GlideSignals API. This is for batching.
* @param AISearchResult sysId
*/
AutoResolutionAISearchHelper.processFeedbacks = function(resultSysId) {
var result = new AutoResolutionAISearchResult(resultSysId);
result.processFeedbacks();
};
/**
* Updates the multiple feedbacks at once. After this call, only one event will be fired.
* @param resultLineItemSysIds an array of sys_ids of AI Search result line items.
* @param feedbackType This can be either 'positive' or 'negative'
* @param feedbackValue It can be one of the predefined values for positive or negative values.
*/
AutoResolutionAISearchHelper.updateMultipleResultLineItemFeedbacks = function(resultLineItemSysIds, feedbackType, feedbackValue) {
for(var i=0; i<resultLineItemSysIds.length; i++) {
var lineItemSysId = resultLineItemSysIds[i];
AutoResolutionAISearchHelper.updateResultLineItemFeedback(lineItemSysId, feedbackType, feedbackValue, false);
}
if(!gs.nil(lineItemSysId)) {
var lineItem = new AutoResolutionAISearchResultLineItem(lineItemSysId);
AutoResolutionAISearchHelper.processFeedbacks(lineItem.getAISearchResultId());
}
};
/**
* Parsed the AI search results
*/
AutoResolutionAISearchHelper.parseAISearchResults = function(searchResults, maxGeniusResultLimit, maxSearchResultLimit) {
var results = JSON.parse(searchResults);
var result = results.result[0];
var executionResult = result.executionResult;
var geniusSearchResults = null;
var nonGeniusResults = null;
var searchMetadata = {};
searchMetadata = executionResult.searchMetadata;
var items = executionResult.geniusResultsTemplates.items.slice(0, maxGeniusResultLimit);
if (items.length > 0)
geniusSearchResults = items;
items = executionResult.searchResultsTemplates.items.slice(0, maxSearchResultLimit);
if (items.length > 0)
nonGeniusResults = items;
var searchMetadataStr = !gs.nil(searchMetadata) ? JSON.stringify(searchMetadata) : null ;
var geniusResultsStr = !gs.nil(geniusSearchResults) ? JSON.stringify(geniusSearchResults) : null ;
var nonGeniusResultsStr = !gs.nil(nonGeniusResults) ? JSON.stringify(nonGeniusResults) : null;
return {
searchMetadata: searchMetadataStr,
geniusSearchResults: geniusResultsStr,
searchResults: nonGeniusResultsStr
};
};
/**
* Get regular AIS result link, with iar portal configuration
* @param contextId
* @param resultPayload
* @return {string}
*/
AutoResolutionAISearchHelper.getAISearchResultLink = function(contextId, resultPayload) {
// propValues
var sysId = AISearchHelper.getParentIdFromPropValues(resultPayload.propValues);
var tableName = AISearchHelper.getParentTableFromPropValues(resultPayload.propValues);
var actionName = ""; // unused in this flow
// get portal from iar config
var contextGr = new GlideRecord(AutoResolutionConstants.CONTEXT_TABLE_NAME);
contextGr.get(contextId);
var configGr = contextGr.configuration.getRefRecord();
var portalGr = configGr.portal.getRefRecord();
var portal = portalGr.getDisplayValue("url_suffix");
return sn_cs.VASystemObject.applyLinkTemplateCustomPortal(sysId, tableName, actionName, portal);
};
/**
* Add IAR-specific parameters on top of regular AIS result link
* @param aisURL
* @param lineItemSysId
* @return {string}
*/
AutoResolutionAISearchHelper.getIARSearchResultLink = function(aisURL, lineItemSysId) {
// change to specific iar params (as long as the default values are already there)
aisURL = AutoResolutionAISearchHelper._addIARToIdParam(aisURL);
return aisURL + "&" + global.AutoResolutionConstants.RECOMMENDATION_ID_PARAM + "=" + lineItemSysId;
};
/**
* if tableName is supported, return the url with id replaced
* @param aisURL
* @return string
* @private
*/
AutoResolutionAISearchHelper._addIARToIdParam = function(aisURL) {
if (aisURL.indexOf(AutoResolutionConstants.CATALOG_TABLE_NAME) !== -1) {
return AutoResolutionAISearchHelper._replaceIdParam(aisURL,
AutoResolutionConstants.CATALOG_TABLE_NAME, AutoResolutionConstants.IAR_CATALOG_TABLE_NAME);
}
else if (aisURL.indexOf(AutoResolutionConstants.KB_ARTICLE_TABLE_NAME) !== -1) {
return AutoResolutionAISearchHelper._replaceIdParam(aisURL,
AutoResolutionConstants.KB_ARTICLE_TABLE_NAME, AutoResolutionConstants.IAR_KB_ARTICLE_TABLE_NAME);
}
else return aisURL;
};
/**
* replace id param in url with idReplaceValue
* @param url
* @param idSource
* @param idReplaceValue
* @return {string}
* @private
*/
AutoResolutionAISearchHelper._replaceIdParam = function(url, idSource, idReplaceValue) {
var paramToReplaceRegEx = new RegExp("([?&]id=)" + idSource + "(&|$)");
return url.replace(paramToReplaceRegEx, "$1" + idReplaceValue + "$2");
};
/**
* Takes in results that have been processed by VAAISearchHelperTokyo.processResults
* and adds iar-specific field onto those results
*
* @param arResult : AutoResolutionAISearchResult
* @param processedResults
*/
AutoResolutionAISearchHelper.formatResultsForIAR = function(arResult, processedResults) {
var formattedResults = {};
// genius result
var geniusResult = "";
var geniusResultLineItems = arResult.getGeniusSearchResults(); // returns array of genius results, empty array if no results
if (!gs.nil(processedResults.geniusSearchResults) && geniusResultLineItems.length !== 0) {
geniusResult = JSON.parse(processedResults.geniusSearchResults);
var index = 0; // currently only supporting 1 genius result
geniusResult.auto_resolution_url = AutoResolutionAISearchResultLineItem.getRecommendationURL(geniusResultLineItems[index]);
geniusResult.auto_resolution_line_item_sys_id = geniusResultLineItems[index].getSysId();
formattedResults.geniusSearchResult = JSON.stringify(geniusResult);
}
// regular search results
var searchResults = [];
var searchResultLineItems = arResult.getSearchResults();
var maxResults = VAAISearchHelperTokyo.getRegularSearchDisplaySize(searchResultLineItems);
var processedSearchResults = JSON.parse(processedResults.searchResults);
// TODO: do we need to check if results are out of order here?
for (var i = 0; i < maxResults; i++) {
var processedSearchResult = processedSearchResults[i];
processedSearchResult.auto_resolution_url = AutoResolutionAISearchResultLineItem.getRecommendationURL(searchResultLineItems[i]);
processedSearchResult.auto_resolution_line_item_sys_id = searchResultLineItems[i].getSysId();
searchResults.push(processedSearchResult);
}
formattedResults.searchResults = JSON.stringify(searchResults);
// metadata don't change
formattedResults.searchMetadata = processedResults.searchMetadata;
return formattedResults;
};
/**
* Returns the predicted values found by contextId
* @param contextId: AR context Id
*/
AutoResolutionAISearchHelper.getPredictedResultsByContextId = function(contextId) {
var rtn = {predicted_language:'', predicted_criticality:'', predicted_search_query:''};
var gr = new GlideRecord('sys_cs_auto_resolution_prediction');
if (gr.addQuery('ar_context', contextId)) {
rtn.predicted_language = ensureValue(gr.getValue('predicted_language'));
rtn.predicted_search_query = ensureValue(gr.getValue('predicted_search_query'));
rtn.predicted_criticality = ensureValue(gr.getValue('predicted_criticality'));
}
return rtn;
};
/**
* Returns the language that needs to be used for AISearch
*/
AutoResolutionAISearchHelper.getLanguageForAISearch = function(contextGr) {
// look for the predicted language first.
var prediction = contextGr.prediction;
// if available, use the predicted language.
if (!gs.nil(prediction) || !gs.nil(prediction.predicted_language))
return prediction.predicted_language.getValue();
// if the language is not found, use the user's prefered language.
var user = contextGr.notification_user;
if (!gs.nil(user) && !gs.nil(user.preferred_language))
return user.preferred_language.getValue();
// still not found, use the sytem default.
return gs.getSession().getLanguage();
};
/**
* Returns the locale that needs to be used for AISearch
*/
AutoResolutionAISearchHelper.getLocaleForAISearch = function(contextGr) {
return ''; // currently, the following logic is breaking AIsearch for catalog. This is a temp fix.
var lang = global.AutoResolutionAISearchHelper.getLanguageForAISearch(contextGr);
var country;
//1. check user's country
var user = contextGr.notification_user;
if (!gs.nil(user) && !gs.nil(user.country)) {
country = user.country.getValue();
}
else {
// if user's country is not found, get the system's locale.
var locale = gs.getProperty(global.AutoResolutionAISearchConstants.SYS_LOCALE_PROP_NAME);
if (!gs.nil(locale)) {
var index = locale.indexOf('.');
if (index != -1)
country = locale.substring(index+1);
}
}
// if still not found, use the default.
if (gs.nil(country))
country = global.AutoResolutionAISearchConstants.DEFAULT_LOCALE_COUNTRY;
// locale = language.COUNTRY
return lang + '.' + country;
};
/**
* Returns a collection of parameters for GlideSignals Event. These parameters will be used for Glide Signals Event.
*
* @param resultGr : GlideRecord of sys_cs_auto_resolution_ai_search_result
*/
AutoResolutionAISearchHelper.createParamBagForGlideSignalsEvent = function(resultGr, language) {
var paramBag = {};
// this execution of the search is done on behalf of the notification user.
// If not found, use the current user which is most likely the system user.
var user = resultGr.ar_context ? resultGr.ar_context.notification_user : null;
if (!gs.nil(user))
paramBag[global.AISearchConstants.USER_ID] = user.getValue();
else
paramBag[global.AISearchConstants.USER_ID] = gs.getUserID();
// session_id was randomly generated when resultGr was created
paramBag[global.AISearchConstants.SESSION_ID] = resultGr.getValue('session_id');
paramBag[global.AISearchConstants.SEARCH_PROFILE] = resultGr.getValue('search_profile');
paramBag[global.AISearchConstants.SEARCH_CONTEXT_CONFIG_ID] = resultGr.getValue('search_app_config');
paramBag[global.AISearchConstants.QUERY_TERM] = resultGr.getValue('search_term');
paramBag[global.AISearchConstants.LANGUAGE] = language;
return paramBag;
};
/**
* Tests if AISearch feedback handling is enabled or not.
*/
AutoResolutionAISearchHelper.isAISearchFeedbackEnabled = function() {
var propVal = gs.getProperty(global.AutoResolutionAISearchConstants.AR_AI_SEARCH_FEEDBACK_ENABLED_PROP_NAME, 'true');
return propVal && propVal === 'true';
};
AutoResolutionAISearchHelper.updateAISResultFeedback= function(aisId, feedbackType) {
var ais = new AutoResolutionAISearchResult(aisId);
ais.setFeedbackType(feedbackType);
ais.update();
};
/**
* Get search result info from task sys id, mainly used in email scripts
* @param taskId
* @return [{id, title, className, description}]
*/
AutoResolutionAISearchHelper.getRecommendationInfoFromTaskId = function(taskSysId) {
var contextGr = new GlideRecord(AutoResolutionConstants.CONTEXT_TABLE_NAME);
contextGr.addQuery("task", taskSysId);
contextGr.query();
if (!contextGr.next())
return [];
var aiSearchResult = AutoResolutionAISearchHelper.getSearchResultByContextId(contextGr.getUniqueValue());
if (gs.nil(aiSearchResult))
return [];
var aiSearchResultLineItems = aiSearchResult.getSearchResults();
aiSearchResultLineItems.splice(5);
var recommendations = [];
for (var i = 0; i < aiSearchResultLineItems.length; i++) {
var recommendationSysId = aiSearchResultLineItems[i].getSysId();
var recommendationPayload = JSON.parse(aiSearchResultLineItems[i].getResultPayload());
var recommendation = {
"id": recommendationSysId,
"title": GlideSPScriptable().stripHTML(recommendationPayload.propValues.title),
"className": recommendationPayload.propValues.model.table,
"description": GlideSPScriptable().stripHTML(recommendationPayload.propValues.description)
};
recommendations.push(recommendation);
}
return recommendations;
};
function ensureValue(val) {
return gs.nil(val) ? '' : val;
}
Sys ID
42801ffe530501105400ddeeff7b1279