DialogFlow and contexts with voximplant - javascript

I try to set Contexts in DialogFlow with Voximplant intergration described here:
https://cogint.ai/voximplant-dialogflow-connector-2019/#settingcontexts
require(Modules.AI);
const languageCode = "en-US";
const agentId = 247;
let agent,
call,
conversation,
endUserParticipant,
isConversationCreated = false,
isCallCreated = false,
isCallConnected = false,
isParticipantCreated = false;
VoxEngine.addEventListener(AppEvents.Started,
function (ev) {
agent = new CCAI.Agent(agentId);
agent.addEventListener(CCAI.Events.Agent.Started, () => {
conversation = new CCAI.Conversation({ agent: agent });
conversation.addEventListener(CCAI.Events.Conversation.Created, () => {
isConversationCreated = true;
createParticipant();
});
});
});
VoxEngine.addEventListener(AppEvents.CallAlerting,
function (ev) {
isCallCreated = true;
createParticipant();
call = ev.call;
call.answer();
call.addEventListener(CallEvents.Connected,
function () {
isCallConnected = true;
//Script whith phone number to contexts must be added here somehow. Probably in setupMedia function.
setupMedia();
});
call.addEventListener(CallEvents.Disconnected,
function () {
conversation.stop();
VoxEngine.terminate();
});
});
function createParticipant() {
if (!isConversationCreated || !isCallCreated) return;
endUserParticipant = conversation.addParticipant({
call: call,
options: { role: "END_USER" },
dialogflowSettings: {
lang: languageCode,
singleUtterance: true,
replyAudioConfig: { audioEncoding: "OUTPUT_AUDIO_ENCODING_OGG_OPUS" },
},
});
endUserParticipant.addEventListener(CCAI.Events.Participant.Created, () => {
isParticipantCreated = true;
setupMedia();
});
}
function setupMedia() {
if (!isParticipantCreated || !isCallConnected) return;
endUserParticipant.analyzeContent({
eventInput: { name: "WELCOME", languageCode: languageCode },
});
endUserParticipant.addEventListener(
//Script whith phone number to contexts must be added here somehow.
phoneContext = {
name: "phone",
lifespanCount: 99,
parameters: {
caller_id: call.callerid(),
called_number: call.number()
}
},
//endUserParticipant.setQueryParameters({contexts: [phoneContext]})
//Script whith phone number to contexts must be added here somehow.
CCAI.Events.Participant.PlaybackFinished,
() => {
//Added by and call works, but hang up
VoxEngine.setQueryParameters({contexts: [phoneContext]});
//Added by and call works, but hang up
VoxEngine.sendMediaBetween(call, endUserParticipant);
}
);
VoxEngine.sendMediaBetween(call, endUserParticipant);
}
The Voximplant number is forwarded to Dialogflow but after 20 seconds the voicebot become silent, but call is not terminated. I remove contexts part and the call and voicebot works as it is intended to.
What is wrong?

I ended up rewrite my code. I was able to pass on the caller_id / caller_number parameters to DialogFlow not as a Contexts by script. However, I added the two variables as Contexts in my Welcome intent.
function setupMedia() {
if (!isParticipantCreated || !isCallConnected) return;
endUserParticipant.analyzeContent({
eventInput: {
name: "WELCOME",
languageCode: languageCode,
parameters: {
//phone: call.callerid(),
caller_id: call.callerid(),
called_number: call.number()}
},
});
endUserParticipant.addEventListener(
CCAI.Events.Participant.PlaybackFinished,
() => {
VoxEngine.sendMediaBetween(call, endUserParticipant);
}
);
VoxEngine.sendMediaBetween(call, endUserParticipant);
}

I recommend using Voximplant's Modules.AI integration instead of Modules.CCAI as I used in the cogint.ai article you mentioned. Modules.CCAIis used automatically through Dialogflow's One-click integrations, but it is not as well supported beyond that from what I have seen.
They have instructions for that here and a walkthrough video here. Unfortunately the API is very different that what you have with the CCAI module, but you will find many more references and examples to that (like what I have on cogint.ai).
Modules.AI only works with Dialogflow ES.

Related

How to disable toast message for Newsletter module on Odoo (v14) website

For the website I develop, I use Newsletter module to create a mailing list. It's quite enough for basic needs. When you insert an e-mail and click to subscribe button, it shows (replace) "Thanks" message and hide the "Subscribe" button. It also shows a toast message: "Thanks for subscribing!" on the top right side of the page.
I don't want to show toast messages for newsletter subscriptions. Unfortunately, there is no option to enable/disable it.
If I disable/remove that part below from website_mass_mailing.js file it doesn't show the toast message.
self.displayNotification({
type: toastType,
title: toastType === 'success' ? _t('Success') : _t('Error'),
message: result.toast_content,
sticky: true,
});
I don't want to touch this file (website_mass_mailing.js) but instead, inherit it and remove that part but I couldn't succeed. Any suggestion on how to do it?
You should create a new module which depends on website_mass_mailing and extends mass_mailing.website_integration via a dedicated javascript module.
For example:
odoo.define('my_module.mass_mailing_website_integration', function (require) {
var website_integration = require('mass_mailing.website_integration');
website_integration.extend({
// Your Logic Here
});
}
Find mass_mailing method who's calling displayNotification and override it.
Unfortunately i see no alternative to copy-pasting it entirely from source and then removing desired behaviours.
Do not forget to include your javascript in web_assets template.
After suggestions of #icra I've tried to figure it out and here is the code that worked for me.
Thanks to Cybrosys Techno Solutions Pvt.Ltd as well to achieve the solution.
Here is the code:
odoo.define('your_module.name', function (require){
var publicWidget = require('web.public.widget');
var _t = core._t;
publicWidget.registry.subscribe.include({
_onSubscribeClick: async function () {
var self = this;
var $email = this.$(".js_subscribe_email:visible");
if ($email.length && !$email.val().match(/.+#.+/)) {
this.$target.addClass('o_has_error').find('.form-control').addClass('is-invalid');
return false;
}
this.$target.removeClass('o_has_error').find('.form-control').removeClass('is-invalid');
let tokenObj = null;
if (this._recaptcha) {
tokenObj = await this._recaptcha.getToken('website_mass_mailing_subscribe');
if (tokenObj.error) {
self.displayNotification({
type: 'danger',
title: _t("Error"),
message: tokenObj.error,
sticky: true,
});
return false;
}
}
const params = {
'list_id': this.$target.data('list-id'),
'email': $email.length ? $email.val() : false,
};
if (this._recaptcha) {
params['recaptcha_token_response'] = tokenObj.token;
}
this._rpc({
route: '/website_mass_mailing/subscribe',
params: params,
}).then(function (result) {
let toastType = result.toast_type;
if (toastType === 'success') {
self.$(".js_subscribe_btn").addClass('d-none');
self.$(".js_subscribed_btn").removeClass('d-none');
self.$('input.js_subscribe_email').prop('disabled', !!result);
if (self.$popup.length) {
self.$popup.modal('hide');
}
}
// make the changes you need accordingly or comment out the below code.
self.displayNotification({
type: toastType,
title: toastType === 'success' ? _t('Success') : _t('Error'),
message: result.toast_content,
sticky: true,
});
});
},
})
})

VueJS this.progress is undefined inside window function

I'm using a Facebook login and I'm showing progress loading for the user until I get a response back from Facebook for authentication.
But I used to hide the progress bar like this.progress = false but this variable is undefined inside the window function.
My code :
initFacebook() {
this.progress=true
window.fbAsyncInit = function() {
window.FB.init({
appId: "MY-APP-ID", //You will need to change this
cookie: true, // This is important, it's not enabled by default
version: "v2.6",
status: false,
});
window.FB.login(function(response) {
if (response.status === 'connected'){
window.FB.api('/me?fields=id,name,email', function(response) {
console.log( response) // it will not be null ;)
})
} else {
console.log("User cancelled login or did not fully authorize.")
}
},
{scope: 'public_profile,email'}
);
this.progress = false
console.warn(this.progress)
};
},
I'm unable to set this.progress = false after getting all responses from Facebook.
I get an error while I console.log(this.progress) variable.
Error :
Login.vue?7463:175 undefined
How can I set this.progress variable to false once the authentication checks are complete?
Try converting all function() calls into arrow function calls () =>
The problem is that a function() will break the global vue scope. So vue this is not available within a function() call, but it is available within an arrow function () => {}
In a block scope (function() { syntax), this is bound to the nested scope and not vue's this instance. If you want to keep vues this inside of a function, use an arrow function (ES6) or you can have const that = this and defer the global this to that in a regular function() { if you prefer it this way.
Try using this code converted with arrow functions and see if it works:
initFacebook() {
this.progress=true
window.fbAsyncInit = () => {
window.FB.init({
appId: "MY-APP-ID", //You will need to change this
cookie: true, // This is important, it's not enabled by default
version: "v2.6",
status: false,
});
window.FB.login((response) => {
if (response.status === 'connected'){
window.FB.api('/me?fields=id,name,email', (response) => {
console.log( response) // it will not be null ;)
})
} else {
console.log("User cancelled login or did not fully authorize.")
}
},
{scope: 'public_profile,email'});
this.progress = false
console.warn(this.progress)
};
},
I know this because I just had the same problem :-) see here:
Nuxt plugin cannot access Vue's 'this' instance in function blocks

how to do nativescript paytm integration

i have checked the native-script-paytm integration plugin. but both git-hub repository are not running instead it gives stack exception. so i created my own project and some how its doing something. but here i have lot of questions on how to get 'mid', 'order id' etc.
can anyone give step by step details for this.
const createViewModel = require("./main-view-model").createViewModel;
const Paytm = require("#nstudio/nativescript-paytm").Paytm;
const paytm = new Paytm();
exports.pageLoaded = function (args) {
const page = args.object;
page.bindingContext = createViewModel();
}
exports.onPayWithPaytm = function (args) {
console.log("Paying");
paytm.setIOSCallbacks({
didFinishedResponse: function (response) {
console.log("got response");
console.log(response);
},
didCancelTransaction: function () {
console.log("User cancelled transaction");
},
errorMissingParameterError: function (error) {
console.log(error);
}
});
const order = {
// This will fail saying duplicate order id
// generate your own order to test this.
MID: "Tomcas09769922377481",
ORDER_ID: "ORDER8874",
CUST_ID: "CUST6483",
INDUSTRY_TYPE_ID: "Retail",
CHANNEL_ID: "WAP",
TXN_AMOUNT: "10.00",
WEBSITE: "APP_STAGING",
CALLBACK_URL: "https://pguat.paytm.com/paytmchecksum/paytmCallback.jsp",
CHECKSUMHASH:
"NDspZhvSHbq44K3A9Y4daf9En3l2Ndu9fmOdLG+bIwugQ6682Q3JiNprqmhiWAgGUnNcxta3LT2Vtk3EPwDww8o87A8tyn7/jAS2UAS9m+c="
};
paytm.createOrder(order);
paytm.initialize("STAGING");
paytm.startPaymentTransaction({
someUIErrorOccurred: function (inErrorMessage) {
console.log(inErrorMessage);
},
onTransactionResponse: function (inResponse) {
console.log(inResponse);
},
networkNotAvailable: function () {
console.log("Network not available");
},
clientAuthenticationFailed: function (inErrorMessage) {
console.log(inErrorMessage);
},
onErrorLoadingWebPage: function (
iniErrorCode,
inErrorMessage,
inFailingUrl
) {
console.log(iniErrorCode, inErrorMessage, inFailingUrl);
},
onBackPressedCancelTransaction: function () {
console.log("User cancelled transaction by pressing back button");
},
onTransactionCancel: function (inErrorMessage, inResponse) {
console.log(inErrorMessage, inResponse);
}
});
}
For reference
As mentioned in the plugin's ReadMe file,
You will need a working backend server to generate paytm orders. Do not generate the order or checksum in the app.

Issue with Firebase Cloud Messaging Service Worker and self.addEventListener

I've successfully built an FCM notification service worker for my web app, and it's working OK so far. I used toastr to present notifications within the web app. I'm currently having an issue with the service worker when the web site is not open. Here is my code from firebae-messaging-sw.js:
//Firebase initialized above here
messaging.setBackgroundMessageHandler(function (payload) {
const notiTitle = payload.data.title;
var body = payload.data.body;
const opts = {
icon : "/ui/img/icons/android-chrome-256x256.png",
actions : [
{
action: 'view-ticket',
title: 'View Ticket',
icon: null
}
],
body: body
//url: link
};
self.addEventListener('notificationclick', function (event) {
const clickedNotification = event.notification;
clickedNotification.close();
if(!event.action) {
return;
}
switch(event.action) {
case 'view-ticket':
var promiseChain = clients.openWindow(payload.data.link);
break;
}
event.waitUntil(promiseChain);
});
return self.registration.showNotification(notiTitle, opts);
});
It's almost working perfectly except for one issue. When I send my first test notification, payload.data.link is parsed ok. But on the next notification, payload.data.link is not updated, so the wrong link is sent. I think that maybe self.addEventListener is in the wrong place, but I'm not sure how else to put it (I obviously can't do it after the return).
Any idea where I should put the event listener code?
I fixed it! I was able to repair this by adding a variable and moving addEventListener outside of setBackgroundMessageHandler like so:
//Firebase started up above
var clickDestination; //init this variable
//add event listener before background message handler and use clickDestination
self.addEventListener('notificationclick', function (event) {
const clickedNotification = event.notification;
clickedNotification.close();
if (!event.action) {
return;
}
if(event.action === 'view-ticket') {
var promise = new Promise(function () {
return clients.openWindow(clickDestination);
});
event.waitUntil(promise);
}
});
messaging.setBackgroundMessageHandler(function (payload) {
const notiTitle = payload.data.title;
var body = payload.data.body;
clickDestination = payload.data.link; //set clickDestination based on payload
/*self.addEventListener('notificationclick', function (event) {
event.notification.close();
event.waitUntil(self.clients.openWindow(payload.data.link));
});*/
const opts = {
icon : "/ui/img/icons/android-chrome-256x256.png",
actions : [
{
action: 'view-ticket',
title: 'View Ticket',
icon: '/ui/img/icons/ticket-icon.png'
}
],
body: body
};
return self.registration.showNotification(notiTitle, opts);

Do I need any server adjustments in order to use fully HTML5 History API?

I am using HTML5 History API (on Chrome), at the following link:
http://jsbin.com/zuqijofole/1
You can see a simple application which shows/hides div (Views).
Script works fine using browser backward and forward buttons but if I type directly in the browser the following address (in order to see View 2)
http://jsbin.com/zuqijofole/2
the document is not found. I need instead the second View to be shown.
I would like to know:
Should I implement on server side some logic which map URL? Which
coul be a solution using latest PHP?
Or am I missing some implementation in my JS?
Notes: solution should work in a SPA application, so all data is rendered by JS app.
window.app = {
data: {
views: [
{ id: 0, isActive: false },
{ id: 1, isActive: false },
{ id: 2, isActive: false },
]
},
start: function () {
this.listeners();
// default entry
var activeView = this.wm.activeView;
history.replaceState({ activeView: activeView }, document.title, document.location.href);
window.app.wm.hideViews();
window.app.wm.showView();
},
listeners: function () {
window.addEventListener('popstate', function (event) {
// fires when backing/forwarding in history
console.log(event);
console.log(window.history.state);
this.wm.showHideBl(event.state);
}.bind(this));
var elm = document.getElementById('btn-prev');
elm.addEventListener('click', function () {
window.app.wm.snowPrevView();
});
elm = document.getElementById('btn-next');
elm.addEventListener('click', function () {
window.app.wm.snowNextView();
});
},
wm: {
activeView: 0, // default
showView: function () {
var elm = document.getElementById('view-' + this.activeView);
elm.style.display = '';
},
showHideBl: function (data) {
this.hideView();
this.activeView = data.activeView;
this.showView();
},
snowNextView: function () {
// bl
if (this.activeView < window.app.data.views.length - 1) {
this.hideView();
this.activeView++;
this.showView();
history.pushState({ activeView: this.activeView }, '', this.activeView);
}
},
snowPrevView: function () {
// bl
if (this.activeView > 0) {
this.hideView();
this.activeView--;
this.showView();
history.pushState({ activeView: this.activeView }, '', this.activeView);
}
},
hideView: function () {
var elm = document.getElementById('view-' + this.activeView);
elm.style.display = 'none';
},
hideViews: function () {
window.app.data.views.forEach(function (item, index, array) {
var elm = document.getElementById('view-' + item.id);
elm.style.display = 'none';
}.bind(this));
}
}
};
Yes, for a completely seamless experience, you want that all URLs created by the History API to be mapped to actual URLs that the server can use.
For example, if you have a table that you can sort client side, you can use the history API to save the sorting state into the URL. The server should be able to read that URL and serve a table already sorted when the page is refreshed.
The best way to make sure everything works as intended is to disable JavaScript and make sure you can still navigate and use the site correctly (even though the page refreshes all the time).

Categories

Resources