Reputation: 121
I am using the Dialogflow Inline editor to make a call to an API. When I use console.log to log some of the data from the API it works. However, when I use agent.add with the same variable it gives an error.
I read some other stackoverflows about this issue where people used a promise and resolve call. I have tried to implement this in my code. However, I'm not sure if I've used it in the right way.
This is my code:
'use strict';
const axios = require('axios');
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 randomHandler(agent){
const regio = agent.parameters.regio;
if (regio != "Alkmaar" && regio != "Schiphol"){
agent.add(`Deze regio bestaat helaas niet binnen NH nieuws, kies een andere regio of kies voor het nieuws uit heel Noord-Holland`);
} else {
return axios.get(`https://api.datamuse.com/words?rel_rhy=book`)
.then((result) => {
result.data.map (res => {
const dataArray = ""; // An array with the results. However we got it
const words = dataArray.map( entry => entry.word ); // Get just the "word" field from each entry in the dataArray
const wordsString = words.join(', '); // Put commas in between each word
agent.add( `The results are: ${wordsString}`);
});
});
}
}
// 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('random', randomHandler);
agent.handleRequest(intentMap);
});
and this is my package.json:
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "10"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^5.13.1",
"firebase-functions": "^2.0.2",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0",
"axios" : "0.20.0"
}
}
Upvotes: 1
Views: 846
Reputation: 121
Solved, the problem was that I called the agent.add more than 2 times (which is the maximum). This code works for me:
const { conversation } = require('@assistant/conversation');
const functions = require('firebase-functions');
const axios = require('axios').default;
const app = conversation();
var titels = [];
axios.get(`YOUR-API`)
.then((result)=> {
titels.push(result.data.categories[0].news[0].title);
/* result.data.map(wordObj => {
titels.push(wordObj.categories.news.title);
});*/
});
app.handle('rhymeHandler', conv => {
console.log(titels[0]);
conv.add(titels[0]);
});
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
/* for (i = 1; i < 4; i++) {
conv.add(words[i]);
} */
//console.log(words);
Upvotes: 1
Reputation: 50701
As you suspected - the problem is with Promises.
rhymingWordHandler()
has an asynchronous operation in it (the web call using axios), but you're not returning a Promise.
Fortunately, axios.get()
does return a Promise. You can tell because you're calling .then()
on what is returned, and .then()
also returns a Promise and so forth. I like to this of this as a "Promise-chain". Changing this to return a Promise is relatively simple:
return axios.get(`https://api.datamuse.com/words?rel_rhy=${word}`)
.then( /* and so forth */ )
However, this isn't quite enough with your code. You don't need to create a Promise inside the .then()
function, and doing so only confuses things.
Remember that Intent names are case sensitive - you need to use the exact same capitalization in both the name that you have in the UI as well as the name you use for intentMap.set()
. You currently have "Rhymingword" in one place and "RhymingWord" in the other (one W is capitalized, the other isn't).
You also may have a minor problem that you may not be able to call agent.add(rhyme)
multiple times. Some agents can only handle one or two text responses. Instead, you'll need to build the response string from the array of results.
How to build a string like this depends on your exact content. The easiest (although not grammatically correct) is to just put commas in between them. I often do them in steps, so it might look like this:
const dataArray = // An array with the results. However we got it
const words = dataArray.map( entry => entry.word ); // Get just the "word" field from each entry in the dataArray
const wordsString = words.join(', '); // Put commas in between each word
agent.add( `The results are: ${wordsString}`. );
There are lots of problems with this, and a good solution would handle cases such as:
But this should be a start to making sure you call agent.add()
just once.
Upvotes: 2