Name
sn_ci_analytics.CAClickMetricsCustomEventProcessor
Description
No description available
Script
var CAClickMetricsCustomEventProcessor = Class.create();
var eventInfoRequiredByEventName = {
AI_SEARCH_TRIGGERED: ['Search Term', 'Results Count', 'Language', 'Results Count'],
AI_SEARCH_RESULT_CLICKED: ['Order', 'Search Term', 'Title', 'Description'],
AI_SEARCH_RESULT_DISPLAYED: ['Title', 'Search Term', 'Description', 'Data Source Title', 'Document Table'],
CONTEXTUAL_SEARCH_TRIGGERED: ['Search Term', 'Results Count', 'Language', 'Results Count'],
CONTEXTUAL_SEARCH_RESULT_DISPLAYED: ['Title', 'Search Term', 'Description', 'Data Source Title', 'Document Table'],
CONTEXTUAL_SEARCH_RESULT_CLICKED: ['Order', 'Search Term', 'Title', 'Description'],
SEARCH_RESULT_CLICKED: ['Order', 'Search Term', 'Title', 'Description'],
BOT_OUTPUT_CREATED: ['Header', 'Name', 'Results Count', 'Search Term'],
BOT_OUTPUT_LINK_DISPLAYED: ['URL', 'Control Type', 'Order', 'Search Term'],
BOT_OUTPUT_LINK_CLICKED: ['Order', 'Search Term', 'URL'],
}
CAClickMetricsCustomEventProcessor.prototype = {
initialize: function() {
this.logger = CIAnalyticsLogger.getLogger({
source: "CASearchCustomEventProcessor"
});
this.conversationEventsInfo = {};
this.isAISearchTriggered = false;
this.payloadBuilder = {};
},
process: function(payloadBuilder) {
try {
//initiating conversation with empty data
this.conversationEventsInfo = {};
this.payloadBuilder = payloadBuilder;
var conversation = payloadBuilder.getConversation();
var conversationId = conversation.Id;
// preprocessing conversation click metrics events
this._preProcessConversationSearchInfo(conversationId);
var events = this._generateEvents();
// pushing events to conversation custome events list
events.forEach(function(event) {
payloadBuilder.getConversation()['Events'].push(event);
});
if (this.isAISearchTriggered) {
payloadBuilder.setAISearchInvokedStatus();
}
} catch (err) {
var message = "CI analytics search metrics processing failed:" + err.message;
if (err.stack)
message = message + "\n" + err.stack;
this.logger.error(message);
}
},
// Mimics Object.values() function & Returns values
_ObjectValues: function(obj) {
obj = obj ? obj : {};
return Object.keys(obj).map(function(key) {
return obj[key];
});
},
_createSearchEvents: function(searchInfo) {
var events = [];
var eventTypes = Object.keys(searchInfo);
var isAISearch = true;
var results = [];
var _this = this;
eventTypes.forEach(function(eventType) {
if (eventType == CAConstants.eventNames.AI_SEARCH_TRIGGERED) {
events.push(searchInfo.AI_SEARCH_TRIGGERED);
} else if (eventType == CAConstants.eventNames.AI_SEARCH_RESULT_DISPLAYED) {
results = _this._ObjectValues(searchInfo.AI_SEARCH_RESULT_DISPLAYED);
events = events.concat(results);
} else if (eventType == CAConstants.eventNames.CONTEXTUAL_SEARCH_TRIGGERED) {
isAISearch = false;
events.push(searchInfo.CONTEXTUAL_SEARCH_TRIGGERED);
} else if (eventType == CAConstants.eventNames.CONTEXTUAL_SEARCH_RESULT_DISPLAYED) {
results = _this._ObjectValues(searchInfo.CONTEXTUAL_SEARCH_RESULT_DISPLAYED);
events = events.concat(results);
}
});
if (!this.isAISearchTriggered && isAISearch) {
this.isAISearchTriggered = true;
}
if (isAISearch) {
var searchResutltsClicked = searchInfo[CAConstants.eventNames.AI_SEARCH_RESULT_CLICKED] ? searchInfo[CAConstants.eventNames.AI_SEARCH_RESULT_CLICKED] : searchInfo.SEARCH_RESULT_CLICKED;
results = this._ObjectValues(searchResutltsClicked);
results.forEach(function(result) {
result.Name = CAConstants.eventNames.AI_SEARCH_RESULT_CLICKED;
var searchClickedInfo = searchInfo.AI_SEARCH_RESULT_DISPLAYED[result.Properties['Order']];
Object.keys(searchClickedInfo.Properties).forEach(function(key) {
result.Properties[key] = searchClickedInfo.Properties[key];
});
});
if (!searchInfo.AI_SEARCH_RESULT_CLICKED) {
searchInfo[CAConstants.eventNames.AI_SEARCH_RESULT_CLICKED] = searchInfo.SEARCH_RESULT_CLICKED;
}
events = events.concat(results);
} else {
results = this._ObjectValues(searchInfo.SEARCH_RESULT_CLICKED);
results.forEach(function(result) {
result.Name = CAConstants.eventNames.CONTEXTUAL_SEARCH_RESULT_CLICKED;
var searchClickedInfo = searchInfo.CONTEXTUAL_SEARCH_RESULT_DISPLAYED[result.Properties['Order']];
Object.keys(searchClickedInfo.Properties).forEach(function(key) {
result.Properties[key] = searchClickedInfo.Properties[key];
});
});
events = events.concat(results);
searchInfo[CAConstants.eventNames.CONTEXTUAL_SEARCH_RESULT_CLICKED] = searchInfo.SEARCH_RESULT_CLICKED;
}
if (isAISearch) {
var aiSearchResults = searchInfo.AI_SEARCH_RESULT_DISPLAYED;
var hasSearchResults = aiSearchResults && Object.keys(aiSearchResults).length;
if (!hasSearchResults) {
events.push({
Name: CAConstants.eventNames.AI_SEARCH_ZERO_RESULTS,
Type: 'Custom',
Properties: searchInfo.AI_SEARCH_TRIGGERED.Properties,
Time: searchInfo.AI_SEARCH_TRIGGERED.Time
});
}
var aiSearchResultsClicked = searchInfo.AI_SEARCH_RESULT_CLICKED;
var hasSearchResultsClicked = aiSearchResultsClicked && Object.keys(aiSearchResultsClicked).length;
if (hasSearchResults && !hasSearchResultsClicked) {
events.push({
Name: CAConstants.eventNames.AI_SEARCH_ZERO_CLICKS,
Type: 'Custom',
Properties: searchInfo.AI_SEARCH_TRIGGERED.Properties,
Time: searchInfo.AI_SEARCH_TRIGGERED.Time
});
}
} else {
var contextualSearchResults = searchInfo.CONTEXTUAL_SEARCH_RESULT_DISPLAYED;
var hasContextualSearchResults = contextualSearchResults && Object.keys(contextualSearchResults).length;
if (!hasContextualSearchResults) {
events.push({
Name: CAConstants.eventNames.CONTEXTUAL_SEARCH_ZERO_RESULTS,
Type: 'Custom',
Properties: searchInfo.CONTEXTUAL_SEARCH_TRIGGERED.Properties,
Time: searchInfo.CONTEXTUAL_SEARCH_TRIGGERED.Time
});
}
var contextualSearchResultsClicked = searchInfo.CONTEXTUAL_SEARCH_RESULT_CLICKED;
var hasContextualSearchResultsClicked = contextualSearchResultsClicked && Object.keys(contextualSearchResultsClicked).length;
if (hasContextualSearchResults && !hasContextualSearchResultsClicked) {
events.push({
Name: CAConstants.eventNames.CONTEXTUAL_SEARCH_ZERO_CLICKS,
Type: 'Custom',
Properties: searchInfo.CONTEXTUAL_SEARCH_TRIGGERED.Properties,
Time: searchInfo.CONTEXTUAL_SEARCH_TRIGGERED.Time
});
}
}
return events;
},
_createBotEvents: function(botInfo) {
var events = [];
var results = [];
var hasBotOutResults = false;
events.push(botInfo.BOT_OUTPUT_CREATED);
if (botInfo.BOT_OUTPUT_LINK_DISPLAYED) {
hasBotOutResults = true;
results = this._ObjectValues(botInfo.BOT_OUTPUT_LINK_DISPLAYED);
events = events.concat(results);
} else {
events.push({
Name: CAConstants.eventNames.BOT_OUTPUT_ZERO_RESULTS,
Type: 'Custom',
Properties: botInfo.BOT_OUTPUT_CREATED.Properties,
Time: botInfo.BOT_OUTPUT_CREATED.Time
});
}
if (botInfo[CAConstants.eventNames.BOT_OUTPUT_LINK_CLICKED]) {
results = this._ObjectValues(botInfo[CAConstants.eventNames.BOT_OUTPUT_LINK_CLICKED]);
results.forEach(function(result) {
var botClickedInfo = botInfo.BOT_OUTPUT_LINK_DISPLAYED[result.Properties['Order']];
Object.keys(botClickedInfo.Properties).forEach(function(key) {
result.Properties[key] = botClickedInfo.Properties[key];
});
});
events = events.concat(results);
} else if (hasBotOutResults) {
events.push({
Name: CAConstants.eventNames.BOT_OUTPUT_ZERO_CLICKS,
Type: 'Custom',
Properties: botInfo.BOT_OUTPUT_CREATED.Properties,
Time: botInfo.BOT_OUTPUT_CREATED.Time,
});
}
return events;
},
_generateEvents: function() {
var ids = Object.keys(this.conversationEventsInfo);
var events = [];
var _this = this;
ids.forEach(function(id) {
var info = _this.conversationEventsInfo[id];
if (info.type == 'search') {
var searchEvents = _this._createSearchEvents(info);
events = events.concat(searchEvents);
} else if (info.type == 'bot-links') {
var botEvents = _this._createBotEvents(info);
events = events.concat(botEvents);
}
});
return events;
},
_cleanAttributes: function(attributes, customEventName) {
var eventAttributes = {};
if (eventInfoRequiredByEventName[customEventName]) {
eventInfoRequiredByEventName[customEventName].forEach(function(attributeName) {
eventAttributes[attributeName] = attributes[attributeName];
});
return eventAttributes;
}
return attributes;
},
_fetchEventFromGroupAttributes: function(attributes, customEventName) {
var event = {
Name: customEventName,
Type: 'Custom',
Time: attributes['Response Time'] ? parseInt(attributes['Response Time']) : 0,
}
event.Properties = this._cleanAttributes(attributes, customEventName)
return event;
},
_customEventName: function(searchType, eventName, resultType) {
if (searchType && searchType.includes('AI Search')) {
return 'AI_' + eventName;
} else if (searchType == 'Contextual') {
return 'CONTEXTUAL_' + eventName;
} else if (resultType && resultType.includes('AI Search')) {
return 'AI_' + eventName;
}
return eventName;
},
_fetchSearchStringFromContext: function(rec) {
try {
var context = rec.getValue('context').substring(16);
var taskContextXml = new global.VAGlobalUtil().getDecompressedValue(context);
var xmlDoc = new XMLDocument2();
xmlDoc.parseXML(taskContextXml);
var searchValue = xmlDoc.getNodeText("/com.glide.cs.qlue.entities.TaskContext/values/entry[string='search_text']/com.glide.cs.qlue.entities.TypedValue/value");
return searchValue;
} catch (e) {
return false;
}
},
_appendTopicAndSearchTermInfo: function(attributes) {
var documentId = attributes['document_id'];
var documentRef = attributes['document_ref'];
var rec = new GlideRecord(documentRef);
rec.get(documentId);
var topicId = rec.getValue('topic_type');
var searchTerm = this._fetchSearchStringFromContext(rec);
if (searchTerm) {
attributes['Search Term'] = searchTerm
} else {
var topicGR = new GlideRecord('sys_cs_topic');
topicGR.get(topicId);
attributes['Search Term'] = topicGR.getValue('name');
attributes['Topic'] = topicGR.getValue('name');
}
},
_updateConversationInfoBasedOnEventName: function(id, attributes, eventFrom, conversationId) {
var eventName = attributes.Name;
var customEventName = '';
var eventInfo = this.conversationEventsInfo[id];
if (eventFrom == 'search') {
var searchType = attributes['Search Type'];
var resultType = attributes['Result Type'];
customEventName = this._customEventName(searchType, eventName, resultType);
if (eventName == 'SEARCH_TRIGGERED') {
eventInfo[customEventName] = this._fetchEventFromGroupAttributes(attributes, customEventName);
} else if (eventName == 'SEARCH_RESULT_DISPLAYED') {
eventInfo[customEventName] = eventInfo[customEventName] ? eventInfo[customEventName] : {};
eventInfo[customEventName][attributes['Order']] = this._fetchEventFromGroupAttributes(attributes, customEventName);
if (resultType && (attributes['Result Type'].equals("AI Search - Genius") ||
(attributes['Result Type'].equals("AI Search - Standard") &&
attributes['Document Table'] && attributes['Document Table'].includes('kb_knowledge'))))
this.payloadBuilder.updateSharedKBCount();
} else if (eventName == 'SEARCH_RESULT_CLICKED') {
eventInfo[customEventName] = eventInfo[customEventName] ? eventInfo[customEventName] : {};
eventInfo[customEventName][attributes['Order']] = this._fetchEventFromGroupAttributes(attributes, customEventName);
}
} else if (eventFrom == 'bot-links') {
this._appendTopicAndSearchTermInfo(attributes);
if (eventName == CAConstants.eventNames.BOT_OUTPUT_CREATED) {
eventInfo[CAConstants.eventNames.BOT_OUTPUT_CREATED] = this._fetchEventFromGroupAttributes(attributes, CAConstants.eventNames.BOT_OUTPUT_CREATED);
} else if (eventName == CAConstants.eventNames.BOT_OUTPUT_LINK_DISPLAYED) {
customEventName = CAConstants.eventNames.BOT_OUTPUT_LINK_DISPLAYED;
eventInfo[customEventName] = eventInfo[customEventName] ? eventInfo[customEventName] : {};
eventInfo[customEventName][attributes['Order']] = this._fetchEventFromGroupAttributes(attributes, customEventName);
if (attributes['URL'].includes('kb_knowledge'))
this.payloadBuilder.updateSharedKBCount();
} else if (eventName == CAConstants.eventNames.BOT_OUTPUT_LINK_CLICKED) {
customEventName = CAConstants.eventNames.BOT_OUTPUT_LINK_CLICKED;
eventInfo[customEventName] = eventInfo[customEventName] ? eventInfo[customEventName] : {};
eventInfo[customEventName][attributes['Order']] = this._fetchEventFromGroupAttributes(attributes, customEventName);
}
}
},
_preProcessConversationSearchInfo: function(conversationId) {
var groupIdsGr = this._fetchConversationSearchGroups(conversationId);
while (groupIdsGr.next()) {
var groupId = groupIdsGr.getValue('group_id');
var attributesOfSearchGroup = this._fetchGroupAttributes(groupId, conversationId);
var searchId = attributesOfSearchGroup['Search Id'];
var correlationId = attributesOfSearchGroup['Correlation Id'];
if (searchId && searchId != 'undefined') {
if (this.conversationEventsInfo[searchId]) {
this._updateConversationInfoBasedOnEventName(searchId, attributesOfSearchGroup, 'search', conversationId);
} else {
this.conversationEventsInfo[searchId] = {
type: 'search'
};
this._updateConversationInfoBasedOnEventName(searchId, attributesOfSearchGroup, 'search', conversationId);
}
} else if (correlationId && correlationId != 'undefined') {
if (this.conversationEventsInfo[correlationId]) {
this._updateConversationInfoBasedOnEventName(correlationId, attributesOfSearchGroup, 'bot-links', conversationId);
} else {
this.conversationEventsInfo[correlationId] = {
type: 'bot-links'
};
this._updateConversationInfoBasedOnEventName(correlationId, attributesOfSearchGroup, 'bot-links', conversationId);
}
}
}
},
_fetchGroupAttributes: function(groupId, conversationId) {
var attributes = {};
var rec = new GlideRecord('sys_ci_analytics');
rec.addQuery('conversation', conversationId);
rec.addQuery('group_id', groupId);
rec.query();
while (rec.next()) {
var jsonObj = JSON.parse(rec.getValue("metric"));
attributes['document_ref'] = rec.getValue('document_ref');
attributes['document_id'] = rec.getValue('document_id');
for (key in jsonObj) {
attributes[key] = jsonObj[key];
}
}
return attributes;
},
_fetchConversationSearchGroups: function(conversationId) {
var rec = new GlideAggregate('sys_ci_analytics');
rec.addQuery('conversation', conversationId);
rec.groupBy('group_id');
rec.query();
return rec;
},
type: 'CAClickMetricsCustomEventProcessor'
};
Sys ID
b9d9c67d77933010c23e1f130e5a99ad