Dialogflow api call works, but chatbot shuts off - javascript

In Dialogflow, i use the free edition (V2) with the blaze plan from Firebase.
I have an Intent that works on the word "test". When i enter "test" in the simulator, the chatbot gives an non response and leaves the chat. It is suppose to make an call to my API and retrieves information.
The weird part is, there is a console.log that prints out the body and that returns the JSON from the API. So that means the API call works fine, but there is still an error somewhere within the bot.
I found this question: Dialogflow v2 error “MalformedResponse 'final_response' must be set”
It looks alot like my problem, yet i cant seem to figure out what i should change to make mine work.
Thanks in advance for your time.
The Fulfullment:
function testcommand(agent) {
callNPApi().then((output) => {
agent.add(output);
}).catch(() => {
agent.add("That went wrong!");
});
}
function callNPApi() {
return new Promise((resolve, reject) => {
request2(url, function (error, response2, body){
//The substring is too ensure it doesnt crash for the character limit yet
body = body.substring(1,10);
console.log('Api errors: ' + JSON.stringify(error));
console.log('Api body: ' + JSON.stringify(body));
if (error) {
reject();
}
resolve('api call returned: ');
});
});
}
The Response in the console:
{
"responseMetadata": {
"status": {
"code": 10,
"message": "Failed to parse Dialogflow response into AppResponse because of empty speech response",
"details": [
{
"#type": "type.googleapis.com/google.protobuf.Value",
"value": "{\"id\":\"bca7bd81-58f1-40e7-a5d5-e36b60986b66\",\"timestamp\":\"2018-09-06T12:45:26.718Z\",\"lang\":\"nl\",\"result\":{},\"alternateResult\":{},\"status\":{\"code\":200,\"errorType\":\"success\"},\"sessionId\":\"ABwppHFav_2zx7FWHNQn7d0uw8B_I06cY91SKfn1eJnVNFa3q_Y6CrE_OAJPV-ajaZXl7o2ZHfdlVAZwXw\"}"
}
]
}
}
}
The Error in the console:
MalformedResponse
'final_response' must be set.

Yup, this is the same problem.
The issue is that you're returning a Promise from callNPApi(), but your event handler (which I assume is testcommand()) isn't also returning a Promise. If you are doing async calls anywhere in your handler, you must use a Promise, and if you are using a Promise you must also return that Promise from the handler.
In your case, this should be a simple change. Simply add "return" to your handler. So it might look something like this
function testcommand(agent) {
return callNPApi().then((output) => {
agent.add(output);
}).catch(() => {
agent.add("That went wrong!");
});
}

Related

nodejs app crash on openai dall-e 2 api rejected request

I'm surely dumb, but I'm not able to figure out how to handle openai api rejected requests
( for the context, dall-e 2 is an image generator )
when user tries to generate forbidden images, my nodejs app just exits
async function start(arg) {
try{
// generate image
const response = openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
});
// on success response
response.then(res =>{
console.log("ok");
})
response.catch(err =>{
console.log(err);
});
} catch(e){
console.log(e);
}
}
it gives me something like that on the exit :
data: {
error: {
code: null,
message: 'Your request was rejected as a result of our safety system. Your prompt may contain text that is not allowed by our safety system.',
param: null,
type: 'invalid_request_error'
}
}
tried using response.catch and try catch without success, the app just exits everytime
I at least want to ignore this error in the first place
in a second hand, I would like to console.log the given message (data.error.message)
I don't know what to do to by honest, don't even understand why try catch isn't working
With the details given, my guess would be that the Promise returned by getImages is being rejected. You could debug this a bit by adding some additional logs into your .catch callback and catch statement.
How to do this really depends on what you're trying to do with this api, the code as it's currently written would log something and exit no matter what happens.
There's a couple ways to handle this
Use your .catch to handle the error. Utilizing promise chainability you can get something like this
openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
user: msg.author.id,
})
.catch((e) => {
if (e.data.error.message.includes('safety system')) {
return 'something'
}
console.error(e)
})
If you need the response object, the asnwer might be different. Looks like the openai package is built on axios and you can pass axios options into it. See https://axios-http.com/docs/handling_errors and the Request Options section of https://npmjs.com/package/openai
EDIT
I found my solution thanks to #JacksonChristoffersen
Basically I was getting http status 400
I just added request options from axios to validate http status smaller than 500
Here's the solution:
async function start(arg) {
try{
// generate image
const response = openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
},{
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500
}
});
// on success response
response.then(res =>{
console.log("ok");
})
response.catch(err =>{
console.log(err);
});
} catch(e){
console.log(e);
}
}

Parse Cloud Code Defines with Parse 3.0.0

I'm trying to return values from Parse.Cloud.define functions in cloud code using Parse. I'm using Parse 3.0.0 and I can get it to return values from simple cloud code defines but not complex ones.
I'm coding client side iOS in Objective-C.
Here's the cloud code function (I don't care if this is unsafe, I'm not changing it)
Parse.Cloud.define("doStuff", (request) => {
const query = new Parse.Query(Parse.User);
query.equalTo("username", request.params.username);
query.first({useMasterKey:true})
.then((results) => {
Parse.User.requestPasswordReset(results.get("email"))
.then(() => {
return "good work";
}).catch((error) => {
});
})
.catch((error) => {
});
});
This works just fine, it sends the email to the user as expected by using the User's username field.
In iOS I'm calling it like this:
[PFCloud callFunctionInBackground:#"doStuff" withParameters:#{#"username" : cleanEntryData} block:^(NSString * object, NSError * error) {
if (!error) {
NSLog(#"success %#", object);
} else {
NSLog(#"error %#", error);
}
}];
This call works in iOS and the email is successfully sent to the user for password reset. However, here's the problem.
when I call
NSLog(#"success %#", object);
the value in Xcode debug window is
success (null)
I expect it to be
success good work
When I a simple cloud code define like so:
Parse.Cloud.define("testing", (req) => {
return "very good";
});
with iOS like so:
[PFCloud callFunctionInBackground:#"testing" withParameters:#{#"nothing" : #"nothing"} block:^(NSString * object, NSError * error) {
if (!error) {
NSLog(#"success %#", object);
} else {
}
}];
then i get the result in Xcode debugger that i'm looking for
success very good
i don't know why the "doStuff" cloud code define is not returning the string "good work" when the function is clearly executing and sending the email as it should. I've read both the Parse 3.0.0 and JS 2.0.0 guides and they aren't very descriptive on how this should work with Parse Cloud defines. I'm not a JS coder, I only code in mobile, so I'm probably doing something stupid. Any help would be great. Thanks.
There's no issue in your iOS code, the issue lies in the cloud code, so you'll need to change the cloud code, since it's not necessarily unsafe, but rather flawed.
The issue is that you are nesting Promises inside each other instead of chaining them together, hence the single nested return value is lost in the several nested layers.
Parse.Cloud.define("doStuff", (request) => {
const query = new Parse.Query(Parse.User);
query.equalTo("username", request.params.username);
return query.first({useMasterKey:true})
.then((results) => {
return Parse.User.requestPasswordReset(results.get("email"));
}).then(() => {
return "good work";
})
});

Firebase response depending on Firestore Query does not work

Depending on whether there is an entry in Cloud Firestore with the correct DocumentId. However, this does not work because my function sends the status 200 before even finishing the query. So how can I get that working?
Here is my code:
access = false;
admin.firebase().collection("tuere").doc(door).collection("eintritt").get().then((snapshot) => {
snapshot.forEach((doc) => {
if(doc.id === uid){
access = true;
console.log("May open door " + uid);
}
});
}).catch((err) => {
console.log(err);
});
res.status(200).send(access);
When I open the Tab in Chrome and let it load "false" appears, but when I wait like 15 Seconds "May open door (uid)" appears in the Logs.
How can I solve this problem and how can i get my function to run faster?
You should send the HTTP response when the promise resolves, so within the then of the query promise: like that:
access = false;
admin.firebase().collection("tuere").doc(door).collection("eintritt").get()
.then((snapshot) => {
snapshot.forEach((doc) => {
if(doc.id === uid){
access = true;
console.log("May open door " + uid);
}
});
res.status(200).send(access);
}).catch((err) => {
console.log(err);
res.status(500).send(err);
});
Also, you should send an HTTP response in case of error, this is why I added res.status(500).send(err); in the catch
I would suggest you look this video from Doug Stevenson: https://www.youtube.com/watch?v=7IkUgCLr5oA
Also there is a point which surprises me: shouln't you use
admin.firestore().collection("tuere").doc(door)....
instead of
admin.firebase().collection("tuere").doc(door)
I have to look in the reference, but I have the feeling that admin.firebase() does not exist.

Promise either never get called, or is rejected (Parse JS SDK)

I am trying to write a function that add or edit some fields on a User object.
The problem come when I try to save the user, if I use user.save, the Promise is rejected with error 206 UserCannotBeAlteredWithoutSessionError.
However, if I get the session id (and documentation about that is scarce), the promise never get resolve, nor rejected. The app seems to just jump to the callback.
My function:
function update(user, callback) {
let query = new Parse.Query(Parse.User);
query.equalTo("username", user.email);
query.find().then(
(users) => {
if(users.length === 0) {
callback('Non existent user');
} else {
let user = users[0];
// user.set('some', 'thing');
console.log('save');
user.save(/*{
sessionToken: user.getSessionToken()
}*/).then(
(test) => {
console.log('OK - ' + test);
callback();
}, (err) => {
console.log('ERR- ' + require('util').inspect(err));
// console.log(callback.toString());
callback(error.message);
}
);
}
},
(error) => {
callback(error.message);
}
);
}
Called with:
var async = require('async'),
baas = require('./baas.js');
async.waterfall([
(callback) => {
callback(null, {
email: 'user#test.com',
password: 'password'
});
},
(user, callback) => {
console.log('connect');
baas.connect(() => { //Initialize the connection to Parse, and declare use of masterKey
callback(null, user);
});
},
(user, callback) => {
console.log('update');
baas.update(user, (err) => {
callback(err);
});
}
], (err) => {
console.log('Error: ' + err);
});
The logs become:
Without session token:
connect
update
save
ERR- ParseError { code: 206, message: 'cannot modify user sA20iPbC1i' }
With session token:
connect
update
save
I do not understand how it is possible that the promise just callback without printing anything, nor why no error are raised anywhere.
Edit:
Following #user866762 advice, I tried to replace the query with Parse.User.logIn and use the resulting User object.
While this solution give me a sessionToken, the end result is the same, parse crash if I don t provide the session token, or give me a error if I do.
According to the Parse Dev guide:
...you are not able to invoke any of the save or delete methods unless the Parse.User was obtained using an authenticated method, like logIn or signUp.
You might also try becoming the user before saving, but I have my doubts that will work.
When you're "get[ting] the session id" my guess is that you're really breaking something. Either Parse is having a heart attack at you asking for the session token, or when you're passing it in save you're causing something there to explode.

Returning a response immediately with res.json

I have an express route which takes in some parameters, queries the database, and then returns some response.
I am using sequelize to query the db:
router.get('/query', function(req,res) {
var name = req.params.name;
var gid = req.params.gid;
// Query the db
models.user.find({ where: { name: name }}).then(function(user) {
models.group.find({ where: { id: gid }}).then(function(group) {
// if user found, return data to client
if (user) {
res.json({"user": user, "group": group});
}
});
}).catch(function(error) {
// catch any errors from db query
res.status(500).json({"error":error});
});
// Return a server error for any other reason
// This causes ERROR
res.status(500).json({"error":"Something went wrong. Check your input."});
});
But I keep getting the error on the last line:
Can't set headers after they are sent
It seems like the last line is ALWAYS run, even if it finds a user (which should return data to the client and be done).
Why doesn't res.json(..) immediately return to the client when a user is found? Since headers were already set, when the last line runs, it throws that error.
You need to only conditionally return an error. The line:
res.status(500).json({"error":"Something went wrong. Check your input."});
is always getting executed. The reason for this is that the function you pass to the find method is only called later in the event loop after the db responds. This means that when that call back is called you have already set the error on the response.
Your should either remove that line or decide when you want to return an error but don't return an error every time.
Remember javascript is asynchronous.
As soon you call this function
models.user.find({ where: { name: name }})
That last line is executed:
res.status(500).json({"error":"Something went wrong. Check your input."});
It seems you are trying to cater for 2 scenarios:
Bad request data from client - i.e. no gid given
Internal server errors - i.e. error with the database
I would recommend changing your catch function to something like this:
.catch(function(error) {
// catch any errors from db query
if (err === "Unable to connect to database") {
return res.status(500).json({ error: "There was an internal error"})
}
res.status(400).json({"error": "Bad input, please ensure you sent all required data" });
});
Have a read up on the list of standard HTTP status codes:
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
What #bhspencer said is right. You have to remove that last line.
That line probably gets executed before any query in the database.
You need to implement a return in
models.user.find({ where: { name: name }}).then(function(user) {
models.group.find({ where: { id: gid }}).then(function(group) {
// if user found, return data to client
if (user) {
res.json({"user": user, "group": group});
return;
}
});
}).catch(function(error) {
// catch any errors from db query
res.status(500).json({"error":error});
return;
});
Actually res.json( does not end the processing of node.js code execution without return statement.

Categories

Resources