I got a weird problem with dialogflow / node.js backend.
Within Dialogflow I have two entities "color" and "order_amount". I set the entities to required within the intent. But only one of the required entities is send back to my backend and the other is undefined. Though both are received within dialogflow.
app.intent('Default Welcome Intent - yes', (conv, {product_color}, {order_amount}) => {
console.log({product_color});
console.log({order_amount});
conv.ask(`Top. In welke maat?`);
});
So for example, when this intent runs the slotfilling is being done in dialogflow. But I only the first entity is defined e.g {color} and {order_amount} is undefined. When I switch {product_color} and {order_amount} as the below example. Then product_color is undefined.
app.intent('Default Welcome Intent - yes', (conv, {order_amount}, {product_color})
Anyone knows whats going on?
Got the answer myself. You can use "params": https://actions-on-google.github.io/actions-on-google-nodejs/classes/dialogflow.dialogflowconversation.html#parameters
The issue is that you're mangling your JavaScript. The second function parameter contains an object with all the Intent parameters. The {name1} syntax in JavaScript maps object attribute names to a variable. So you could rewrite the line as
app.intent('Default Welcome Intent - yes', (conv, {product_color,order_amount})
Related
What if I have more than 100 intents including the followup intents. Should we write separate handler for each 100 intent and call a common function from the handler function. Is it correct?
Here we want to have common function with intent name as parameter, because all we do is fetch the response from database.
Shall we have parameterized function in intentmap set or have separate handler function for all these intents and call common parameterized function from inside. Please suggest.
Yes using paramerized functions or classes is a good practice. With this setup you can easily re-use any required logic if two intents perform similair actions in the webhook.
If you require some different behaviour you can enter values into the parameters, an example of this would be a function that ends the conversation.
app.intent("Stop Conversation"), (conv) => {
const message = "Okay, have a nice day";
endConversation(conv, message);
});
app.intent("Cancel Reservation"), (conv) => {
const message = "Okay, I will cancel your reservation. Have a nice day."
endConversation(conv, message)
});
endConversation(conv, message) {
conv.close(message);
}
You could choose to go for one single handler that looks up the intent name and then fetches the response, but this can cause some issues when working with Helper intents. These Helper intents require extra parameters that normal intents do no use, so you will have to account for them in your common handler or write seperate handlers for them. If you do not need these intents, then there isn't any harm in using a single handler.
One extra thing to note, having 100 intents is quite alot. Remember that intents should be used to indicate what you user says and not as a step in your flow. Usually this means that you only have one intent to handle yes input from your users and you will use context to detirmine which step of the conversation you are in.
If you are using the actions-on-google or dialogflow-fulfillment libraries, then yes, having an Intent Handler for each Intent and having those handlers call other functions with the parameters you want is the best approach.
However... if you're not using these libraries, you certainly have other options available.
For example, using multivocal you can set builder functions that extract parameters into the request environment and make the database call. If you set the "Action" field in Dialogflow you can (but don't have to) use this as the basis for an Action Handler.
If you just want to stick to your own libraries, you can parse the JSON yourself and make whatever function calls based on whatever values you wish.
I have been exploring Dialogflow from last 6-7 days and have created a bot which has menu in the form of List.
After going through lot of articles got to know that we need to have event actions_intent_OPTION in one of the intents for List to work properly. Also got to know that on top of it we need to have handler/intent for actions_intent_OPTION. This intent would be triggered once user taps one of the option of List.
Now i am struggling in defining handler for event actions_intent_OPTION. I had defined intent with name "actions_intent_OPTION-handler" but I am not able to find the code which i can code in for fulfillment section of Dialogflow, which will identify the option selected by user and will call the intent associated to that option.
I am a not from coding background, and I tried one code (index.js), but when deployed doesn't given any error however when executed on simulator it throws error "Failed to parse Dialogflow response into AppResponse because of empty speech response."
Reiterating my requirement, I am looking for a sample code which can capture the option selected by user (from list) and trigger the already defined intent.
Details about bot,list and intents is attached herewith.
This is the list defined by me and currently iam trying to code to capture the Payment Due Date option (which has text Payment Due Date Electricity defined in list
Code in fulfillment section
Intents defined
Note - Intent which needs to be called is "1.1 - ElectricityDetails - DueDate"
Here is the code -> Please don't ask me why i have used certain peice of code, as iam newbie :).
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {dialogflow} = require('actions-on-google');
const app = dialogflow({debug: true});
//const agent = new WebhookClient({ request, response });
let intentMap = new Map();
app.intent('actions_intent_OPTION-handler', (conv, params, option) => {
if (!option) {
conv.ask('You did not select any item from the list or carousel');
} else if (option === 'Payment Due Date Electricity') {
//conv.ask('You are great');
//intentMap.set('Default Welcome Intent', welcome);
intentMap.set('1.1 - ElectricityDetails - DueDate',option);
} else {
conv.ask('You selected ' + option);
}
});
//agent.handleRequest(intentMap);
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have a few issues here, so it is difficult to tell exactly which one is the real problem, but they all boil down to this statement in your question:
Please don't ask me why i have used certain peice of code
We understand that you're new - we've all been there! But copying code without understanding what it is supposed to do is a risky path.
That said, there are a few things about your design and code that jump out at me as issues:
Mixing libraries
You seem to be loading both the actions-on-google library and the dialogflow-fulfillment library. While most of what you're doing is with the actions-on-google library, the intentMap is what is used by the d-f library.
You can't mix the two. Pick one and understand how to register handlers and how those handlers are chosen.
Register handlers with actions-on-google
If you're using the a-o-g library, you'll typically create the app object with something like
const app = dialogflow();
and then register each handler with something like
app.intent( 'intent name', conv => {
// handler code here
});
You'll register the app to handle the request and response with something like
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Register handler with dialogflow-fulfillment
The dialogflow-fulfillment approach is similar, but it suggests creating a Map that maps from Intent Name to handler function. Something like this:
let intentMap = new Map();
intentMap.set( 'intent name', handlerFunction );
Where handlerFunction is also the name of a function you want to use as the handler. It might look something like
function handlerFunction( agent ){
// Handler stuff here
}
You can then create an agent, set the request and response objects it should use, and tell it to use the map to figure out which Intent Handler to call with something like
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
agent.handleRequest( intentMap );
Intents represent what the user does, not what you do with it
Remember that Intents represent a user's action.
What you do based on that action depends on a lot of things. In your case, once they have selected an option, you want to reply the same way as if they had triggered it with a particular Intent. Right?
You don't do that by trying to trigger that Intent.
What you do is you have both Handlers call a function that does what you want. There is nothing fancy about this - both are just calling the same function, just like lots of other code that can call common functions.
Don't try to dynamically register handlers
Related to the previous issue, trying to register a new Handler inside an existing Handler won't do what you want. By that time, it is too late, and the handlers are already called.
There may be situations where this makes sense - but they are very few, far between, and a very very advanced concept. In general, register all your handlers in a central place as I outlined above.
Hi I have made an entity called answers in dialogflow, this entity contains all the answers to my questions for my quiz game.
I get the questions from my database and then check to see if the given answer is correct.
app.intent('answer-question', (conv, {answer})=> {
if(answer == ((conv.data.answers)[0])){
//stuff}
else{
conv.close('you lose');
}
});
However, this function only works when the user gets the answer correct. If the user answers the question incorrectly, then I get the following error:
"Question Master isn't responding right now. Try again soon."
MalformedResponse
'final_response' must be set.
So my question is, how can i cater for the infinite selection of wrong answers a user might give?
Cheers!
You should handle that in a fallback intent. A new Dialogflow agent comes with a default: https://dialogflow.com/docs/intents/default-intents#default_fallback_intent
You should also consider using contexts, so the fallback intent knows that you are expecting an answer and provide a different response when an answer isn't expected.
I have an intent named "intent.address" with the action name "address_action" and the training phrase "My address". When this intent is triggered, response comes from my webhook saying "Alright! your address is USER_ADDRESS".
Used app.ask() here
What I want is, when this response comes from the webhook then another intent named "intent.conversation" (event name "actions_intent_CONFIRMATION")(here also webhook enabled) gets triggered, which will ask for user confirmation to continue or not?
For example :
Alright your address is USER_ADDRESS
then next
Do you want ask address/directions again?
Intents do not reflect what your webhook says, it reflects what the user says. Intents are what the user intends to do - what they want.
So no, you can't just trigger another Intent this way. There are a few ways to do what you're asking, however.
Using the Confirmation helper with the actions-on-google v1 node.js library
If you really want to use the Confirmation helper, you need to send back JSON, since the node.js v1 library doesn't support sending this helper directly. Your response will need to look something like:
{
"data": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.CONFIRMATION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.ConfirmationValueSpec",
"dialogSpec": {
"requestConfirmationText": "Please confirm your order."
}
}
}
}
}
}
If you're not already doing JSON in your responses, then you probably don't want to go this route.
Using the Confirmation helper with the actions-on-google v2 node.js library
If you've already switched to v2 of this library, then you have the ability to send a Confirmation with something like this
app.intent('ask_for_confirmation_detail', (conv) => {
conv.ask("Here is some information.");
conv.ask(new Confirmation('Can you confirm?'));
});
Or you can just use the Dialogflow way of doing this
In this scenario - you don't use the Confirmation helper at all, since it is pretty messy.
Instead, you include your question as part of the response, and you add two Followup Intents - one to handle what to do if they say "yes", and one if they say "no".
API.ai's prebuild packages allow you to easily get long lists of intents. Currently I'm trying to make use of their smalltalk package, which has at about 100 intents, and response to each.
I am making use of the api-ai-recognizer package to listen for intents. That works well, but now I have to match those intents, so that I can define the dialog (which is nothing more than using the fulfillment). And this is where I am having trouble.
intents = IntentDialog({recognizers: [apiairecognizer(CLIENT_TOKEN)]})
intents.matches('smalltalk', smalltalk_handler) // No luck
intents.matches(/smalltalk/, smalltalk_handler) // No luck
intents.onDefault(default_handler)
In the default_handler I capture the args:
{"score":1,
"intent":"smalltalk.greetings.how_are_you",
"entities": [
{
"entity":"Lovely, thanks.",
"type":"fulfillment",
"startIndex":-1,
"endIndex":-1,
"score":1
},
{
"entity":false,
"type":"actionIncomplete",
"startIndex":-1,
"endIndex":-1,
"score":1
}
]}
This makes sense according to the documentation of how matches works.
But that does mean that I don't know how to actually use the full list of intents, without explicitly copying every single intent in.
Just to clarify, if I use the exact intent:
intents.matches('smalltalk.greetings.how_are_you', smalltalk_handler)
I receive the nice response: Lovely, thanks.
Any suggestions?
So far, the only thing I have come up with is to modify the api-ai-recognizer such that it will return only smalltalk as intent, whenever it encounters a version of it. This way the intent dialog only needs to recognize one intent. Because they are handled in the same way, it doesn't matter at this point.