I am trying to build a chatbot using dialogflow, I am trying to call an event after a time period like in the below code:
function createLink(agent) {
setTimeout(cnf, 3000);
agent.add(`Please complete payment by clicking (https://www.aa.bb)`);
}
function cnf(agent) {
console.log('In cnf');
agent.setFollowupEvent('cnf_event');
}
The logs shows that cnf function got executed but dialogflow never execute the cnf_event
What's happening here and how can I do this
Any help, thanks in advance!
You need to pass agent within your set-timeout function,
function createLink(agent) {
setTimeout((agent) => {
cnf(agent)
}, 3000);
console.log(`Please complete payment by clicking (https://www.aa.bb)`);
}
function cnf(agent) {
console.log('In cnf');
agent.setFollowupEvent('cnf_event');
}
Related
I am building this app where each user can execute a function in my node.js server, the function is a loop that keep running and updating the db. My goal is to find a way to stop the function executed by the user, to give you an idea about the logic I already implemented please see the code below :
app.get('/api/v1/', cors(), (request, response) => {
let timer = setInterval(apiCall, interval);
if (request.query.running === false) {
clearInterval(timer);
}
function apiCall(i) {
webshot(url, 'public/' + filename, options, function (err) {
if (err) { console.log(err) }
});
}
})
I was planning to send an API call with running=false to stop it but it doesn't seems to work, it just create another thread
Your approach works, with a few improvements and changes in logic:
You should compare to 'false' instead of false, or parse/eval the
querystring.
Your timer variable's scope should be the entire web process. If you declare it inside the function, you loose its reference to use it later in clearInterval.
Your setInterval must be inside an else clause, in other way you'll be cancelling it and starting it again in the same call.
Your example didn't have defined the interval variable. I changed it for 2s.
Having this changed, your example works. Check it out:
var express = require('express');
var app = express();
var timer;
function apiCall(i) {
console.log("api called " + Date());
}
app.get('/api/v1/', (request, response) => {
if (request.query.running === 'false') {
clearInterval(timer);
console.log('Timer stopped');
} else {
console.log('Timer started');
timer = setInterval(apiCall, 2000);
}
response.send(200);
})
app.listen(3000);
Of course this solution has a problem: it will not distinguish between user calls: this means that if several users call your API endpoint, all of them will be interacting with the same timer. If you want different timers per user you'll have to add logic inside your api to detect which user made the call, and of course have a different timer for each user. The easiest would be to add a name inside the API call: /api/v1/john/, and instead of a timer variable, have a mapping with the timer variable for each user. Regards!
Homebridge trigger function in other function
I want to trigger a binded function such as getCurrentFanSpeed in setInterval
I have tried .getCurrentFanSpeed or .getCurrentFanSpeed.call();
setInterval(function () {
fanservice.getCurrentFanSpeed ;
fanservice.log("Interval: Get Current Fan Speed");
}, this.interval);
Actually it doesn't run the code.
only displayed Interval: Get Current Fan Speed every 10sec
If Fanservice accepts callback function, You can get a result like below.
setInterval(async function () {
fanservice.getCurrentFanSpeed(function(result) => {
console.log(result);
});
fanservice.log("Interval: Get Current Fan Speed");
}, this.interval);
It might help you
Finally i found that i can just use emit() to call the function
such as
fanService.getCharacteristic(Characteristic.RotationSpeed).emit("set");
thanks for all.
I'm using both chrome.webRequest.onBeforeRequest and chrome.tabs.onCreate listeners in my extension. I'm trying to utilize the tab.openerTabId attribute that you get in tabs.onCreate, to have it available by the time the webRequest.onBeforeRequest callback runs, but onBeforeRequest seems to be running before tabs.onCreate fires. Is there any simple way around this?
var openerTabId;
function checkNewTab(tab) {
openerTabId = tab.openerTabId;
}
function checkRedirects(details) {
//code that I don't want to run until I have openerTabId in those
//instances where web request is due to a new tab being opened
}
function setupNewTabListener() {
chrome.tabs.onCreated.addListener(checkNewTab);
}
function setUpRedirectListener() {
chrome.webRequest.onBeforeRequest.removeListener(checkRedirects);
var filter = createFilter(redirects);
chrome.webRequest.onBeforeRequest.addListener(checkRedirects, filter, ["blocking"]);
}
function setupInitial() {
'''
setupNewTabListener();
setUpRedirectListener();
'''
}
chrome.storage.local.get({
'''
setupInitial();
});
I have some intents that need to trigger the fulfillment webhook and don't care about the response. The webhook takes longer than the timeout to respond so I'd like the intent to simply respond with "Thanks for chatting" and then close the conversation while actually triggering the webhook.
Feels easy but I'm missing something. Also I'm new to the dialogflow stuff.
I can do this in any language, but here's an example in Javascript:
fdk.handle(function (input) {
// Some code here that takes 20 seconds.
return {'fulfillmentText': 'i can respond but I will never make it here.'}
});
EDIT 1 - Trying async
When I use an async function, the POST request never happens. So in the following code:
fdk.handle(function (input) {
callFlow(input);
return { 'fulfillmentText': 'here is the response from the webhook!!' }
});
async function callFlow(input) {
console.log("input is --> " + input)
var url = "some_url"
console.log("Requesting " + url)
request(url, { json: true, headers: {'Access-Control-Allow-Origin' : '*'} }, (err, res, body) => {
if (err) { return console.log(err); }
console.log("body is...")
console.log(body)
});
}
I see in the logs the two console.log outputs but nothing from the request. And the request doesn't seem to happen either because I don't see it at my endpoint.
SOLUTION
Thanks Prisoner for the tip. Seems like I needed to return the fulfillment JSON back through the callFlow() and handle() functions. Now Google Home doesn't timeout and both the HTTP call and response are generated.
const fdk = require('#fnproject/fdk');
const request = require('request');
fdk.handle(function (input) {
return callFlow(input);
});
async function callFlow(input) {
var searchPhrase = input || "cats"
var url = "some url"
return new Promise((resolve, reject) => {
request.post(url, {
headers: { 'content-type': 'application/x-www-form-urlencoded' },
body: searchPhrase
},
function (err, resp, body) {
if (err) { return console.log(err) }
r = { 'fulfillmentText': `OK I've triggered the flow function with search term ${searchPhrase}` }
resolve(r)
}
);
});
}
You cannot trigger the fulfillment asynchronously. In a conversational model, it is expected that the fulfillment will perform some logic that determines the response.
You can, however, perform an asynchronous operation in the fulfillment that does not complete before you return the result.
If you are using a sufficiently modern version of node (version 8 and up), you can do this by declaring a function as an async function, but not calling it with the await keyword. (If you did call it with await, it would wait for the asynchronous operation to complete before continuing.)
So something like this should work, given your example:
async function doSomethingLong(){
// This takes 20 seconds
}
fdk.handle(function (input) {
doSomethingLong();
return {'fulfillmentText': 'This might respond before doSomethingLong finishes.'}
});
Update 1 based on your code example.
It seems odd that you report that the call to request doesn't appear to be done at all, but there are some odd things about it that may be causing it.
First, request itself isn't an async function. It is using a callback model and async functions don't just automatically wait for those callbacks to be called. So your callFlow() function calls console.log() a couple of times, calls request() and returns before the callbacks are called back.
You probably should replace request with something like the request-promise-native package and await the Promise that you get from the call. This makes callFlow() truly asynchronous (and you can log when it finishes the call).
Second, I'd point out that the code you showed doesn't do a POST operation. It does a GET by default. If you, or the API you're calling, expect a POST, that may be the source of the error. However, I would have expected the err parameter to be populated, and your code does look like it checks for, and logs, this.
The one unknown in the whole setup, for me, is that I don't know how fdk handles async functions, and my cursory reading of the documentation hasn't educated me. I've done this with other frameworks, and this isn't a problem, but I don't know if the fdk handler times out or does other things to kill a call once it sends a reply.
I'm new to node.js.
I have tried to create a setTimeout that executes a database SELECT Query and repeats 3 seconds after processing the SELECT results has completed.
var newDBMessagesInterval = 3000; // 3 Seconds
(function newDBMessagesSchedule() {
setTimeout(function() {
dbNewMessagesQuery(function(dbResults,dbResultsLength) {
console.log(dbResults);
newDBMessagesSchedule();
});
}, newDBMessagesInterval)
})();
function dbNewMessagesQuery(callback) {
dbConnection.query("SELECT data1,data2,data3 FROM table WHERE condition=1;", function (dbError, dbResults, dbFields) {
if(dbResults.length > 0) {
callback(dbResults,dbResults.length);
}
});
callback();
}
It appears the setTimeout number of loops increases each time it runs (eg: first one console.log(dbResults), but then 2times and then 4 etc). Also I'm not sure if its waiting on the database SELECT to completed before trying to process the next time.
Looking for some advise on how to create this loop correctly with node.js
thx
Your dbNewMessagesQuery calls callback twice. Once synchronously, and once after the db query succeeds. You should just be calling it once after the query is done. With your current code, for every call to newDBMessagesSchedule, you queue up two more calls to run later.
function dbNewMessagesQuery(callback) {
dbConnection.query("SELECT data1,data2,data3 FROM table WHERE condition=1;", function (dbError, dbResults, dbFields) {
callback(dbResults, dbResults.length);
});
}
I'd also recommend not bothering to pass the length separately, and instead pass along the error if there is one. Currently you just assume there will never be an error.
function dbNewMessagesQuery(callback) {
dbConnection.query("SELECT data1,data2,data3 FROM table WHERE condition=1;", function (dbError, dbResults, dbFields) {
callback(dbError, dbResults);
});
}