/**
* @module managers/speech-manager
* @description This module manages speech
* @requires modules/hash
* @requires common/view
* @requires managers/template-manager
* @requires managers/prsonas-manager
* @requires jHammer
*/
define([
"managers/prsonas-manager",
"managers/timer-manager"
],
function (Prsonas, Timer) {
// ---------------------------------------------------------------
//
// SPEECH MANAGER
//
// ---------------------------------------------------------------
var Speech = function () {
console.log(" * <speech>");
this.oPrsonas = Prsonas;
this.oTimer = Timer;
window.tEvent.eventStr.EVENT_IN_WALKAWAY = "EVENT_IN_WALKAWAY";
window.tEvent.eventStr.EVENT_IN_WALKUP = "EVENT_IN_WALKUP";
this.ui = {
speakPanel : ".js-complex-speak",
speakCopy : ".js-complex-speak-copy",
ccPanel : ".js-complex-cc",
ccCopy : ".js-complex-cc-copy",
micToggle : ".js-complex-mic",
micIcon : ".js-complex-mic-icon",
micSwitch : ".js-complex-mic-switch",
backBtn : ".js-complex-back-btn",
homeBtn : ".js-complex-home-btn",
aslFadeContent : ".js-complex-asl-fade"
};
this.def = {
CLASS_HIDE_ME : "hide-me",
SENTIMENT_POSITIVE : "_positive",
SENTIMENT_NEGATIVE : "_negative"
};
// forced mic toggle
this.micEnabled = true;
// json config
this.jConfig = -1;
// manifest
this.manifest = -1;
// enable first load events
this.firstLoad = true;
this.qaUpdateDate = -1;
this.init();
};
Speech.prototype = {
// ______________________________________________________________
// init
/**
* init
* @description Initializes class
* @memberOf module:managers/speech-manager
* @instance
*/
init: function() {
var self = this;
if (typeof window.oModel === "undefined" || window.oModel.modelReady === false){
window.tEvent.addListener("EVENT_MODEL_READY", function(evt, data) {
self.onModelReady();
});
} else {
self.onModelReady();
}
},
// ______________________________________________________________
// initSpeech
/**
* initSpeech
* @description Init speech
* @fires assignListeners();
* @memberOf module:managers/speech-manager
* @instance
*/
initSpeech: function() {
var self = this;
if (!this.jConfig.speech.showMicToggle){
$(this.ui.micToggle).addClass(this.def.CLASS_HIDE_ME);
}
// set this.qaUpdateDate
if (typeof window.oPrsonas.avatar !== "undefined" && typeof window.oPrsonas.avatar.getQAProjectInfo !== "undefined"){
this.qaUpdateDate = window.oPrsonas.avatar.getQAProjectInfo().data.lastDeployedDateTime;
}
this.assignListeners();
},
// ______________________________________________________________
// assignListeners
/**
* assignListeners
* @description Assigns listeners to events used in this class.
* @listens EVENT_ADMIN_GOT_MANIFEST
* @listens EVENT_TEMPLATE_LOADED
* @listens EVENT_TIMER_EXPIRED
* @listens EVENT_HISTORY
* @listens avatar.eventTypes["CC"]
* @listens avatar.eventTypes["END_CC"]
* @listens avatar.eventTypes["PHRASE_RECOGNIZED"]
* @memberOf module:managers/speech-manager
* @instance
*/
assignListeners: function() {
var self = this;
window.tEvent.addListener("EVENT_ADMIN_GOT_MANIFEST", function(evt, data){
self.manifest = data;
});
window.tEvent.addListener(window.tEvent.eventStr.EVENT_TEMPLATE_LOADED, function(evt, eventId){
self.onPageLoad(eventId);
});
window.tEvent.addListener("EVENT_TIMER_EXPIRED", function(evt, data){
self.doWalkAway();
});
window.tEvent.addListener([this.jConfig.prsonas.timers.expiredEvent], function(evt, data){
self.doWalkAway();
});
$("body").hammer().on("click", this.ui.micSwitch, function(e){
self.onToggleMic();
});
// cc event
this.oPrsonas.sdk.subscribe(this.oPrsonas.avatar.eventTypes["CC"], function(evt) {
self.onCcEvent(evt);
});
// endcc event
this.oPrsonas.sdk.subscribe(this.oPrsonas.avatar.eventTypes["END_CC"], function(evt) {
self.onEndCcEvent(evt);
});
// PHRASE_RECOGNIZED event
this.oPrsonas.sdk.subscribe(this.oPrsonas.avatar.eventTypes["PHRASE_RECOGNIZED"], function(evt) {
self.onSpeechPhraseRecognized(evt)
});
// timer expired
var walkUpevent = "";
for (var key in this.jConfig.receiveKeyEvents) {
if (key.toLowerCase() === "walkaway"){
walkUpevent = this.jConfig.receiveKeyEvents[key].event;
break;
}
}
window.tEvent.addListener(["EVENT_TIMER_EXPIRED", walkUpevent], function(evt, data){
self.onQaUpdateCheck();
});
},
// --------------------------------------------------------------
// HELPERS
// --------------------------------------------------------------
// ______________________________________________________________
// toggleSpeech
/**
* toggleSpeech
* @description Enables or Disables speech recognition
* @param {('enable'|'disable')} state - toggle to state
* @memberOf module:managers/speech-manager
* @instance
*/
toggleSpeech: function(state) {
var $micToggle = $(this.ui.micToggle);
var lang = $("body").attr("data-lang");
var langId = this.jConfig.language.nuBrowserIds[lang];
if (!this.micEnabled){
state = "disable";
$micToggle.removeClass("is-enabled");
$micToggle.addClass("is-disabled");
} else {
$micToggle.removeClass("is-disabled");
$micToggle.addClass("is-enabled");
}
switch(state){
case "disable":
$(this.ui.speakIcon).removeClass("is-listening");
this.oPrsonas.avatar.stopListening();
if (this.micEnabled){
this.oTimer.killTimer();
}
this.onIndicatorUpdate({
id: "microphone",
status: false
});
break;
case "enable":
$(this.ui.speakIcon).addClass("is-listening");
if (typeof langId !== "undefined"){
this.oPrsonas.avatar.startListening(langId);
}
// trigger listening intent
if (this.jConfig.speech.listeningIntent !== ""){
var doListen = true;
for (let i = 0; i < this.jConfig.speech.listeningIntentExceptionModules.length; i++){
if ( $("body").attr("data-module-id") === this.jConfig.speech.listeningIntentExceptionModules[i]){
doListen = false;
}
}
if (doListen) {
window.oPrsonas.sendKey(this.jConfig.speech.listeningIntent);
}
}
this.oTimer.resetTimeout();
window.tEvent.fire(window.tEvent.eventStr.EVENT_IN_WALKUP);
this.onIndicatorUpdate({
id: "microphone",
status: true
});
break;
}
},
// ______________________________________________________________
// doWalkAway
/**
* doWalkAway
* @description Sets the WalkAway state
* @fires EVENT_IN_WALKAWAY
* @memberOf module:managers/speech-manager
* @instance
*/
doWalkAway: function() {
this.resetSpeech();
window.tEvent.fire(window.tEvent.eventStr.EVENT_LANGUAGE_RESET);
this.toggleSpeech("disable");
if (!this.micEnabled) {
this.onToggleMic();
}
window.tEvent.fire(window.tEvent.eventStr.EVENT_IN_WALKAWAY);
},
// ______________________________________________________________
// resetSpeech
/**
* resetSpeech
* @description Resets the closed caption and speech panels
* @param {Boolean} [isFromEndCc=false] If true that this call is coming from an endCC event.
* @memberOf module:managers/speech-manager
* @instance
*/
resetSpeech: function(isFromEndCc) {
var self = this;
var ccFadeDelay = this.jConfig.speech.ccPanel.animation.delayFadoutOnEndCc;
if (typeof isFromEndCc === "undefined" || !isFromEndCc){
ccFadeDelay = 0;
}
// kill tweens
TweenLite.killTweensOf($(this.ui.aslFadeContent));
TweenLite.killTweensOf($(this.ui.ccPanel));
TweenLite.killTweensOf($(this.ui.speakPanel));
// fade in asl fade content
TweenLite.to($(this.ui.aslFadeContent), 1, {opacity: 1});
// clear cc copy
TweenLite.to($(this.ui.ccPanel), 1, {opacity: 0, delay: ccFadeDelay, onComplete:function(){
$(self.ui.ccCopy).scrollTop(0);
$(self.ui.ccCopy).html("");
$(self.ui.ccPanel).css("display", "none");
}});
// clear speak copy
TweenLite.to($(this.ui.speakPanel), 1, {opacity: 0, onComplete:function(){
$(self.ui.speakPanel).css("display", "none");
$(self.ui.speakCopy).html("");
}});
},
// ______________________________________________________________
// showCC
/**
* showCC
* @description Shows the closed caption copy of the ID found in content/json/langCopy.json
* @param {String} data - data of the closed caption
* @memberOf module:managers/speech-manager
* @instance
*/
showCC: function(data) {
var ccData = {};
var lang = $("body").attr("data-lang");
var ccConfig;
if (typeof window.oLang.jLangConfig.ccCopy[lang] !== "undefined"){
ccConfig = window.oLang.jLangConfig.ccCopy[lang];
}
var animConfig = this.jConfig.speech.ccPanel.animation;
var isFound = false;
var temp;
// update speech
this.onIndicatorUpdate({
id: "speech"
});
if (!this.jConfig.services.speechToText.alwaysListen){
this.toggleSpeech("disable");
}
this.oTimer.killTimer();
// get cc config.
if (typeof ccConfig !== "undefined"){
for (var key in ccConfig){
if (key.toLowerCase() === data.value.toLowerCase()){
// proxy?
if (typeof ccConfig[key].copyProxy !== "undefined" && ccConfig[key].copyProxy !==""){
ccData = ccConfig[ccConfig[key].copyProxy];
} else {
ccData = ccConfig[key];
}
isFound = true;
break;
}
}
}
if (!isFound){
ccData = {
"copy" : data.properties.copy
};
}
ccData.duration = Number(data.properties.duration);
// fade out asl fade content
if (lang.toLowerCase() === "_asl" || lang.toLowerCase() === "_bsl"){
TweenLite.to($(this.ui.aslFadeContent), 1, {opacity: 0.17});
}
// show and animate spoken panel0
TweenLite.killTweensOf($(this.ui.ccPanel));
TweenLite.killTweensOf($(this.ui.ccCopy));
$(this.ui.ccCopy).html(ccData.copy + "<br> ");
$(this.ui.ccCopy).scrollTop(0);
$(this.ui.ccPanel).css("display", "block");
$(this.ui.ccPanel).css("opacity", "0");
$(this.ui.ccPanel).css("marginTop", "-35px");
TweenLite.to($(this.ui.ccPanel), .5, {opacity: 1, marginTop: "0px"});
// do scroll
const elHeight = $(this.ui.ccCopy).height();
const elActualHeight = $(this.ui.ccCopy)[0].scrollHeight;
// init nice scroller
$(this.ui.ccCopy).niceScroll({emulatetouch:true, touchbehavior:true, autohidemode:true});
const scrollAmount = elActualHeight - elHeight;
const adjustedDuration = ccData.duration - (ccData.duration * 0.3); // adds buffer
const visibleFraction = Math.min(elHeight / elActualHeight, 1.0);
const pauseDuration = adjustedDuration * visibleFraction; // in seconds
const scrollDuration = ccData.duration - pauseDuration; // in seconds
const scrollDistance = elActualHeight - elHeight; // pixels to scroll
const scrollSpeed = scrollDuration > 0 ? scrollDistance / scrollDuration : 0; // pixels per second
if (scrollDuration > 0) {
TweenLite.to($(this.ui.ccCopy), scrollDuration, {scrollTop: scrollDistance, ease: "none"}).delay(pauseDuration);
}
},
// ______________________________________________________________
// isValidIntent
/**
* isValidIntent
* @description Validates intent against manifest.IntentMetaData
* @param {String} intentStr - Intent to validate
* @return {Object} Returns the IntentMetaData object for that intent
* @memberOf module:managers/speech-manager
* @instance
*/
isValidIntent: function(intentStr) {
var returnObj = window.oModel.getReturnObj();
returnObj.status = "error";
for (var key in this.manifest.IntentMetaData) {
if (key.toLowerCase() === intentStr){
returnObj.status = "ok";
returnObj.data = this.manifest.IntentMetaData[key];
break;
}
}
return(returnObj);
},
// ______________________________________________________________
// triggerActionEvent
/**
* triggerActionEvent
* @description Triggers an action event from processed phrase metadata results
* @param {Object} phraseObj - Phrase object from speech to text.
* @fires Event associated with action
* @memberOf module:managers/speech-manager
* @instance
*/
triggerActionEvent: function(phraseObj) {
var actionsConfig = this.jConfig.services.qaSpokenActions;
var lang = $("body").attr("data-lang").replace("_", "").toLowerCase();
var intent = "";
// speech
if (typeof phraseObj._sendKeyDone !== "undefined" && !phraseObj._sendKeyDone){
if (typeof phraseObj.action_speech === "undefined" && typeof phraseObj.action_ux !== "undefined" && phraseObj.action_ux.context !== "page") {
if (typeof phraseObj._raw.properties.answer.qnaId !== "undefined") {
intent = this.formatQnaIntent(phraseObj._raw.properties.answer.qnaId);
} else {
intent = this.formatIntentName(phraseObj._raw.value);
}
if (phraseObj.answer !== "") {
window.oPrsonas.sendKey(intent, phraseObj.answer);
phraseObj._sendKeyDone = true;
}
} else if (typeof phraseObj.action_speech !== "undefined") {
if (phraseObj.action_speech.context === lang){
window.oPrsonas.sendKey(phraseObj.action_speech.id);
phraseObj._sendKeyDone = true;
} else {
if (typeof phraseObj._raw.properties.answer.qnaId !== "undefined") {
intent = this.formatQnaIntent(phraseObj._raw.properties.answer.qnaId);
} else {
intent = this.formatIntentName(phraseObj._raw.value);
}
if (phraseObj.answer !== "") {
window.oPrsonas.sendKey(intent, phraseObj.answer);
phraseObj._sendKeyDone = true;
}
}
}
}
// action_ux handling
if (typeof phraseObj.action_ux !== "undefined"){
if (typeof actionsConfig[phraseObj.action_ux.context] !== "undefined"){
if (typeof actionsConfig[phraseObj.action_ux.context][phraseObj.action_ux.id] !== "undefined"){
window.tEvent.fire(actionsConfig[phraseObj.action_ux.context][phraseObj.action_ux.id], phraseObj);
}
}
}
},
// ______________________________________________________________
// formatIntentName
/**
* formatIntentName
* @description Reformats string for consistant valid intent name used for dynamic speech.
* @param {String} intentStr - String to be formated
* @returns {String} Formatted string
* @memberOf module:managers/speech-manager
* @instance
*/
formatIntentName: function(intentStr) {
intentStr = window.helpers.removeSpecialChars(intentStr).trim();
intentStr = intentStr.split(" ").join("_");
return( intentStr.toLowerCase() );
},
// ______________________________________________________________
// formatQnaIntent
/**
* formatQnaIntent
* @description Reformats qna ID to be used as intent.
* @param {String} qnaID - String to be formated
* @returns {String} Formatted string
* @memberOf module:managers/speech-manager
* @instance
*/
formatQnaIntent: function(qnaID) {
intentStr = "qna_" + String(qnaID);
return(intentStr);
},
// ______________________________________________________________
// processSpeechContext
/**
* processSpeechContext
* @description Process the context of the speech to text object. Context can be comment, navigation, location. Options include comment_intent, navigation_back, navigation_home, navigation_intent, location_locationID
* @param {Object} phraseObj - Phrase object from speech to text.
* @fires triggerActionEvent()
* @memberOf module:managers/speech-manager
* @instance
*/
processSpeechContext: function(phraseObj) {
if (typeof this.jConfig.services.qaSpokenActions === "undefined"){
console.warn(" ! <iha.processSpeechContext> jConfig.services.qaSpokenActions is not defined");
}
var actionsConfig = this.jConfig.services.qaSpokenActions;
var lang = $("body").attr("data-lang");
var intent = "";
phraseObj._sendKeyDone = false;
// speech handling
if ( (typeof phraseObj.action_speech === "undefined" || phraseObj.action_speech === "genai") && (typeof phraseObj.action_ux === "undefined") ){
var doFallback = false;
if (typeof phraseObj.action_speechfallback !== "undefined"){
var langExceptions = this.jConfig.services.genaiFallbackToIntents;
for (var i = 0; i < langExceptions.length; i++) {
if (langExceptions[i] === lang) {
doFallback = true;
break;
}
}
}
if (doFallback) {
window.oPrsonas.sendKey(phraseObj.action_speechfallback.id);
phraseObj._sendKeyDone = true;
} else {
if (typeof phraseObj._raw.properties.answer.qnaId !== "undefined") {
intent = this.formatQnaIntent(phraseObj._raw.properties.answer.qnaId);
} else {
intent = this.formatIntentName(phraseObj._raw.value);
}
if (phraseObj.answer !== "") {
window.oPrsonas.sendKey(intent, phraseObj.answer);
phraseObj._sendKeyDone = true;
}
}
}
// UX handling
if (typeof phraseObj.action_ux !== "undefined" && phraseObj.action_ux.context !== ""){
switch(phraseObj.action_ux.context){
case "closemodal":
window.oModal.close();
this.triggerActionEvent(phraseObj);
break;
case "modal":
window.oModal.load({
id: "mActionUx",
content : window.oProjTemplates["m" + phraseObj.action_ux.id](),
modalSource: "primary"
});
window.oLang.applyCurrentLanguage();
this.triggerActionEvent(phraseObj);
break;
case "qrcode":
var qrCodeBase64 = window.nc_gfx.getQrCodeBase64(phraseObj.action_ux.id, 4, "L");
qrCodeBase64 = 'data:image/png;base64, ' + qrCodeBase64
window.oModal.load({
id: "mQrCode",
content : window.oDxpTemplates.mQrCode({
base64: qrCodeBase64,
url: phraseObj.action_ux.id
}),
isBackground: false,
modalSource: "primary"
});
window.oLang.applyCurrentLanguage();
this.triggerActionEvent(phraseObj);
break;
case "intent":
if (typeof actionsConfig["intent"] !== "undefined"){
window.tEvent.fire(actionsConfig["intent"][phraseObj.action_ux.id]);
}
break;
case "comment":
window.oPrsonas.sendKey(phraseObj.action_ux.id);
this.triggerActionEvent(phraseObj);
break;
case "navigation":
switch(phraseObj.action_ux.id){
case "back":
if ($(this.ui.backBtn).length !== 0){
window.tEvent.fire("EVENT_PAGE_BACK_BTN");
} else if ($(this.ui.homeBtn).length !== 0) {
window.tEvent.fire("EVENT_PAGE_HOME_BTN");
} else {
return;
}
break;
case "home":
if ($(this.ui.homeBtn).length !== 0) {
window.tEvent.fire("EVENT_PAGE_HOME_BTN");
} else {
return;
}
break;
default:
this.triggerActionEvent(phraseObj);
}
break;
case "location":
if (typeof window.oIha !== "undefined" && window.oIha.oMappedIn !== "undefined" ){
if ($(".iha-mappedin-container").css("marginTop") === "-5000px"){
window.tEvent.fire("EVENT_PAGE_IHA_MAP", phraseObj.action_ux.id);
} else {
window.oIha.oMappedIn.showDirections(phraseObj.action_ux.id, phraseObj);
}
}
break;
default:
this.triggerActionEvent(phraseObj);
}
}
},
// ______________________________________________________________
// processSpeechPhrase
/**
* processSpeechPhrase
* @description Process the phrase of the speech to text object to process the context and display the speech to the UX
* @param {Object} phraseObj - Phrase object from speech to text.
* @fires processSpeechContext()
* @memberOf module:managers/speech-manager
* @instance
*/
processSpeechPhrase: function(phraseObj) {
console.log(" * <speech.processSpeechPhrase>", phraseObj);
var self = this;
var lang = $("body").attr("data-lang");
var animConfig = this.jConfig.speech.spokenPanel.animation;
var confidenceConfig = this.jConfig.services.speechToText.confidence;
if (Number(phraseObj.confidence) < Number(confidenceConfig.min)) {
console.log(" * <speech.processSpeechPhrase> ignored because of low confidence: " + phraseObj.confidence + " < " + confidenceConfig.min);
window.oPrsonas.sendKey("NoResponse");
this.toggleSpeech("enable");
// ignore
return;
} else if (Number(phraseObj.confidence) < Number(confidenceConfig.trigger)){
console.log(" * <speech.processSpeechPhrase> cant help because of low confidence: " + phraseObj.confidence + " < " + confidenceConfig.trigger);
window.tEvent.fire(window.tEvent.eventStr.EVENT_CANT_HELP);
} else {
this.processSpeechContext(phraseObj);
}
// populate spoken copy
var showStr = phraseObj.spokenStr
$(this.ui.speakCopy).html(showStr);
// show spoken panel
TweenLite.killTweensOf($(this.ui.speakPanel));
$(this.ui.speakPanel).css("opacity", 0);
$(this.ui.speakPanel).css("display", "table");
$(this.ui.speakPanel).css("marginLeft", "-50px");
TweenLite.to($(this.ui.speakPanel), .3, {opacity: 1, marginLeft: "0px"});
window.setTimeout(function(){
TweenLite.to($(self.ui.speakPanel), 2, {opacity: 0, display: "none", onComplete:function(){
$(self.ui.speakCopy).html("");
}});
}, animConfig.fadeOutTimer);
},
// --------------------------------------------------------------
// EVENTS
// --------------------------------------------------------------
// ______________________________________________________________
// onQaUpdateCheck
/**
* onQaUpdateCheck
* @description Knowedge Base modified check. Refresh browser if true.
* @memberOf module:managers/speech-manager
* @instance
*/
onQaUpdateCheck: function() {
if (this.qaUpdateDate === -1){
return;
}
var qaDate = window.oPrsonas.avatar.getQAProjectInfo().data.lastDeployedDateTime;
var date1 = moment(qaDate);
var date2 = moment(this.qaUpdateDate);
var isAfter = date1.isAfter(this.qaUpdateDate);
if (isAfter){
window.location.reload(true);
}
},
// ______________________________________________________________
// onModelReady
/**
* onModelReady
* @description Initializes class
* @memberOf module:managers/speech-manager
* @instance
*/
onModelReady: function() {
// set defines
this.def = _.merge(this.def, window.oModel.def);
// set jConfig data
this.jConfig = window.oModel.jConfig;
this.initSpeech();
},
// ______________________________________________________________
// onToggleMic
/**
* onToggleMic
* @description Toggle the mic state
* @param {Boolean} forceState (Optional) forces mic state
* @fire toggleSpeech()
* @memberOf module:managers/speech-manager
* @instance
*/
onToggleMic: function(forceState) {
var $micToggle = $(this.ui.micToggle);
var toggleSpeech = "";
var micState;
if (typeof forceState === "undefined"){
if ($micToggle.hasClass("is-enabled")){
micState = false;
} else {
micState = true;
}
} else {
micState = forceState;
}
if (micState){
$micToggle.removeClass("is-disabled");
$micToggle.addClass("is-enabled");
this.micEnabled = true;
toggleSpeech = "enable";
} else {
$micToggle.removeClass("is-enabled");
$micToggle.addClass("is-disabled");
this.micEnabled = false;
toggleSpeech = "disable";
}
this.toggleSpeech(toggleSpeech);
},
// ______________________________________________________________
// onProcessStatusMessage
/**
* onProcessStatusMessage
* @description Receive and process Prsonas event status message
* @param {Object} data - Message object
* @fire toggleSpeech()
* @memberOf module:managers/speech-manager
* @instance
*/
onProcessStatusMessage: function(data) {
switch(data.type){
case "status":
if (data.property === "ischaracterspeaking"){
data.value = data.value.trim();
console.log(" * <speech.onProcessStatusMessage> speech: ", data.value);
$("body").attr("data-speaking", data.value);
if (data.value === "true"){
this.toggleSpeech("disable");
} else {
this.toggleSpeech("enable");
}
}
break;
}
},
// ______________________________________________________________
// onCcEvent
/**
* onCcEvent
* @description Receives closed caption event
* @param {Object} data - Message object
* @memberOf module:managers/speech-manager
* @fires showCC()
* @instance
*/
onCcEvent: function(data){
console.log(" * <speech.onCcEvent>", data);
//display cc copy
this.showCC(data);
},
// ______________________________________________________________
// on`Event
/**
* onEndCcEvent
* @description Receives end closed caption event
* @param {Object} data - Message object
* @memberOf module:managers/speech-manager
* @instance
*/
onEndCcEvent: function(data){
let doCleanup = false;
if (typeof data.properties.segment === "undefined") {
doCleanup = true;
} else {
const currentSeg = window.Number(data.properties.segment.split("/")[0]);
const totalSegs = window.Number(data.properties.segment.split("/")[1]);
if (currentSeg === totalSegs) {
doCleanup = true;
}
}
if (doCleanup) {
console.log(" * <speech.onEndCcEvent>", data);
if (data.value.toLowerCase().indexOf("walkaway") !== -1) {
this.doWalkAway();
} else {
var isFound = false;
for (let i = 0; i < this.jConfig.intentsToIgnoreMicActivation.length; i++) {
if (data.value.toLowerCase() === this.jConfig.intentsToIgnoreMicActivation[i]){
isFound = true;
break;
}
}
if (!isFound) {
this.resetSpeech(true);
this.toggleSpeech("enable");
}
}
// update speech
this.onIndicatorUpdate({
id: "speech"
});
}
},
// ______________________________________________________________
// onIndicatorUpdate
/**
* onIndicatorUpdate
* @description Receive and process UX updates on status indicator states
* @param {Object} data - Message object
* @memberOf module:managers/speech-manager
* @instance
*/
onIndicatorUpdate: function(data) {
switch(data.id){
case "microphone":
window.oConnection.showMicrophoneAccessWarning(data.status);
break;
case "speech":
window.oConnection.showSpeechAccessWarning();
break;
}
},
// ______________________________________________________________
// onSpeechPhraseRecognized
/**
* onSpeechPhraseRecognized
* @description Receive and parse phrase from speech to text.
* @param {Object} data - Speech data
* @fires processSpeechPhrase()
* @memberOf module:managers/speech-manager
* @instance
*/
onSpeechPhraseRecognized: function(data) {
if (!this.jConfig.speech.isSpeachEnabled){
return;
}
this.toggleSpeech("disable");
console.log(" * <speech.onSpeechPhraseRecognized> ", data);
var responseObj = {
spokenStr : data.properties.raw_phrase,
answer : data.properties.answer.text,
confidence : data.properties.answer.metadata.confidence,
_raw : data
};
// fix for not being able to submit no answer in the knowledge base
if (responseObj.answer.trim() === ".") {
responseObj.answer = "";
}
var id = "";
// action_ux
if (typeof data.properties.answer.metadata.action_ux !== "undefined"){
var action = data.properties.answer.metadata.action_ux.split("_");
responseObj["action_ux"] = {
context : action[0].toLowerCase().trim(),
id : action[1].toLowerCase().trim()
}
}
// action_speech
if (typeof data.properties.answer.metadata.action_speech !== "undefined"){
var action = data.properties.answer.metadata.action_speech.split("_");
responseObj["action_speech"] = {
context : action[0].toLowerCase().trim(),
id : action[1].toLowerCase().trim()
}
}
// action_speechfallback
if (typeof data.properties.answer.metadata.action_speechfallback !== "undefined"){
var intent = data.properties.answer.metadata.action_speechfallback;
responseObj["action_speechfallback"] = {
context : "",
id : intent
}
}
this.processSpeechPhrase(responseObj);
},
// ______________________________________________________________
// onPageLoad
/**
* onPageLoad
* @description Called when a page is loaded
* @param {String} eventId - Event ID
* @param {Object} data - Event data
* @memberOf module:managers/speech-manager
* @instance
*/
onPageLoad: function(eventId, data) {
var self = this;
var speechState;
if (this.firstLoad){
this.firstLoad = false;
// set initial speech state.
this.toggleSpeech("disable");
}
if (!window.oPrsonas.avatar.isSpeaking()) {
this.resetSpeech();
}
// check if we are at the starting page, if do enable forced mic but disable speech
if (this.jConfig.prsonas.timers.expiredEvent === eventId || this.jConfig.document.startEvent === eventId) {
this.onToggleMic(true);
this.toggleSpeech("disable");
} else {
for (let key in this.jConfig.proxySendkeyEvents) {
if ( (key === this.jConfig.prsonas.timers.expiredEvent || key === this.jConfig.document.startEvent) && this.jConfig.proxySendkeyEvents[key] === eventId){
this.onToggleMic(true);
this.toggleSpeech("disable");
}
}
}
}
};
/**
* @global
*/
window.oSpeech = new Speech();
return (window.oSpeech);
});