/**
* @module managers/prsonas-manager
* @description This module manages the DXP SDK functionality.
* @requires prsonasSdk
* @requires prsonasApp
* @requires prsonasAvatar
*/
define([
"prsonasSdk",
"prsonasApp",
"prsonasAvatar"
],
function ()
{
// ---------------------------------------------------------------
//
// PRSONAS MANAGER
//
// ---------------------------------------------------------------
var PrsonasManager = function ()
{
console.log(" * <prsonas>");
window.tEvent.eventStr.EVENT_SONAR = "EVENT_SONAR";
this.def = {
MSG_TYPE_PAGE : "page",
MSG_TYPE_LOCATION : "location",
MSG_TYPE_BUTTON : "button",
MSG_TYPE_ACTION : "action",
MSG_TYPE_LANGUAGE : "language",
MSG_TYPE_STATUS : "status",
MSG_TYPE_CUSTOM : "custom"
};
// from JSON config
this.jConfig = -1;
this.jLangConfig = -1;
this.config = -1;
this.sendKeyEvents = -1;
this.receiveKeyEvents = -1;
this.manifest = -1;
// prsonas code library
this.sdk = window.com.prsonas.sdk;
this.avatar = window.com.prsonas.sdk.avatar;
this.app = window.com.prsonas.sdk.app;
this.ui = {
};
// experience timer
this.experienceTimer = {
startTime : -1,
currentPage : -1,
inProgress : false
};
// maintains current page Event ID
this.currentPage = -1;
this.init();
};
PrsonasManager.prototype =
{
// ______________________________________________________________
// init
/**
* init
* @description Initializes class
* @fires assignListeners()
* @memberOf module:managers/prsonas-manager
* @instance
*/
init: function()
{
this.assignListeners();
},
// ______________________________________________________________
// assignListeners
/**
* assignListeners
* @description Assigns listeners to events used in this class.
* @listens EVENT_JSON_LOADED
* @listens EVENT_ADMIN_GOT_MANIFEST
* @listens EVENT_SET_LANGUAGE
* @listens EVENT_LANGUAGE_CONFIG_LOADED
* @listens sdk.subscribe("SENDKEY")
* @memberOf module:managers/prsonas-manager
* @instance
*/
assignListeners: function()
{
var self = this;
if (typeof window.oModel === "undefined" || window.oModel.jConfig === -1){
window.tEvent.addListener("EVENT_JSON_LOADED", function(evt, data)
{
// clean up for new page
self.onJsonLoaded(data);
});
} else {
self.onJsonLoaded(window.oModel.jConfig);
}
// manifest load
window.tEvent.addListener("EVENT_ADMIN_GOT_MANIFEST", function(evt, data){
self.onGotManifest(data);
});
// get language config
window.tEvent.addListener("EVENT_LANGUAGE_CONFIG_LOADED", function(evt, data){
self.jLangConfig = data;
});
// manifest load
window.tEvent.addListener("EVENT_SET_LANGUAGE", function(evt, languageData){
self.onSetLanguage(languageData);
});
if (typeof this.sdk !== "undefined") {
this.sdk.subscribe(this.sdk.app.eventTypes.SEND_KEY, function(evt){
self.onSonarEvent(evt);
});
}
},
// --------------------------------------------------------------
// HELPERS
// --------------------------------------------------------------
/**
* getTimeBasedIntent
* @description Checks for a time-based intent
* @param {String} intent - Intent to test against
* @return {String} Returns the intent to be used
* @memberOf module:managers/prsonas-manager
* @instance
*/
// ______________________________________________________________
// getTimeBasedIntent
getTimeBasedIntent: function(intent) {
if (typeof intent === "undefined" || typeof this.jConfig.iha === "undefined" || typeof this.jConfig.iha.timeBasedIntents === "undefined") {
return(intent);
}
var tbiObj = this.jConfig.iha.timeBasedIntents;
var isFound = "";
var newIntent = "";
var tempObj,
startTime,
endTime,
currentTime;
for (var key in tbiObj) {
if (key.toLowerCase() === intent.toLowerCase()){
isFound = key;
break;
}
}
if (isFound === ""){
return(intent);
} else {
tempObj = tbiObj[isFound];
currentTime = window.moment();
for (var i = 0; i < tempObj.validTimes.length; i++){
startTime = window.moment(tempObj.validTimes[i].timeStart, "h:mma");
endTime = window.moment(tempObj.validTimes[i].timeStop, "h:mma");
if ( currentTime.isBetween(startTime, endTime) ){
newIntent = tempObj.validTimes[i].intent;
break;
}
}
if (newIntent === ""){
newIntent = tempObj.defaultIntent;
}
console.log(" * <oPrsonas.sendKey.getTimeBasedIntent> Using time based intent", newIntent);
return(newIntent);
}
},
// ______________________________________________________________
// sendKey
/**
* sendKey
* @description Fires off animation intent. First checking for a time-based intent
* @param {String} intent - Intent to test against
* @fires avatar.playAnimation()
* @memberOf module:managers/prsonas-manager
* @instance
*/
sendKey: function(intent, speechText) {
if (intent === ""){
return;
}
// check for time based intent
intent = this.getTimeBasedIntent(intent);
// play anim/intent
if (typeof speechText !== "undefined"){
this.avatar.playAnimation(intent, speechText);
console.log(" * <prsonas.sendKey> " + intent + " | " + speechText);
} else {
this.avatar.playAnimation(intent);
console.log(" * <prsonas.sendKey> " + intent);
}
},
// ______________________________________________________________
// startExperienceTimer
/**
* startExperienceTimer
* @description Restarts experience timer
* @param {String} pageEvent - Page event restarting the experience timer
* @memberOf module:managers/prsonas-manager
* @instance
*/
startExperienceTimer: function(pageEvent) {
this.experienceTimer.inProgress = true;
this.experienceTimer.startTime = new Date();
this.experienceTimer.currentPage = pageEvent;
},
// ______________________________________________________________
// clearExperienceTimer
/**
* clearExperienceTimer
* @description Clears/kills experience timer
* @memberOf module:managers/prsonas-manager
* @instance
*/
clearExperienceTimer: function() {
this.experienceTimer.startTime = -1;
this.experienceTimer.inProgress = false;
this.experienceTimer.currentPage = -1;
},
// ______________________________________________________________
// endExperienceTimer
/**
* endExperienceTimer
* @description Ends experience experience timer and packages data for stats
* @todo Need to log the stats
* @memberOf module:managers/prsonas-manager
* @instance
*/
endExperienceTimer: function() {
if (!this.experienceTimer.inProgress) return;
var experienceTime = Math.abs( this.experienceTimer.startTime - (new Date()) );
if (experienceTime < this.config.timers.minInteractTime) return;
// Convert to seconds
var duration = Math.abs(experienceTime / 1000);
duration = Math.ceil(duration);
console.log(" * <prsonas.endExperienceTimer> Experience lasted " + duration + " seconds");
//Need to check if we are in an interaction. If not exit.
if(duration < 1000){
//Package up data
var payload = {};
payload["SessionDuration"] = duration.toString();
payload["ExitPage"] = this.currentPage;
var data = JSON.stringify(payload);
//this.sendGenericStat(data);
} else {
console.log(" * <prsonas.endExperienceTimer> Session Timer sent out of range Capture");
}
// Reset start times
this.clearExperienceTimer();
},
// ______________________________________________________________
// initSendKeyEvents
/**
* initSendKeyEvents
* @description Initializes the project JSON sendKeyEvents to trigger intents/sendkeys when event is fired
* @fires endExperienceTimer()
* @fires startExperienceTimer()
* @fires sendKey()
* @memberOf module:managers/prsonas-manager
* @instance
*/
initSendKeyEvents: function(){
var lang = $("body").attr("data-lang");
var self = this;
var knowledgebase = window.oPrsonas.avatar.getQAProjectInfo(true);
var isKb = false;
for (var e in this.sendKeyEvents) {
window.tEvent.addListener(e, function(evt, data) {
// end timer
self.endExperienceTimer();
// start timer
self.startExperienceTimer(evt.type);
if (typeof self.sendKeyEvents[evt.type] !== "undefined") {
var intent = self.sendKeyEvents[evt.type].toLowerCase();
// check if genai
if (typeof data !== "undefined" && typeof data.spokenStr !== "undefined" && typeof data !== "string" && typeof data.action_speech === "undefined") {
var doFallback = false;
if (typeof data.action_speechfallback !== "undefined"){
var langExceptions = self.jConfig.services.genaiFallbackToIntents;
for (var i = 0; i < langExceptions.length; i++) {
if (langExceptions[i] === lang) {
doFallback = true;
break;
}
}
}
if (doFallback){
self.sendKey(data.action_speechfallback.id);
} else {
if (typeof data._raw.properties.answer.qnaId !== "undefined") {
intent = window.oSpeech.formatQnaIntent(data._raw.properties.answer.qnaId);
} else {
intent = window.oSpeech.formatIntentName(data._raw.value);
}
self.sendKey(intent, data.answer);
}
} else if (typeof data !== "undefined" && typeof data !== "string" && typeof data.action_speech !== "undefined") {
var doFallback = false;
if (typeof data.action_speechfallback !== "undefined"){
var langExceptions = self.jConfig.services.genaiFallbackToIntents;
for (var i = 0; i < langExceptions.length; i++) {
if (langExceptions[i] === lang) {
doFallback = true;
break;
}
}
}
if (doFallback){
self.sendKey(data.action_speechfallback.id);
} else {
if (data.action_speech.context === lang){
self.sendKey(data.action_speech.id);
} else {
self.sendKey(data.action_speech.id, data.answer);
}
}
} else {
// check against knowledgebase
isKb = false
let temp = -1;
if (knowledgebase.success === true && typeof knowledgebase.data.qna !== "undefined") {
// look for intent
for (let i = 0; i < knowledgebase.data.qna.length; i++) {
// get which metadata we need
if (typeof knowledgebase.data.qna[i].metadata !== "undefined") {
if (typeof knowledgebase.data.qna[i].metadata.action_ux !== "undefined") { //action_ux
temp = knowledgebase.data.qna[i].metadata.action_ux.split("_")[1];
} else if (typeof knowledgebase.data.qna[i].metadata.navigation !== "undefined") { // navigation
temp = knowledgebase.data.qna[i].metadata.navigation;
} else if (typeof knowledgebase.data.qna[i].metadata.intent !== "undefined") { // intent
temp = knowledgebase.data.qna[i].metadata.intent;
}
if (temp !== -1 && temp === intent) {
isKb = true;
self.sendKey(intent, knowledgebase.data.qna[i].answer);
break;
}
}
}
}
// if there is no match in the knowledgebase -> check for json copy
if (!isKb) {
if (self.jLangConfig !== -1 && typeof self.jLangConfig.customIntents[intent] !== "undefined"){
if (lang === "_ASL" || lang === "_BSL"){
self.sendKey(intent);
} else {
self.sendKey(intent, self.jLangConfig.customIntents[intent]);
}
} else {
self.sendKey(intent);
}
}
}
}
});
}
},
// ______________________________________________________________
// getConfigSetting
/**
* getConfigSetting
* @description Returns setting from avatar config
* @param {String} settingStr - property from avatar config
* @returns SettingsValue
* @memberOf module:managers/prsonas-manager
* @instance
*/
getConfigSetting: function(settingStr) {
return (this.app.getSetting(settingStr));
},
// ______________________________________________________________
// fireSendkeyEvent
/**
* fireSendkeyEvent
* @description Fires off event based on sonar received sendkey based on project JSON receiveKeyEvents object
* @param {String} sendkey - sendkey received from sonar
* @returns SettingsValue
* @memberOf module:managers/prsonas-manager
* @instance
*/
fireSendkeyEvent: function(sendkey) {
if (typeof this.receiveKeyEvents[sendkey.toUpperCase()] === "undefined") {
return;
}
var evt = this.receiveKeyEvents[sendkey.toUpperCase()].event;
console.log(" * <prsonas.fireSendkeyEvent> ", evt);
window.tEvent.fire(evt);
},
// --------------------------------------------------------------
// EVENTS
// --------------------------------------------------------------
// ______________________________________________________________
// onJsonLoaded
/**
* onJsonLoaded
* @description Project JSON loaded handling
* @param {JSON} jData - Project JSON
* @fires initSendKeyEvents()
* @memberOf module:managers/prsonas-manager
* @instance
*/
onJsonLoaded: function(jData) {
console.log(" * <prsonas.onJsonLoaded>", jData);
if (this.config !== -1){
return;
}
// get JSON personas config
this.jConfig = jData;
this.config = window.helpers.clone(jData.prsonas);
// sendKey Events
this.sendKeyEvents = window.helpers.clone(jData.sendKeyEvents);
// receive key Events
this.receiveKeyEvents = window.helpers.clone(jData.receiveKeyEvents);
this.initSendKeyEvents();
},
// ______________________________________________________________
// onGotManifest
/**
* onGotManifest
* @description Received SDK manifest JSON
* @param {JSON} jData - SDK Manifest JSON
* @memberOf module:managers/prsonas-manager
* @instance
*/
onGotManifest: function(jData) {
if (this.manifest !== -1){
return;
}
this.manifest = jData;
},
// ______________________________________________________________
// onSetLanguage
/**
* onSetLanguage
* @description Sets the avatar language.
* @param {Object} languageData - Data of the language being set to
* @memberOf module:managers/prsonas-manager
* @instance
*/
onSetLanguage: function(languageData) {
var langCode = this.jConfig.language.nuBrowserIds[languageData.language];
if (typeof langCode !== "undefined") {
console.log(" ! <prsonas.onSetLanguage> langCode", langCode);
// set avatar language.
window.oPrsonas.avatar.setLanguage(langCode);
} else {
console.warn(" ! <prsonas.onSetLanguage> No language data available.");
}
},
// ______________________________________________________________
// onSonarEvent
/**
* onSonarEvent
* @description Received sonar event
* @param {Object} sonarEvt - Sonar event data
* @fires EVENT_SONAR_SENDKEY
* @memberOf module:managers/prsonas-manager
* @instance
*/
onSonarEvent: function(sonarEvt) {
console.log(" * <prsonas.onSonarEvent> ", sonarEvt);
window.tEvent.fire(window.tEvent.eventStr.EVENT_SONAR, sonarEvt);
switch(sonarEvt.type){
case this.sdk.app.eventTypes.SEND_KEY:
this.fireSendkeyEvent(sonarEvt.value);
break;
}
}
};
/**
* @global
*/
window.oPrsonas = new PrsonasManager();
return (window.oPrsonas);
});