Since I upgraded my Dialogflow to use v2 API, I get the following error:
Dialogflow IntentHandler not found for intent: myIntent
For some reasons, my intent is no longer recognized altough the action name is identical - myIntent.
This is how I'm using my NodeJS (express V4) app to return a response:
dialogflowApp.intent('myIntent', (conv, {version}) => {
conv.close('test');
});
What could have gone wrong?
Make sure that myIntent is spelled the same in Dialogflow and in your NodeJS webhook function, otherwise you'll get this error. This is how I write and access my functions in the webhook:
//Function execution
dialogflowApp.intent('myIntent', myIntentFunction);
//Function definition
function myIntentFunction(conv, {version}){
conv.close('test');
}
V2 Actions SDK uses the Intent name instead of the Action Name. The Intent name can be found in your request, or directly from DialogFlow intent interface
DialogFlow V1 to V2 Migration Documentation
In V2 you have to use the intent name instead of the action name. First you define this at the beginning of the index file:
'use strict';
const {dialogflow} = require('actions-on-google');
const functions = require('firebase-functions');
const app = dialogflow({debug: true});
Then you have to add the code for each intent:
app.intent('intentName1', (conv, {parameterName}) => {
conv.close('Answer text');
});
app.intent('intentName2', (conv, {parameterName}) => {
conv.ask('Answer text');
});
Finally, at the end of the index file, it is necessary to set the DialogflowApp object to handle the HTTPS POST request. Like this:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
In your example:
dialogflowApp.intent('myIntent', (conv, {version}) => {
conv.close('test');
});
You should check that you have defined 'dialogflowApp' at the begining of index file:
const dialogflowApp = dialogflow({debug: true});
Then you have two options:
Replace 'myIntent' with the name of the intent
Change your intent name to be 'myIntent'
IMPORTANT: You have to make sure that the intent name in dialogflow and that in the code are exactly the same, since it is case sentive.
'version' should be the name of a parameter received from that intent.
Also check that you have this at the end of the index file:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(dialogflowApp);
Hope this can help! :)
Try to put your intent handler outside your express '/' post route:
dialogflowApp.intent('myIntent', (conv, {version}) => {
conv.close('test');
});
express().post('/', function(req, res)) {
})
According to this comment on Github, Actions-on-Google V2 does not match on the action, but instead matches on the intent.name. I have yet to find a smooth way of finding the name property of a Dialogfow intent, but I have been able to find it by looking at the Diagnostic info after testing it in the right column.
Note: What you named the intent at the top of the screen is the Display Name, not the name.
Update: Part of the intent.name can be found in the URL after opening the intent. The intent.name currently is given in the following format:
projects/<username>/agent/intents/<intent-uuid>
The intent-uuid can be found in the last part of the path:
https://console.dialogflow.com/api-client/#/agent/<agent-uuid>/editIntent/<intent-uuid>/
While this is also not ideal either, it can make things a little easier.
Try also to remove space from the intent name defined in DialogFlow and in your javascript function call. This solve the problem in my case (running in a Azure function)
before :
app.intent('Open Car Gate', conv => {
conv.close('OK, je vais ouvrir le portail en grand !');
});
after :
app.intent('OpenCarGate', conv => {
conv.close('OK, je vais ouvrir le portail en grand !');
});
Related
I need some help in creating the fulfillment for the intents that i have created in Dialog flow. There are 15 intents that i have created and i have integrated them and tested and it works fine. I am stuck in fulfillment and unable to proceed since i am confused whether the fulfillment setup. Since has to be done for every intent that i have created i believe. I am unsure how to do this to complete by one click using fulfillment link on the left pane. does it work if i just directly click on fulfillment and deploy. I am really confused. Please help me out.
Setting up Fulfillment is a multi-step process.
Enabling Fulfillment
Select Fulfillment on the left navigation
If your fulfillment code will be running at a remote webhook, enable "Webhook" and enter the URL for your webhook.
If you don't have a place to run your fulfillment code, you can also use the Inline Editor to get started. Enable this, and you'll be entering your code here directly.
Save the configuration.
Enabling for each Intent
While this sets the Fulfillment that will be used for your project, you must still enable this for each Intent that should call it.
Go back to the Intent listing and select an Intent.
Scroll towards the bottom of the page in the Fulfillment section.
Turn "Enable webhook call for this intent" on.
Save the configuration.
Repeat this for every Intent that you want to process using Fulfillment.
Deploying your webhook
You will also need to write your webhook to handle the various Intents that are triggered. The code for the Inline Editor can be a good place to start.
In the intentMap, you will need to add a map from the Intent name to a function that will do the handling when that Intent triggers the webhook. You can have a different handler function for each Intent, use the same function for some, have those functions call other functions, whatever you need.
A couple of things to note, however:
If your handler needs to do an asynchronous function (access a database, make a network call, etc), then you need to make sure you return a Promise.
If you're using the Inline Editor and you're making network calls outside of Google's network, then you need to upgrade your Firebase subscription to the Blaze plan. (You will still likely be able to work with the free tier of that plan.)
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function handlerOne(agent) {
agent.add(`This is handler one`);
}
function handlerThree(agent) {
agent.add(`This is handler three`);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('intent.one', handlerOne);
intentMap.set('intent.two', handlerOne);
intentMap.set('intent.three', handlerThree);
agent.handleRequest(intentMap);
});
You can create a map in the API, where all intent will be mapped to a correspondence handler in fulfillment.
Here is sample code,
const express = require("express");
const { WebhookClient } = require("dialogflow-fulfillment");
const { welcome, defaultFallback } = require("./intents/welcomeExit");
const app = express();
app.post("/dialogflow", express.json(), (req, res) => {
const agent = new WebhookClient({ request: req, response: res });
let intentMap = new Map();
intentMap.set("Default Welcome Intent", welcome);
intentMap.set("Default Fallback Intent", defaultFallback);
agent.handleRequest(intentMap);
});
app.listen(process.env.PORT || 8080);
This has been done in NodeJS. You can use other languages supported by Dialogflow.
How it gets configured in Dialogflow check this link.
I want to run this code in dialogflow ,basically i want to use if condition
for example.
if my intent "Done" reply response [Text Response] =>'Now add 2 more and say got it' then
it switch to my another intent called "alright" so the response should be "you no. is 1" and end the converstation.
similary
if my intent "Done" reply response [Text Response] =>'Now add 4 more and say got it' then
it switch to my another intent called "alright" so the response should be "you no. is 2" and end the converstation.
and goes on.
just look at the SS Below
enter image description here
enter image description here
'use strict';
// Import the Dialogflow module from the Actions on Google client library.
const {dialogflow} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});
var numr=0;
app.intent('done',(conv,output)=>{
if(conv.ask ==='Now add 2 more, and say got it'){
numr=1;
return numr;
}
else{
numr=2;
return numr;
}
});
app.intent('Alright',(conv)=>{
conv.close('your number is '+ numr);
});
// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
There are a number of issues with your code that make it difficult to understand exactly what you're doing. However, there are a few things to note. I'm assuming you're using JavaScript here.
You have a syntax error in how you are using else. The else statement should be followed by an execution block. You look like you're following it with a condition. Perhaps you are trying to use else if there?
conv.ask is a function. You're then assigning a string to it which would remove it as a function. I don't think this is what you mean to do here.
In the Intent Handler for the "done" Intent, you're not sending anything back to the user using the conv.ask() function since you just removed that as a function.
Setting a global variable does not guarantee the value of it will be preserved in between Intent Handler calls. If you want a value saved during a conversation, you should use a Context or conv.data or other means.
How do I end my conversation from the webhook ?
Marking it within Dialogflow does nothing , basically does not stop it as I am using the webhook for fulfillment .
And if I add it to the code as below then it does not play the media.
// Import the Dialogflow module from the Actions on Google client library.
// https://github.com/actions-on-google/actions-on-google-nodejs
const {dialogflow, Suggestions, MediaObject, Image} = require('actions-on-google');
// Import the firebase-functions package for Cloud Functions for Firebase fulfillment.
const functions = require('firebase-functions');
// Node util module used for creating dynamic strings
const util = require('util');
// Instantiate the Dialogflow client with debug logging enabled.
const app = dialogflow({
debug: true
});
// Do common tasks for each intent invocation
app.middleware((conv, framework) => {
console.log(`Intent=${conv.intent}`);
console.log(`Type=${conv.input.type}`);
//kng
console.log(`Arguments=${conv.arguments}`);
console.log(`Arguments=${typeof(conv.arguments)}`);
// Determine if the user input is by voice
conv.voice = conv.input.type === 'VOICE';
if (!(conv.intent === 'Default Fallback Intent' || conv.intent === 'No-input')) {
// Reset the fallback counter for error handling
conv.data.fallbackCount = 0;
}
});
app.intent('Play Sound', (conv, {SoundType,duration}) => {
const suggestions1 = new Suggestions('do this ', 'do that', 'do nothing');
simple_response = 'this is a response from the webhook'
conv.ask(simple_response)
conv.ask(new MediaObject({
name: SoundType,
url: some_mp3file_url,
icon: new Image({
url: some_image_url,
alt: 'Media icon'
})
}));
conv.ask( suggestions1);
//if I close from the code it doesnot play the sound
conv.close();
//if I comment out the close statement above then it does not close and toggling on the "set this intent as the end of convesation does not seem to help."
}
)
Update - This was intact a bug as pointed out by one of the comments . Reported to google and they fixed the same in April or May
I can duplicate the issue, but it appears to be a bug - playing audio as part of the response and having it close after the audio finishes used to work. It is clearly supposed to be supported - the documentation and the simulator state that Suggestions aren't required if this is a final response.
The workaround is to create an additional Intent that handles the Action actions_intent_MEDIA_STATUS. This Intent would then close the conversation.
I'm trying to create custom fallbacks for intents that contain confirmations. Here is the code:
const functions = require('firebase-functions');
const {
dialogflow,
Confirmation
} = require('actions-on-google');
const app = dialogflow({
debug: true,
});
app.intent('vitals-confirmation', (conv, input, confirmation) => {
conv.ask(new Confirmation(`Great! Have you fainted recently?`));
});
app.intent('vitals-confirmation-fallback', (conv, input, confirmation) => {
conv.ask(new Confirmation(`Sorry I didn't understand what you said. Did you faint?`));
})
app.intent('S1-confirmation', (conv, input, confirmation) => {
if (confirmation) {
conv.ask(new Confirmation(`I have recorded that you have fainted. Have your feet been hurting?`));
} else {
conv.ask(new Confirmation(`I have recorded that you have not fainted. Have your feet been hurting?`));
}
});
My app asks the user if they have fainted in "vitals-confirmation" and the user is expected to answer with a yes or no type answer that will be identified by the confirmation helper, if they do this correctly they will go to "S1-confirmation" and will be asked the next question.
However the following is outputted when I respond with an answer that is not a yes/no type answer (for example: "red"):
Sorry, Great! Have you fainted recently?
It seems as though there is a default fallback that responds with "Sorry, [repeats previous text output]" and does not go to a custom fallback intent which I have created (which is my desired result).
Take a look at the documentation for Confirmation helper of Actions SDK for Node.js.
You have to setup an intent with the actions_intent_CONFIRMATION event in DialogFlow in order to retrieve the user response. My advice is to check how you configured your intents and use this method, otherwise be sure to create the follow-up intents with the desired context lifespan.
Example from documentation:
app.intent('Default Welcome Intent', conv => {
conv.ask(new Confirmation('Are you sure you want to do that?'))
})
// Create a Dialogflow intent with the `actions_intent_CONFIRMATION` event
app.intent('Get Confirmation', (conv, input, confirmation) => {
if (confirmation) {
conv.close(`Great! I'm glad you want to do it!`)
} else {
conv.close(`That's okay. Let's not do it now.`)
}
})
I am trying to build a simple chatbot with DialogFlow.
My aim is to give information from user question, like : where can I slackline above water in croatia ? I have two parameters (croatia, waterline) and a list of slackline places.
So I need a data base to retrieve information from parameters. DialogFlow allows fulfillment with Firebase. I build a database with places (name, country, type of slack) and enable webhook call for my intent.
I use Inline Editor and index.js
const parameters = request.body.queryResult.parameters;
var country = parameters.country.toString();
function show(snap) {
console.log('snap');
agent.add(JSON.stringify(snap.val(),null,2));
}
function slkplc(agent) {
var testRef;
firebase.database().ref('slackplace').once('value',show);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('slack place', slkplc);
agent.handleRequest(intentMap);
But I do not get the expected result while trying it on DialogFlow or Google Assistant. The function show is asynchronously called but too late and the response is not available for DialogFlow :
I see three way to deal with this problem :
use blocking call to database : another database ?
treat asynchronous message with DialogFlow ???
response to user that an error occured.
The third that I choose, but it is always on error.
After trying several things to wait data from database response, the only thing I managed is to freeze the response, therefore the timeout of DialogFlow - 5s -and Firebase - 60s - were reached.
A workaround
Another way to do it is to separate database acquisition and request/response from DialogFlow. The data of database is collected outside of the dialogflowFirebaseFulfillment
var data;
var inidata = firebase.database().ref().on('value',function(snap) {
console.log('snap');
data = snap.val();
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
...
function slkplc(agent) {
agent.add(JSON.stringify(data,null,2));
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('slack place', slkplc);
agent.handleRequest(intentMap);
}
Now I can do what I want with data, and I am able to find the place where I can practice waterline in croatia. But there is always something weird, the data of the database is duplicated ...
The "right" solution is option 2 that you suggest: since you're doing an asynchronous call, you need to handle this correctly when working with the dialogflow-fulfillment library.
Basically, if your handler makes an asynchronous call, it needs to be asynchronous as well. To indicate to the handleRequest() method that your handler is async, you need to return a Promise object.
Firebase's once() method returns a Promise if you don't pass it a callback function. You can take advantage of this, return that Promise, and also handle what you want it to do as part of a .then() clause. It might look something like this:
function slkplc(agent) {
var testRef;
return firebase.database().ref('slackplace').once('value')
.then( snap => {
var val = snap.val();
return agent.add( JSON.stringify( val, null, 2 ) );
});
}
The important part isn't just that you use a Promise, but also that you return that Promise.