Adding 'IVA Wakeup' script used for Bot Tango example
This commit is contained in:
parent
f5d69bbc01
commit
22a9e9e77a
17
IVA-Wakeup/UI/After.js
Normal file
17
IVA-Wakeup/UI/After.js
Normal file
@ -0,0 +1,17 @@
|
||||
store.snippets.get('disabler').toggle(payload?.metadata?.outputs?.disableMessengerInput, payload?.metadata?.outputs?.messengerInputPlaceholder || 'Enter question here');
|
||||
console.log('disable?');
|
||||
console.log(payload?.metadata?.outputs?.disableMessengerInput);
|
||||
|
||||
if (payload?.metadata?.outputs?.hideMessenger == true) {
|
||||
store.main.hideMessenger();
|
||||
};
|
||||
|
||||
if (payload?.metadata?.outputs?.minimizeAfterFiveSeconds == true) {
|
||||
setTimeout(() => { store.main.isMessengerVisible = false }, 5000);
|
||||
};
|
||||
|
||||
if (payload?.metadata?.outputs?.disableMessengerInput === true) {
|
||||
store.main.disableMessengerInput();
|
||||
}
|
||||
|
||||
callback(payload);
|
||||
60
IVA-Wakeup/UI/Before.js
Normal file
60
IVA-Wakeup/UI/Before.js
Normal file
@ -0,0 +1,60 @@
|
||||
console.log("inside before addd");
|
||||
console.log(payload);
|
||||
let pramstudioConvoId = "";
|
||||
if (payload?.conversationId) {
|
||||
console.log('inside');
|
||||
console.log(payload?.conversationId);
|
||||
pramstudioConvoId = payload?.conversationId;
|
||||
}
|
||||
store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN") || (window.location.href.includes('ivastudio.ai') && window.location.href.includes('testAuth=1'));
|
||||
|
||||
payload.metadata = {
|
||||
channel: "WEB",
|
||||
companyName: "Lexington Law",
|
||||
companyWebsite: "lexingtonlaw.com",
|
||||
agentType: store.isAuthenticated ? "Paralegal" : "Credit Representative",
|
||||
callerType: "client",
|
||||
serviceType: "case",
|
||||
tenantName: "lexingtonLaw",
|
||||
location: window.location,
|
||||
isAuthenticated: store.isAuthenticated,
|
||||
isSaleCompleted: sessionStorage.getItem("signupComplete") || "", //Conversion tracking snippet, string
|
||||
//studioConvoId = pramstudioConvoId
|
||||
};
|
||||
|
||||
payload.metadata.studioConvoId = pramstudioConvoId;
|
||||
|
||||
try {
|
||||
const customerData = JSON.parse(sessionStorage.getItem("customerData") || "{}");
|
||||
const userDetails = JSON.parse(sessionStorage.getItem("userDetails") || "{}");
|
||||
const ucidSession = sessionStorage.getItem("ucid");
|
||||
|
||||
// --- UCID priority: userDetails > customerData > sessionStorage ---
|
||||
payload.metadata.ucid =
|
||||
userDetails?.ucid ??
|
||||
customerData?.ucid ??
|
||||
(ucidSession ? ucidSession.replace(/^"|"$/g, "") : undefined) ??
|
||||
payload.metadata.ucid;
|
||||
|
||||
// --- First pass: customerData ---
|
||||
payload.metadata.firstName = customerData?.firstName ?? payload.metadata.firstName;
|
||||
payload.metadata.lastName = customerData?.lastName ?? payload.metadata.lastName;
|
||||
payload.metadata.email = customerData?.email ?? payload.metadata.email;
|
||||
|
||||
// --- Second pass: userDetails (overrides customerData if present) ---
|
||||
payload.metadata.firstName = userDetails?.firstName ?? payload.metadata.firstName;
|
||||
payload.metadata.lastName = userDetails?.lastName ?? payload.metadata.lastName;
|
||||
payload.metadata.email = userDetails?.email ?? payload.metadata.email;
|
||||
|
||||
// --- ClientID only if authenticated ---
|
||||
if (store.isAuthenticated) {
|
||||
payload.metadata.clientID = userDetails?.clientID ?? payload.metadata.clientID;
|
||||
}
|
||||
|
||||
// const data1 = JSON.parse(sessionStorage.getItem("XSRF-TOKEN"));
|
||||
// payload.metadata.xsrf_token = data1;
|
||||
} catch (e) {
|
||||
//payload.metadata.isAuthenticated = false;
|
||||
}
|
||||
|
||||
callback(payload);
|
||||
685
IVA-Wakeup/UI/OnLoad.js
Normal file
685
IVA-Wakeup/UI/OnLoad.js
Normal file
@ -0,0 +1,685 @@
|
||||
// START TEMPLATING
|
||||
|
||||
window.store = store;
|
||||
|
||||
window.checkCookieExists = (cookieName) => {
|
||||
return document.cookie.includes(`${cookieName}=`);
|
||||
}
|
||||
|
||||
function isMobile() {
|
||||
return /Mobi|Android/i.test(navigator.userAgent);
|
||||
}
|
||||
|
||||
window.mobileRedirectionCheck = () => {
|
||||
if (isMobile()) {
|
||||
store.main.hideMessenger();
|
||||
}
|
||||
}
|
||||
|
||||
function renderTemplate(template, data) {
|
||||
// Replace variables like {{variable}} with their corresponding values in data
|
||||
template = template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => {
|
||||
return data[key] || '';
|
||||
});
|
||||
|
||||
// Handle v-if directives
|
||||
template = template.replace(/<(\w+)\s*v-if="([^"]+)"\s*>([\s\S]*?)<\/\1>/g, (_, tag, condition, truePart) => {
|
||||
// Evaluate the condition in the context of data
|
||||
const conditionValue = eval(condition.replace(/\b(\w+)\b/g, (match) => data[match] !== undefined ? data[match] : match)); // Replace variables with their values
|
||||
|
||||
if (conditionValue) {
|
||||
// If the condition is true, render the v-if block
|
||||
return `<${tag}>${truePart}</${tag}>`;
|
||||
}
|
||||
|
||||
return ''; // If the condition is false, render nothing
|
||||
});
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
// store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN");
|
||||
// allows user to test authentication if they add &testAuth=1 onto the end of the url and refresh
|
||||
store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN") || (window.location.href.includes('ivastudio.ai') && window.location.href.includes('testAuth=1'));
|
||||
|
||||
const template = `${payload.settings.newConversationPlaceholder.code.html}`;
|
||||
payload.settings.newConversationPlaceholder.code.html = renderTemplate(template, {
|
||||
isAuthenticated: store.isAuthenticated
|
||||
});
|
||||
store.main.setSettings(payload.settings);
|
||||
|
||||
(() => {
|
||||
let lastData = checkCookieExists("PGXREGSITE_LOGIN");
|
||||
setInterval(() => {
|
||||
let currentData = store.isAuthenticated = checkCookieExists("PGXREGSITE_LOGIN") || store.isAuthenticated;
|
||||
payload.settings.newConversationPlaceholder.code.html = renderTemplate(template, {
|
||||
isAuthenticated: store.isAuthenticated
|
||||
});
|
||||
if (store.isAuthenticated && !isLiveChat()) {
|
||||
// disable
|
||||
store.main.disableMessengerInput(); // 2-26-2025 commented out so Travis can test user inputs in Dev only
|
||||
}
|
||||
if (currentData !== lastData) {
|
||||
lastData = currentData;
|
||||
store.main.setSettings(payload.settings);
|
||||
store.conversation.$reset();
|
||||
store.conversationEvent.$reset();
|
||||
store.main.setView("main");
|
||||
}
|
||||
}, 1000);
|
||||
})();
|
||||
|
||||
// END TEMPLATING
|
||||
|
||||
//VERSION 1.1
|
||||
store.random = true;
|
||||
//console.log("payload", payload);
|
||||
const liveChatOnLaunch = payload.settings.chatOnlyMode == true;
|
||||
const closeBtns = payload.settings.desktopCloseBtn == true;
|
||||
if (closeBtns) {
|
||||
delete store.main.isCloseButtonVisible;
|
||||
payload.settings.desktopCloseBtn = false;
|
||||
}
|
||||
store.main.setSettings(payload.settings);
|
||||
|
||||
const getCloseSVG = () => {
|
||||
return `<svg fill="currentColor" height="12px" width="12px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 492" xml:space="preserve"><g><g><path d="M300.188,246L484.14,62.04c5.06-5.064,7.852-11.82,7.86-19.024c0-7.208-2.792-13.972-7.86-19.028L468.02,7.872 c-5.068-5.076-11.824-7.856-19.036-7.856c-7.2,0-13.956,2.78-19.024,7.856L246.008,191.82L62.048,7.872 c-5.06-5.076-11.82-7.856-19.028-7.856c-7.2,0-13.96,2.78-19.02,7.856L7.872,23.988c-10.496,10.496-10.496,27.568,0,38.052 L191.828,246L7.872,429.952c-5.064,5.072-7.852,11.828-7.852,19.032c0,7.204,2.788,13.96,7.852,19.028l16.124,16.116 c5.06,5.072,11.824,7.856,19.02,7.856c7.208,0,13.968-2.784,19.028-7.856l183.96-183.952l183.952,183.952 c5.068,5.072,11.824,7.856,19.024,7.856h0.008c7.204,0,13.96-2.784,19.028-7.856l16.12-16.116 c5.06-5.064,7.852-11.824,7.852-19.028c0-7.204-2.792-13.96-7.852-19.028L300.188,246z"/></g></g></svg>`;
|
||||
};
|
||||
const getMinimizeSVG = () => {
|
||||
return '<svg fill="currentColor" height="12px" width="12px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 492 492" xml:space="preserve"><g> <g><path d="M465.064,207.562H26.908C12.076,207.562,0,219.698,0,234.53v22.804c0,14.832,12.072,27.104,26.908,27.104h438.156 c14.84,0,26.936-12.272,26.936-27.104V234.53C492,219.698,479.904,207.562,465.064,207.562z"/></g></g></svg>';
|
||||
};
|
||||
const getCloseLiveChatSVG = () => {
|
||||
return `<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" width="32px" height="32px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve"><path d="M25.1,12.3v-3c4,0,7.2,3.2,7.2,7.2h-3l4.6,5.7c0.3,0.3,0.7,0.3,0.9,0l4.6-5.7h-3c0-6.3-5.2-11.4-11.4-11.4 v-3l-5.7,4.6C19,7,19.1,7.4,19.4,7.6L25.1,12.3z"/><path d="M26.3,33.6c-1.2-1.6-3.5-2.7-5.8-3.8c-2.4-1-2.7-2-2.7-3c0-1,0.6-2.1,1.4-2.8c1.3-1.3,2.1-3.2,2.1-5.3 c0-4-2.4-7.5-6.5-7.5h-0.4c-4.1,0-6.5,3.5-6.5,7.5c0,2.2,0.7,4,2.1,5.3c0.8,0.7,1.4,1.7,1.4,2.8c0,1-0.3,2-2.7,3 c-3.4,1.5-6.6,3.1-6.7,6.3C2.3,38.4,3.8,40,5.8,40h17.9c0.3,0,0.7-0.1,1-0.2C24.8,37.6,25.3,35.5,26.3,33.6z"/><path d="M31.8,34.6l6,6l-6,6c-0.6,0.6-0.6,1.6,0,2.1l0.7,0.7c0.6,0.6,1.6,0.6,2.1,0l6-6l6,6c0.6,0.6,1.6,0.6,2.1,0 l0.7-0.7c0.6-0.6,0.6-1.6,0-2.1l-6-6l6-6c0.6-0.6,0.6-1.6,0-2.1l-0.7-0.7c-0.6-0.6-1.6-0.6-2.1,0l-6,6l-6-6c-0.6-0.6-1.6-0.6-2.1,0 l-0.7,0.7C31.2,33,31.2,34,31.8,34.6z"/></svg>`;
|
||||
};
|
||||
|
||||
const addScript = (url, root, callback) => {
|
||||
const script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
script.src = url;
|
||||
script.onload = callback;
|
||||
root.appendChild(script);
|
||||
};
|
||||
|
||||
const addLink = (url, root) => {
|
||||
const link = document.createElement("link");
|
||||
link.type = "text/css";
|
||||
link.href = url;
|
||||
link.rel = "stylesheet";
|
||||
root.appendChild(link);
|
||||
};
|
||||
|
||||
const waitForElm = function (selector) {
|
||||
return new Promise((resolve) => {
|
||||
const root = document.querySelector("body ivas-messenger-ui").shadowRoot;
|
||||
if (root.querySelector(selector)) return resolve(root.querySelector(selector));
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (root.querySelector(selector)) {
|
||||
resolve(root.querySelector(selector));
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
observer.observe(root, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const injectStyle = () => {
|
||||
waitForElm("div.app").then((elem) => {
|
||||
elem.insertAdjacentHTML(
|
||||
"afterbegin",
|
||||
`<style>
|
||||
button#close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
z-index: 11111;
|
||||
color: #999
|
||||
}
|
||||
#close:hover {
|
||||
color: #666
|
||||
}
|
||||
button#minimize {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 40px;
|
||||
z-index: 11111;
|
||||
color: #999
|
||||
}
|
||||
#minimize:hover {
|
||||
color: #666
|
||||
}
|
||||
button#livechat {
|
||||
z-index: 11111;
|
||||
}
|
||||
button#debug {
|
||||
z-index: 11111;
|
||||
}
|
||||
.footer{
|
||||
justify-self:normal !important;
|
||||
}
|
||||
</style>`
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const sendLiveChatOnOff = (on) => {
|
||||
let input = on ? "Connecting to live chat" : "Live chat ended";
|
||||
if (on && !store.main.conversationId) {
|
||||
store.conversationEvent.sendMessage({
|
||||
input: input,
|
||||
metadata: { liveChat: on, nluSupressDefaultAnswer: true },
|
||||
});
|
||||
} else if (store.main.conversationId) {
|
||||
for (const webhook of payload.webhooks) {
|
||||
if (webhook.enabled) {
|
||||
axios({
|
||||
method: 'post',
|
||||
url: webhook.url,
|
||||
data: {
|
||||
event: {
|
||||
conversationId: store.main.conversationId,
|
||||
input,
|
||||
external: true,
|
||||
metadata: { liveChat: on }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const delayLiveChatOnOff = (on, msDelay) => {
|
||||
setTimeout(() => {
|
||||
console.log("livechat startup");
|
||||
sendLiveChatOnOff(on);
|
||||
}, msDelay);
|
||||
};
|
||||
|
||||
|
||||
let typingTimeout;
|
||||
const TYPING_DELAY_MS = 500;
|
||||
|
||||
const handleTyping = () => {
|
||||
clearTimeout(typingTimeout);
|
||||
|
||||
typingTimeout = setTimeout(() => {
|
||||
|
||||
console.log("TYPING");
|
||||
console.log("store.main.conversationId");
|
||||
console.log(store.main.conversationId);
|
||||
|
||||
try {
|
||||
fetch("https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/userTyping", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"event": "TYPING",
|
||||
"sessionId": store.main.conversationId
|
||||
}),
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.log("something errored when sending typing event");
|
||||
}
|
||||
}, TYPING_DELAY_MS);
|
||||
}
|
||||
|
||||
const showHideLiveChat = (livechat) => {
|
||||
const root = document.querySelector("body ivas-messenger-ui").shadowRoot;
|
||||
const el = root.getElementById("livechat");
|
||||
if (livechat === true) {
|
||||
waitForElm(".footer").then(() => {
|
||||
let textArea = root.querySelector(".footer textarea");
|
||||
textArea.addEventListener("input", handleTyping);
|
||||
});
|
||||
if (!el) {
|
||||
//store.main.enableMessengerInput();
|
||||
// COMMENTING OUT THE FOLLOWING LINES TO HIDE END LIVE CHAT BUTTON PER CREDITS REQUEST
|
||||
// waitForElm(".footer").then((el) => {
|
||||
// const div = document.createElement("button");
|
||||
// div.id = "livechat";
|
||||
// div.setAttribute("aria-label", "End Live Chat");
|
||||
// div.title = "End Live Chat";
|
||||
// div.style.color = payload.settings.actionColor;
|
||||
// div.innerHTML = getCloseLiveChatSVG();
|
||||
// div.style.paddingRight = "10px";
|
||||
// div.onclick = () => {
|
||||
// sendLiveChatOnOff(false);
|
||||
// if (store.isAuthenticated) {
|
||||
// store.main.disableMessengerInput();
|
||||
// }
|
||||
// store.conversationEvent.sendMessage("Live Chat Session ended. Can I help you with anything else?");
|
||||
// //Add a chip titled "Live Chat"
|
||||
// div.remove();
|
||||
// };
|
||||
// el.appendChild(div);
|
||||
// });
|
||||
}
|
||||
} else if (el) {
|
||||
// livechat == false
|
||||
el.remove();
|
||||
}
|
||||
};
|
||||
|
||||
const isLiveChat = () => {
|
||||
let livechat = false;
|
||||
for (const [id, participant] of Object.entries(store.conversationEvent.participants)) {
|
||||
if (participant.type == "agent") livechat = true;
|
||||
}
|
||||
return livechat;
|
||||
};
|
||||
|
||||
const debugButtons = (liveChatOn) => {
|
||||
waitForElm(".footer").then((el) => {
|
||||
const div = document.createElement("button");
|
||||
div.id = "debug";
|
||||
div.setAttribute("aria-label", "Start Live Chat");
|
||||
div.innerHTML = "Connect to live chat";
|
||||
div.title = "Connect to live chat";
|
||||
div.onclick = () => {
|
||||
store.conversationEvent.sendMessage({
|
||||
input: "Connect to live chat",
|
||||
metadata: { liveChat: true },
|
||||
});
|
||||
};
|
||||
el.parentNode.insertBefore(div, el.nextSibling);
|
||||
});
|
||||
};
|
||||
|
||||
// state variables: connecting to live chat automatically in the messenger visibility event has a sequencing problem. It will get called before axios is loaded and error out.
|
||||
// This delays the live chat connect until after axios is loaded.
|
||||
let isAxiosLoaded = false;
|
||||
let awaitingConnect = false;
|
||||
addScript("https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js", document.head, () => {
|
||||
if (awaitingConnect) {
|
||||
awaitingConnect = false;
|
||||
delayLiveChatOnOff(true, 1500);
|
||||
}
|
||||
isAxiosLoaded = true;
|
||||
});
|
||||
|
||||
window.addEventListener("beforeunload", (event) => {
|
||||
// doesn't work
|
||||
if (liveChatOnLaunch && isLiveChat()) {
|
||||
sendLiveChatOnOff(false);
|
||||
}
|
||||
});
|
||||
|
||||
// update the state of livechat based on the participants. If there is an "agent" participant type, it's a live chat.
|
||||
vm.$watch(
|
||||
() => store.conversationEvent.participants,
|
||||
async (participants) => {
|
||||
try {
|
||||
showHideLiveChat(isLiveChat());
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
vm.$watch(
|
||||
() => store.main.isMessengerVisible,
|
||||
async (isVisible) => {
|
||||
try {
|
||||
console.log("messenger visible =", isVisible, store.main.conversationId);
|
||||
if (isVisible == true) {
|
||||
const livechat = isLiveChat();
|
||||
injectStyle();
|
||||
showHideLiveChat(livechat);
|
||||
//debugButtons(livechat);
|
||||
if (closeBtns) {
|
||||
waitForElm(".app").then((el) => {
|
||||
const div = document.createElement("button");
|
||||
div.id = "minimize";
|
||||
div.title = "Minimize";
|
||||
div.innerHTML = getMinimizeSVG();
|
||||
div.onclick = () => {
|
||||
store.main.hideMessenger();
|
||||
};
|
||||
el.appendChild(div);
|
||||
});
|
||||
waitForElm(".app").then((el) => {
|
||||
const div = document.createElement("button");
|
||||
div.id = "close";
|
||||
div.title = "Close";
|
||||
div.innerHTML = getCloseSVG();
|
||||
div.onclick = () => {
|
||||
//Added the following line and commented out the proceeding if statement at credit's request in order to ONLY minimize the UI when in live chat instead of closing the session
|
||||
store.main.hideMessenger();
|
||||
// if (!isLiveChat() || window.confirm("Live Chat is running. Are you sure you want to close?")) {
|
||||
// store.main.hideMessenger();
|
||||
// if (isLiveChat()) {
|
||||
// sendLiveChatOnOff(false);
|
||||
// }
|
||||
// //store.main.setNewUserSession();
|
||||
// store.conversation.$reset();
|
||||
// store.conversationEvent.$reset();
|
||||
// store.main.setView("chat");
|
||||
// store.main.setNewConversation(true);
|
||||
// }
|
||||
};
|
||||
el.appendChild(div);
|
||||
});
|
||||
}
|
||||
if (liveChatOnLaunch) {
|
||||
if (!livechat) {
|
||||
if (isAxiosLoaded === true) {
|
||||
delayLiveChatOnOff(true, 1500);
|
||||
} else {
|
||||
awaitingConnect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
window.vm = vm;
|
||||
window.store = store;
|
||||
|
||||
addScript("https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/adaptiveCardImplementation_64dbc87628bd839f69b0c962", document.head, () => {
|
||||
// Uncomment the following line to load the optional host config script
|
||||
// addScript('https://router.usw.ivastudio.ai/ProxyScript/run/66ce521b47ec88c50fb8adf4/current/adaptiveCardHostConfig_64dbc87628bd839f69b0c962', document.head);
|
||||
});
|
||||
|
||||
//supplemental code for feedback functionality including waitForElm lines
|
||||
|
||||
// const waitForElm = function (selector) {
|
||||
// return new Promise((resolve) => {
|
||||
// const root = document.querySelector('body ivas-messenger-ui').shadowRoot;
|
||||
// if (root.querySelector(selector)) return resolve(root.querySelector(selector));
|
||||
// const observer = new MutationObserver((mutations) => {
|
||||
// if (root.querySelector(selector)) {
|
||||
// resolve(root.querySelector(selector));
|
||||
// observer.disconnect();
|
||||
// }
|
||||
// });
|
||||
// observer.observe(root, {
|
||||
// childList: true,
|
||||
// subtree: true
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
//END GENERAL ON ENGAGEMENT LOAD CODE
|
||||
|
||||
//BEGIN FEEDBACK SPECIFIC CODE
|
||||
|
||||
vm.$watch(() => store.conversationEvent.messages, async (value) => {
|
||||
value.forEach((message, index) => {
|
||||
if (message.sentBy.hasOwnProperty('type')) {
|
||||
if (localStorage.getItem(`feedback-${message._id}`) || message?.metadata?.feedbackable != true) {
|
||||
} else {
|
||||
window.showFeedback(message._id, message.conversationId, message?.metadata?.transactionId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, {
|
||||
deep: true
|
||||
});
|
||||
|
||||
window.showFeedback = (id, conversationId, transactionId) => {
|
||||
waitForElm(`div#message-${id}`).then((wrap) => {
|
||||
try {
|
||||
// const wrap = document.querySelector("body > se-messenger").shadowRoot.querySelector("#se-messenger-app > div.se-messenger-frame > div > div.se-messenger-body > div");
|
||||
const scrollToTop = () => {
|
||||
wrap.scrollTop = wrap.scrollHeight;
|
||||
};
|
||||
let devWrap = wrap.querySelector(`div.feedback-wrap`);
|
||||
if (!devWrap) {
|
||||
devWrap = document.createElement('div');
|
||||
devWrap.classList.add('feedback-wrap');
|
||||
devWrap.innerHTML = `<div class="feedback" style="top: -10px; right: -20px; display: flex; flex-flow: row nowrap; padding-left: 35px; padding: 5px 0 5px 35px;"><a id="se-messenger-feedback-like-${id}" href="#" style=" display: block; padding: 5px;">👍</a><a id="se-messenger-feedback-dislike-${id}" href="#" style=" display: block; padding: 5px;">👎</a></div>`;
|
||||
wrap.parentElement.querySelector(`div#message-${id} > div`).after(devWrap);
|
||||
}
|
||||
devWrap.querySelector(`a#se-messenger-feedback-like-${id}`).onclick = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("like!");
|
||||
devWrap.parentElement.removeChild(devWrap);
|
||||
send("LIKE");
|
||||
}
|
||||
devWrap.querySelector(`a#se-messenger-feedback-dislike-${id}`).onclick = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("dislike!");
|
||||
devWrap.parentElement.removeChild(devWrap);
|
||||
send("DISLIKE");
|
||||
}
|
||||
wrap.parentElement.parentElement.parentElement.scrollTop =
|
||||
wrap.parentElement.parentElement.parentElement.scrollHeight;
|
||||
const send = (event) => {
|
||||
localStorage.setItem(`feedback-${id}`, true);
|
||||
|
||||
//update DQ_URL with the URL of the LTS version of your feedback query
|
||||
fetch('https://router.usw.ivastudio.ai/DynamicQuery/run/66ce521b47ec88c50fb8adf4/current/Feedback_6529ac38d8f54e4b61bc0a99', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"event": event,
|
||||
"_id": transactionId
|
||||
}),
|
||||
});
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
//END FEEDBACK CODE
|
||||
|
||||
//Watcher to keep IVA Open When in LIVE CHAT
|
||||
vm.$watch(() => store.conversationEvent.messages, async (value) => {
|
||||
try {
|
||||
console.log("Msg received");
|
||||
const livechat = isLiveChat();
|
||||
if (livechat) {
|
||||
if (!store.main.isMessengerVisible) {
|
||||
store.main.showMessenger();
|
||||
}
|
||||
}
|
||||
console.log(livechat);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}, {
|
||||
deep: true
|
||||
});
|
||||
|
||||
window.askIVA =
|
||||
window.askSky =
|
||||
window.askSkyWithData =
|
||||
(input, postBack, configuration, isNew) => {
|
||||
store.main.showMessenger();
|
||||
if (isNew) {
|
||||
store.conversation.$reset();
|
||||
store.conversationEvent.$reset();
|
||||
store.main.setView("chat");
|
||||
store.main.setNewConversation(true);
|
||||
} else {
|
||||
store.main.setView("chat");
|
||||
}
|
||||
store.conversationEvent.sendMessage({
|
||||
input,
|
||||
postBack,
|
||||
configuration
|
||||
});
|
||||
};
|
||||
|
||||
window.openChat = () => {
|
||||
store.main.showMessenger();
|
||||
// start new
|
||||
store.conversation.$reset();
|
||||
store.conversationEvent.$reset();
|
||||
// start new
|
||||
store.main.setView("chat");
|
||||
// start new
|
||||
store.main.setNewConversation(true);
|
||||
};
|
||||
|
||||
window.closeChat = () => {
|
||||
store.main.hideMessenger();
|
||||
};
|
||||
|
||||
//BEGIN MASKING
|
||||
const debounce = (func, timeout = 300) => {
|
||||
let timer;
|
||||
return (...args) => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => { func.apply(this, args); }, timeout);
|
||||
};
|
||||
};
|
||||
|
||||
const de = debounce((value) => {
|
||||
value.forEach((message, index) => {
|
||||
if (message.sentBy.hasOwnProperty('type')) {
|
||||
if (localStorage.getItem(`feedback-${message._id}`) || message?.metadata?.feedbackable != true) {
|
||||
} else {
|
||||
window.showFeedback(message._id, message.conversationId, message?.metadata?.transactionId);
|
||||
}
|
||||
} else {
|
||||
if (message.input) {
|
||||
let matchRes = window.isMask(message.input);
|
||||
if (matchRes.includes("####") || matchRes.includes("#%*!")) {
|
||||
message.input = matchRes;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
vm.$watch(() => store.conversationEvent.messages, de, {
|
||||
deep: true
|
||||
});
|
||||
|
||||
// sendMessage(input, metadata, conversationId) {
|
||||
// try {
|
||||
// debugLogging(`Sending message ${input} and metadata: ${JSON.stringify(metadata)}`);
|
||||
|
||||
// window.liveChat.sendLiveChatMessage(input);
|
||||
|
||||
// const proxyEndpoint = `${store.main.settings.liveChat.apiBaseUrl}/recordUserMessage`;
|
||||
// const id = window.liveChat.convoId;
|
||||
// input = window.isMask(input);
|
||||
// }
|
||||
// }//abbreviated
|
||||
|
||||
// #region Masking
|
||||
window.isMask = (message) => {
|
||||
const ssnRegex = /\b(\d{3}[-. ]?\d{2}[-. ]?\d{4}|\d{2}[-. ]\d{4}|\d{9}|\d{3}-\d{2}-\d{4})\b/g;
|
||||
const ssnRegex2 = /\b(\d{2}(.)\d{4}|\d{3}([- .])\d{3}\3\d{3})\b/g;
|
||||
const ccRegex = /\b(\d{4}[-. ]?\d{6}[-. ]?\d{4,5}|\d{4}[-. ]?\d{4}[-. ]?\d{4}[-. ]?\d{4})\b/g;
|
||||
const acctNoRegex = /\b(\d{4}[-.\s]?\d{4}[-.\s]?\d{4}[-.\s]?\d{4})\b/g;
|
||||
const emailRegex = /\b[a-z0-9._%\+\-—|]+@[a-z0-9.\-—|]+\.[a-z|]{2,6}\b/g;
|
||||
const birthDateRegex = /\b^(3[01]|[12][0-9]|0?[1-9])(\/|-)(1[0-2]|0?[1-9])\2([0-9]{2})?[0-9]{2}$\b/g;
|
||||
const phoneNumberRegex = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$\b/g;
|
||||
|
||||
let regexArr = [];
|
||||
//regexArr.push(acctNoRegex);
|
||||
regexArr.push(ccRegex);
|
||||
regexArr.push(ssnRegex);
|
||||
regexArr.push(ssnRegex2);
|
||||
//regexArr.push(emailRegex);
|
||||
//regexArr.push(birthDateRegex);
|
||||
//regexArr.push(phoneNumberRegex);
|
||||
|
||||
regexArr.forEach((element) => {
|
||||
message = message.replace(element, "####");
|
||||
})
|
||||
|
||||
let badWords = [
|
||||
"anal",
|
||||
"anus",
|
||||
"arse",
|
||||
"ass",
|
||||
"ballsack",
|
||||
"bastard",
|
||||
"bitch",
|
||||
"biatch",
|
||||
"blowjob",
|
||||
"bollock",
|
||||
"bollok",
|
||||
"buttplug",
|
||||
"clitoris",
|
||||
"cock",
|
||||
"coon",
|
||||
"cunt",
|
||||
"damn",
|
||||
"dick",
|
||||
"Dildo",
|
||||
"dyke",
|
||||
"fag",
|
||||
"faggot",
|
||||
"feck",
|
||||
"fellate",
|
||||
"fellatio",
|
||||
"fuck",
|
||||
"fucking",
|
||||
"fucks",
|
||||
"f u c k",
|
||||
"Goddamn",
|
||||
"God damn",
|
||||
"hell",
|
||||
"homo",
|
||||
"jerk",
|
||||
"jizz",
|
||||
"knobend",
|
||||
"knob end",
|
||||
"labia",
|
||||
"lmao",
|
||||
"lmfao",
|
||||
"nigger",
|
||||
"nigga",
|
||||
"prick",
|
||||
"pube",
|
||||
"pussy",
|
||||
"queer",
|
||||
"retard",
|
||||
"sex",
|
||||
"bullshit",
|
||||
"shit",
|
||||
"slut",
|
||||
"tit",
|
||||
"turd",
|
||||
"twat",
|
||||
"whore",
|
||||
"wtf"
|
||||
];
|
||||
|
||||
const regexbadWords = new RegExp(`\\b(?:${badWords.join('|')})\\b`, 'gi');
|
||||
message = message.replace(regexbadWords, '#%*!');
|
||||
return message;
|
||||
};
|
||||
|
||||
//END Masking
|
||||
|
||||
// #region Response Link Click Handling
|
||||
store.conversationEvent.chipOnClick = (data) => {
|
||||
console.log(JSON.stringify(data));
|
||||
if (data.url) {
|
||||
window.open(data.url, '_blank');
|
||||
} else if (data.action) {
|
||||
switch (data.action) {
|
||||
case "hideMessenger":
|
||||
console.log('Got to hide messenger');
|
||||
store.main.hideMessenger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
store.conversationEvent.sendMessage(data);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
68
IVA-Wakeup/global/gvf_ConversationHistory.js
Normal file
68
IVA-Wakeup/global/gvf_ConversationHistory.js
Normal file
@ -0,0 +1,68 @@
|
||||
return {
|
||||
async fetchConversationHistory(conversationId, limit) {
|
||||
|
||||
let datahistory = await db.collection("analytics_transactions").aggregate([
|
||||
{
|
||||
$match: {
|
||||
$and: [
|
||||
{ "conversationId": conversationId },
|
||||
{ "outputs.datacollect": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
]).toArray();
|
||||
|
||||
console.log('10 line');
|
||||
let lastElement = datahistory[datahistory.length - 1];
|
||||
console.log(lastElement?.metadata?.actionType);
|
||||
let messages = [];
|
||||
const tx_msg = (direction, text, sentTime) => {
|
||||
return {
|
||||
conversationId: conversationId,
|
||||
direction,
|
||||
text,
|
||||
dateSent: new Date(sentTime).toISOString(),
|
||||
};
|
||||
};
|
||||
let counts = { agent: 0, ivas: 0 };
|
||||
let agentName;
|
||||
let is_async = null;
|
||||
for (let msg of datahistory) {
|
||||
if (msg?.answers.length) {
|
||||
if (msg?.input !== "") {
|
||||
messages.push(tx_msg("ToAgent", msg?.input, (msg?.metadata?.createdAt ?? Date.now())));
|
||||
}
|
||||
counts.ivas++;
|
||||
for (let i = 0; i < msg?.answers.length; i++) {
|
||||
let answer = msg.answers[i];
|
||||
if (typeof answer !== "string") {
|
||||
answer = JSON.stringify(answer ?? null);
|
||||
}
|
||||
messages.push(tx_msg("ToCustomer", answer, (msg?.metadata?.createdAt ?? Date.now()) + 50 + i));
|
||||
counts.ivas++;
|
||||
}
|
||||
}
|
||||
if (limit > 0 && messages.length >= limit) break;
|
||||
}
|
||||
|
||||
const summary = {
|
||||
conversationId: conversationId,
|
||||
steps: []
|
||||
};
|
||||
|
||||
|
||||
messages.forEach(msg => {
|
||||
summary.steps.push({
|
||||
who: msg.direction === "ToAgent" ? "Customer" : "System",
|
||||
text: msg.text,
|
||||
time: new Date(msg.dateSent).toLocaleString()
|
||||
});
|
||||
});
|
||||
let history = ``;
|
||||
summary.steps.forEach((step, index) => {
|
||||
history += `<strong>${step.who}:</strong> ${step.text}<br/>`;
|
||||
});
|
||||
history+= `<strong>ActionType:</strong> ${lastElement?.metadata?.actionType}`
|
||||
return history;
|
||||
}
|
||||
};
|
||||
39
IVA-Wakeup/global/gvf_handleIVAWakeupEvent.js
Normal file
39
IVA-Wakeup/global/gvf_handleIVAWakeupEvent.js
Normal file
@ -0,0 +1,39 @@
|
||||
return {
|
||||
async handleIVAWakeupEvent(event, req, session, settings, redis, smStr, channel, eventPayload) {
|
||||
try {
|
||||
const ivaWakeupText = `<p><br data-mce-bogus="1"></p><p><br data-mce-bogus="1"></p><p>IVA-Wakeup</p>`;
|
||||
|
||||
if (event.text === ivaWakeupText) {
|
||||
const nluSettings = settings.nlu;
|
||||
|
||||
const result = await axios.post(
|
||||
`${nluSettings.apiBaseURL}Model/run/${req.params.workspaceId}/${req.params.branch}/${nluSettings.modelName}`,
|
||||
{
|
||||
input: "CaseSetup",
|
||||
conversationId: session.conversationId,
|
||||
settings: nluSettings.settings,
|
||||
sessionId: event.sessionId
|
||||
}
|
||||
);
|
||||
|
||||
eventPayload.options = result?.data?.options;
|
||||
eventPayload.metadata = {
|
||||
outputs: result.data?.outputs,
|
||||
channel: channel
|
||||
};
|
||||
eventPayload.input = result.data.answers[0];
|
||||
eventPayload.metadata.outputs.disableMessengerInput = true;
|
||||
eventPayload.metadata.outputs.datacollect = true;
|
||||
|
||||
await redis.hSet(smStr, {
|
||||
formFlow: "true",
|
||||
datacollect: "true",
|
||||
sentdata: "false"
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.info("Error with IVA-Wakeup");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
420
IVA-Wakeup/proxy/CAInterface_Chat.js
Normal file
420
IVA-Wakeup/proxy/CAInterface_Chat.js
Normal file
@ -0,0 +1,420 @@
|
||||
console.info("===== Live Chat Proxy Entry - v16.3 =====");
|
||||
|
||||
const casettings = CAInterface_settings;
|
||||
const CA = CAInterface();
|
||||
const msgrSettings = eval(`settings${casettings.hubSuffixMessenger}`);
|
||||
let nlu = msgrSettings?.nlu;
|
||||
|
||||
const _SELF = `${nlu.apiBaseURL}ProxyScript/run/${req.params.workspaceId}/${req.params.branch}/CAInterface_chat${casettings.hubSuffix}`;
|
||||
|
||||
// API Specific
|
||||
const headers = {
|
||||
Authorization: `Basic ${buffer.Buffer.from(casettings.token.basicAuth).toString("base64")}`,
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
};
|
||||
|
||||
const studioToken = msgrSettings ? { Authorization: `Bearer ${msgrSettings.messenger.token}` } : {};
|
||||
|
||||
console.info({
|
||||
"Express Request": {
|
||||
body: req.body,
|
||||
},
|
||||
});
|
||||
|
||||
const agentAltId = "G3YxOTO1LO_1NlJXEIfk";
|
||||
|
||||
// gather fields from request body
|
||||
const { conversationId, event, input, location, logged, options, queryParams, request, transcript } = req.body || {};
|
||||
|
||||
const channel = req?.body?.event?.metadata?.channel ?? req?.body?.channel ?? "web";
|
||||
const metadata = req.body.event?.metadata;
|
||||
|
||||
const connectedWithAgent = (session) => session?.liveChatRequest && session?.agent?.userId;
|
||||
|
||||
const loopScale = 3;
|
||||
const smStr = `session-map-${conversationId}`;
|
||||
|
||||
(async () => {
|
||||
const session = await redis.hGetAll(smStr);
|
||||
|
||||
// parse session from string to object
|
||||
Object.keys(session).forEach((key) => {
|
||||
try {
|
||||
session[key] = JSON.parse(session[key]);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
const elapsed = (Date.now() - session?.lastActivity) / 1000;
|
||||
const qelapsed = (Date.now() - session?.lastQueueStatus) / 1000;
|
||||
|
||||
console.info(`Time since last user activity: ${elapsed}s`);
|
||||
session.warned ||= false;
|
||||
|
||||
if (!session?.discoveryUrls) {
|
||||
const { urls } = await CA.restUrls();
|
||||
session.discoveryUrls = urls;
|
||||
|
||||
await redis.hSet(smStr, {
|
||||
discoveryUrls: JSON.stringify(urls),
|
||||
});
|
||||
}
|
||||
|
||||
if (event != "FETCH") {
|
||||
console.info({ Session: session });
|
||||
}
|
||||
|
||||
const delayCallFetch = async (delay) => {
|
||||
const id = uuidv4();
|
||||
await redis.hSet(smStr, { fetchid: id });
|
||||
|
||||
let numSeconds = typeof delay === "number" ? delay : loopScale;
|
||||
|
||||
setTimeout(async (smStr, id) => {
|
||||
const session = await redis.hGetAll(smStr);
|
||||
if (session.fetchid == id) {
|
||||
axios({
|
||||
method: "post",
|
||||
url: _SELF,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: { channel, conversationId, event: "FETCH" },
|
||||
});
|
||||
} else {
|
||||
console.info("Fetch: loop stopped (old id)");
|
||||
}
|
||||
}, 1000 * numSeconds, smStr, id);
|
||||
};
|
||||
|
||||
switch (event) {
|
||||
case "JOIN": {
|
||||
console.info("Joining live chat session");
|
||||
const chatRequestDefaults = {
|
||||
customerFirstName: "",
|
||||
customerLastName: "",
|
||||
customerEmail: "",
|
||||
chatLaunchMode: "CHAT_ONLY",
|
||||
refererURL: "example.com",
|
||||
launchIdentifier: casettings.liveChat.launchIdentifier,
|
||||
launchCode: "TextChatCustomerDataED",
|
||||
transcript,
|
||||
};
|
||||
|
||||
const customFieldsDefaults = { company: "Verint" };
|
||||
const chatRequest = { ...chatRequestDefaults, ...(request ?? {}) };
|
||||
chatRequest.customFields = { ...customFieldsDefaults, ...(request?.customFields ?? {}) };
|
||||
|
||||
const data = await CA.axios(`Posting data to "${session.discoveryUrls.client}"`, {
|
||||
method: "post",
|
||||
url: session.discoveryUrls.client,
|
||||
headers,
|
||||
data: chatRequest,
|
||||
});
|
||||
|
||||
// Clean up _links
|
||||
const links = {};
|
||||
Object.keys(data._links).forEach((key) => {
|
||||
links[key] = data._links[key].href;
|
||||
});
|
||||
data._links = links;
|
||||
|
||||
console.info(data);
|
||||
|
||||
await redis.hSet(smStr, {
|
||||
liveChatRequest: "true",
|
||||
chatDetails: JSON.stringify(data),
|
||||
lastActivity: JSON.stringify(Date.now()),
|
||||
lastQueueStatus: JSON.stringify(Date.now()),
|
||||
});
|
||||
|
||||
const queueStatus = await CA.axios(`Getting queue status from "${data._links.queuedstatus}"`,
|
||||
{ method: "get", url: data._links.queuedstatus, headers },
|
||||
async () => {
|
||||
await CA.postEvent(channel, conversationId, { input: casettings.liveChat.queueDisconnectMessage });
|
||||
}
|
||||
);
|
||||
|
||||
if (queueStatus.message) {
|
||||
await CA.postEvent(channel, conversationId, { input: queueStatus.message });
|
||||
}
|
||||
|
||||
delayCallFetch();
|
||||
break;
|
||||
}
|
||||
|
||||
case "LEAVE": {
|
||||
console.info("Leaving live chat session");
|
||||
try {
|
||||
const { data } = await axios({
|
||||
method: "post",
|
||||
url: session.chatDetails._links.logout,
|
||||
headers,
|
||||
});
|
||||
console.info({ "Logout Response": data });
|
||||
|
||||
if (connectedWithAgent(session)) {
|
||||
await CA.postConversationLeave(
|
||||
channel,
|
||||
conversationId,
|
||||
session.agent.userId || casettings.liveChat.participantId || agentAltId,
|
||||
"liveChatEnded"
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
console.info("reset session map");
|
||||
await redis.hSet(smStr, { liveChatRequest: "false", agent: "{}" });
|
||||
break;
|
||||
}
|
||||
|
||||
case "FETCH": {
|
||||
const State = { waiting: 0, leaving: 1, offline: 2 };
|
||||
let state = State.waiting;
|
||||
|
||||
if (session.liveChatRequest == false) {
|
||||
console.info("Live Chat is off");
|
||||
state = State.offline;
|
||||
} else if (session && session.chatDetails) {
|
||||
// queue status check
|
||||
if (!connectedWithAgent(session) && qelapsed > 30) {
|
||||
const queueStatus = await CA.axios(
|
||||
`Getting queue status from "${session.chatDetails._links.queuedstatus}"`,
|
||||
{ method: "get", url: session.chatDetails._links.queuedstatus, headers },
|
||||
async () => {
|
||||
await CA.postEvent(channel, conversationId, { input: casettings.liveChat.queueDisconnectMessage });
|
||||
}
|
||||
);
|
||||
|
||||
if (queueStatus.message && queueStatus.message != session.lastQueueMessage) {
|
||||
await CA.postEvent(channel, conversationId, { input: queueStatus.message });
|
||||
await redis.hSet(smStr, {
|
||||
lastQueueStatus: JSON.stringify(Date.now()),
|
||||
lastQueueMessage: queueStatus.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const data = await CA.axios(
|
||||
`Getting Events from "${session.chatDetails._links.event}"`,
|
||||
{ method: "get", url: session.chatDetails._links.event, headers }
|
||||
);
|
||||
|
||||
data.events = data.events.map((event) => JSON.parse(event));
|
||||
|
||||
if (data.events.length > 0) console.info(data.events);
|
||||
|
||||
const sagent = session.agent || {};
|
||||
const au_default = {
|
||||
userId: casettings.liveChat.participantId || agentAltId,
|
||||
avatar: casettings.liveChat.avatar,
|
||||
type: "agent",
|
||||
};
|
||||
let agent_user = { ...au_default, ...sagent };
|
||||
|
||||
for (const event of data.events) {
|
||||
const agentUser = { ...agent_user, name: event.userDisplayName };
|
||||
|
||||
if (event.userType === "GUEST") {
|
||||
console.info(event);
|
||||
switch (event.type) {
|
||||
case "MessageReceived": {
|
||||
console.info(`Guest said "${event.text}"`);
|
||||
await CA.postEvent(channel, conversationId, {
|
||||
conversationId,
|
||||
input: event.text,
|
||||
sentBy: agentUser,
|
||||
ping: nanoid(),
|
||||
sentAt: Date.now(),
|
||||
});
|
||||
CA.addTransaction(session.conversationId, event.text,
|
||||
{ type: "agent", name: event.userDisplayName, userId: event.userId },
|
||||
{ liveChat: true }
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (event.userType === "AGENT") {
|
||||
console.info(event);
|
||||
switch (event.type) {
|
||||
case "UserTyping":
|
||||
await CA.postTyping(channel, conversationId);
|
||||
break;
|
||||
|
||||
case "AttachmentMessageReceived": {
|
||||
let url = `${casettings.liveChat.attachment.endpoint}/ProxyScript/run/${req.params.workspaceId}/${req.params.branch}/CA_attachments${casettings.hubSuffix}`;
|
||||
url += `?url=${encodeURIComponent(event.url)}&sessionId=${event.sessionId}&fileName=${encodeURIComponent(event.fileName)}`;
|
||||
const response = await CA.downloadFile(event.url, event.sessionId);
|
||||
|
||||
if (CA.channelIsExternal(channel) && response.headers['content-type']) {
|
||||
const attachment = { url, mimeType: response.headers['content-type'], fileName: event.fileName };
|
||||
CA.postEvent(channel, conversationId, { metadata: { channel, attachments: [attachment] } });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "MessageReceived": {
|
||||
console.info(`Agent ${event.userDisplayName} said "${event.text}"`);
|
||||
agent_user.name = event.userDisplayName;
|
||||
|
||||
let eventPayload = {
|
||||
conversationId,
|
||||
input: event.text,
|
||||
sentBy: agentUser,
|
||||
ping: nanoid(),
|
||||
sentAt: Date.now(),
|
||||
};
|
||||
|
||||
if (data.events.some((x) => x.type == "UserExited")) {
|
||||
console.info("Setting liveChat to false");
|
||||
eventPayload.metadata = { outputs: { liveChat: false } };
|
||||
}
|
||||
|
||||
await gvf_handleIVAWakeupEvent().handleIVAWakeupEvent(
|
||||
event, req, session, settings_66a1322d44405adda4fe9f53, redis, smStr, channel, eventPayload
|
||||
);
|
||||
|
||||
if (session.formFlow !== true) {
|
||||
await CA.postEvent(channel, conversationId, eventPayload);
|
||||
}
|
||||
|
||||
CA.addTransaction(
|
||||
session.conversationId,
|
||||
event.text,
|
||||
{ type: "agent", name: event.userDisplayName, userId: event.userID },
|
||||
eventPayload?.metadata?.outputs || { liveChat: true }
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "UserEntered":
|
||||
console.info(`Agent ${event.userDisplayName} joined`);
|
||||
agent_user.name = event.userDisplayName;
|
||||
await redis.hSet(smStr, { agent: JSON.stringify(agent_user) });
|
||||
await CA.postConversationJoin(channel, conversationId, agent_user);
|
||||
await CA.postEvent(channel, conversationId, {
|
||||
conversationId,
|
||||
input: `You are now connected with ${event.userDisplayName}`,
|
||||
sentBy: { ...agentUser, type: "host" },
|
||||
ping: nanoid(),
|
||||
sentAt: Date.now(),
|
||||
});
|
||||
break;
|
||||
|
||||
case "UserExited":
|
||||
state = State.leaving;
|
||||
console.info(`Agent ${event.userDisplayName} left`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.info("Session does not exist!");
|
||||
break;
|
||||
}
|
||||
|
||||
// State handling
|
||||
switch (state) {
|
||||
case State.waiting: {
|
||||
const idle = casettings.liveChat.idle;
|
||||
|
||||
if (elapsed > idle.disconnect.seconds && session.warned) {
|
||||
CA.addTransaction(session.conversationId, "Live Chat Timeout", { type: "host" }, { liveChat: false });
|
||||
await CA.postEvent(channel, conversationId, { input: idle.disconnect.message });
|
||||
state = State.leaving;
|
||||
|
||||
await axios({
|
||||
method: "post",
|
||||
url: _SELF,
|
||||
headers: studioToken,
|
||||
data: { channel, conversationId, event: "LEAVE", session },
|
||||
});
|
||||
break;
|
||||
} else if (elapsed > idle.warning.seconds && !session.warned) {
|
||||
await CA.postEvent(channel, conversationId, { input: idle.warning.message });
|
||||
await redis.hSet(smStr, { warned: "true" });
|
||||
}
|
||||
|
||||
delayCallFetch();
|
||||
break;
|
||||
}
|
||||
|
||||
case State.leaving:
|
||||
console.info("Leaving session");
|
||||
await axios({
|
||||
method: "post",
|
||||
url: _SELF,
|
||||
headers: studioToken,
|
||||
data: { channel, conversationId, event: "LEAVE", session },
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
state = State.offline;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
console.info("Live chat ongoing");
|
||||
|
||||
if (input && session && session.chatDetails) {
|
||||
console.info(session.chatDetails);
|
||||
console.info(`Sending "${input}" to live chat`);
|
||||
|
||||
await axios({
|
||||
method: "post",
|
||||
url: session.chatDetails._links.event,
|
||||
headers,
|
||||
data: [{ type: "MessageSent", text: input }],
|
||||
});
|
||||
|
||||
await redis.hSet(smStr, {
|
||||
lastActivity: JSON.stringify(Date.now()),
|
||||
warned: "false",
|
||||
lastQueueMessage: "",
|
||||
lastQueueStatus: 0,
|
||||
});
|
||||
|
||||
delayCallFetch();
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
.catch(async (error) => {
|
||||
console.error(`Caught error: ${error}`);
|
||||
if (error.response) console.error(`Caught error: ${error.response.data}`);
|
||||
|
||||
const session = await redis.hGetAll(smStr);
|
||||
|
||||
if (session) {
|
||||
await redis.hSet(smStr, { liveChatRequest: "false", agent: "{}" });
|
||||
|
||||
if (session && session.agent && session.chatDetails) {
|
||||
session.agent = JSON.parse(session.agent);
|
||||
session.chatDetails = JSON.parse(session.chatDetails);
|
||||
|
||||
if (connectedWithAgent(session)) {
|
||||
CA.postConversationLeave(
|
||||
channel,
|
||||
conversationId,
|
||||
session.agent.userId || casettings.liveChat.participantId || agentAltId,
|
||||
"AgentExited"
|
||||
);
|
||||
}
|
||||
|
||||
axios({ method: "post", url: session.chatDetails._links.logout, headers });
|
||||
}
|
||||
}
|
||||
|
||||
if (conversationId && session.conversationId) {
|
||||
CA.addTransaction(session.conversationId, "Live Chat Error", { type: "host" }, { liveChat: false });
|
||||
await CA.postEvent(channel, conversationId, {
|
||||
input: "There was a connection issue with the Live Chat, and you were disconnected.",
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
res.send(200);
|
||||
});
|
||||
132
IVA-Wakeup/proxy/CAInterface_Messenger.js
Normal file
132
IVA-Wakeup/proxy/CAInterface_Messenger.js
Normal file
@ -0,0 +1,132 @@
|
||||
console.log("===== Main Messenger Proxy - v17.9 =====");
|
||||
const casettings = CAInterface_settings;
|
||||
console.log(req);
|
||||
const external = req.body.event?.external;
|
||||
const sessionId = req.body.event?.conversationId;
|
||||
const metadata = req.body.event?.metadata;
|
||||
const msgrSettings = eval(`settings${casettings.hubSuffixMessenger}`);
|
||||
let nlu = msgrSettings?.nlu;
|
||||
if (!nlu) {
|
||||
console.log("Install Basic Messenger Webhook.");
|
||||
console.log("Validate the value of hubSuffixMessenger in CAInterface_settings");
|
||||
}
|
||||
|
||||
const messengerUrl = `${nlu.apiBaseURL}ProxyScript/run/${req.params.workspaceId}/${req.params.branch}/messenger${casettings.hubSuffixMessenger}`;
|
||||
const CA = CAInterface();
|
||||
const channel = req?.body?.event?.metadata?.channel ?? req?.body?.channel;
|
||||
const attachments = req?.body?.event?.metadata?.attachments;
|
||||
|
||||
const validEventInput = (event) => {
|
||||
console.log(20);
|
||||
console.log(event);
|
||||
return event?.input && event.input.length != 0;
|
||||
};
|
||||
|
||||
const getGatewayHeaders = async () => {
|
||||
const header = {};
|
||||
if (channel == "whatsapp") {
|
||||
const notify = casettings.notifications ?? [];
|
||||
const handler = notify.find(v => v.name === "VMGateway_eventHandler");
|
||||
if (handler) {
|
||||
const suffix = handler.hubSuffix || "";
|
||||
const gatewaySettings = eval("VMGateway_settings" + suffix);
|
||||
const { refreshGatewayKey } = eval("VMGateway_support" + suffix);
|
||||
if (gatewaySettings?.gateway) {
|
||||
header["x-auth-apiKey"] = await refreshGatewayKey(gatewaySettings.gateway);
|
||||
}
|
||||
}
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const smStr = `session-map-${sessionId}`;
|
||||
//await redis.set("sentdata", "false");
|
||||
const sessionMap = await redis.hGetAll(smStr);
|
||||
console.log(sessionMap);
|
||||
console.log(`47 line`);
|
||||
console.log(smStr);
|
||||
console.log({
|
||||
"Session Map": sessionMap,
|
||||
});
|
||||
if (sessionMap.chatDetails) {
|
||||
sessionMap.chatDetails = JSON.parse(sessionMap.chatDetails);
|
||||
}
|
||||
if (attachments?.length && sessionMap.liveChatRequest !== "true") {
|
||||
res.send({
|
||||
conversationId: sessionId, workspaceId: req.params.workspaceId,
|
||||
answers: [casettings.liveChat.attachment.noLiveChat]
|
||||
});
|
||||
} else if (sessionMap.liveChatRequest == "true" && sessionMap.formFlow !== "true") {
|
||||
if (attachments && attachments.length && sessionMap?.chatDetails?.userId) {
|
||||
const headers = await getGatewayHeaders();
|
||||
for (let attachment of attachments) {
|
||||
CA.sendAttachmentToAgent(sessionMap.chatDetails.userId, attachment, headers);
|
||||
console.log({ attachment });
|
||||
}
|
||||
}
|
||||
if (metadata?.liveChat === false) {
|
||||
await CA.leaveLiveChat(sessionId, sessionMap.conversationId, channel,
|
||||
req.body.event?.input, req.body.event?.sentBy?.userId);
|
||||
} else if (validEventInput(req.body.event)) {
|
||||
await CA.sendToLiveChat(sessionId, sessionMap.conversationId, channel,
|
||||
req.body.event?.input, req.body.event?.sentBy?.userId);
|
||||
}
|
||||
res.send({
|
||||
conversationId: sessionId, workspaceId: req.params.workspaceId,
|
||||
input: req.body.event?.input, answers: [],
|
||||
classificationResults: []
|
||||
});
|
||||
// }
|
||||
}
|
||||
else if (validEventInput(req.body.event)) {
|
||||
console.log(79);
|
||||
console.log(metadata);
|
||||
// call the webhook
|
||||
const { data: recognizedData } = await axios({
|
||||
url: messengerUrl,
|
||||
method: "post",
|
||||
data: req.body,
|
||||
});
|
||||
if (recognizedData?.formFlowEnd) {
|
||||
let sentdata = sessionMap?.sentdata;
|
||||
if (sessionMap?.datacollect === "true" && sentdata === "false") {
|
||||
let history = await gvf_ConversationHistory().fetchConversationHistory(sessionMap?.conversationId, 0);
|
||||
if (metadata?.liveChat === false) {
|
||||
await CA.leaveLiveChat(sessionId, sessionMap.conversationId, channel,
|
||||
history, req.body.event?.sentBy?.userId);
|
||||
} else if (validEventInput(req.body.event)) {
|
||||
await CA.sendToLiveChat(sessionId, sessionMap.conversationId, channel,
|
||||
history, req.body.event?.sentBy?.userId);
|
||||
}
|
||||
await redis.hSet(smStr, {
|
||||
datacollect: "false",
|
||||
sentdata: "true"
|
||||
});
|
||||
}
|
||||
}
|
||||
if (recognizedData?.outputs?.liveChat === true || metadata?.liveChat == true) {
|
||||
if (external && metadata?.liveChat == true) {
|
||||
// need to log invisible chat messages
|
||||
CA.addTransaction(recognizedData.conversationId, "Start Live Chat", "user", {
|
||||
liveChat: true,
|
||||
});
|
||||
}
|
||||
CA.joinLiveChat(
|
||||
channel,
|
||||
sessionId,
|
||||
recognizedData.conversationId,
|
||||
recognizedData?.outputs?.liveChatRequest
|
||||
);
|
||||
}
|
||||
res.send(recognizedData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
res.send({
|
||||
answers: ["Something went wrong. Please try again."],
|
||||
outputs: {},
|
||||
});
|
||||
}
|
||||
})();
|
||||
197
IVA-Wakeup/proxy/messenger.js
Normal file
197
IVA-Wakeup/proxy/messenger.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user