I want to make sure my handler returns "speakoutput" after it receives the result from IBM Watson API. When my code calls IBM API, it will directly jump to "return handlerInput.responseBuilder", because it takes some time for IBM API to analyze the input text.
I tried "await", "promise", but it was not working for my case. "Await" and "promise" could make sure I receive the result from API, but it never prevent my code from jumping to the next line before it finish the API call.
How do I solve this problem?
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
var speakoutput ='';
//IBM API HERE
var NaturalLanguageUnderstandingV1 = require('watson-developer-cloud/natural-language-understanding/v1.js');
var nlu = new NaturalLanguageUnderstandingV1({
iam_apikey: 'my_api_key',
version: '2018-04-05',
url: 'https://gateway.watsonplatform.net/natural-language- understanding/api/'
});
//nlu.analyze takes a lot of time to process
nlu.analyze(
{
html: 'Leonardo DiCaprio won Best Actor in a Leading Role for his performance', // Buffer or String
features: {
//concepts: {},
'keywords': {},
'relations': {},
'sentiment': {
'targets': [
'in'
]
}
}
},
function(err, response) {
if (err) {
console.log('error:', err);
} else {
//console.log(JSON.stringify(response, null, 2));
var temparray = [];
for (i in response.keywords){
speakoutput +=response.keywords[i].text;
console.log(JSON.stringify(response.keywords[i].text, null, 2));
temparray.push(response.keywords[i].text);
}
console.log(temparray);
}
}
);
//my code will jump to this part before it finishes "nlu.analyze"
return handlerInput.responseBuilder
.speak(speakoutput)
.reprompt('What do you want to know? you could search data for atm, course search, fed events,')
.getResponse();
},
};
Convert the cb to a promise and return the promise chain as your handle
function. Whatever calls handle
must also use .then()
or await
Example of an aync handle()
can be found at https://github.com/alexa/skill-sample-nodejs-city-guide/blob/master/lambda/custom/index.js
const GoOutHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'GoOutIntent';
},
handle(handlerInput) {
return new Promise((resolve) => {
getWeather((localTime, currentTemp, currentCondition) => {
const speechOutput = `It is ${localTime
} and the weather in ${data.city
} is ${
currentTemp} and ${currentCondition}`;
resolve(handlerInput.responseBuilder.speak(speechOutput).getResponse());
});
});
},
};
So for yours:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
//nlu.analyze takes a lot of time to process
return (new Promise(function(resolve,reject){ // convert cb to promise
var speakoutput ='';
//IBM API HERE
var NaturalLanguageUnderstandingV1 = require('watson-developer-cloud/natural-language-understanding/v1.js');
var nlu = new NaturalLanguageUnderstandingV1({
iam_apikey: 'my_api_key',
version: '2018-04-05',
url: 'https://gateway.watsonplatform.net/natural-language- understanding/api/'
});
nlu.analyze(
{
html: 'Leonardo DiCaprio won Best Actor in a Leading Role for his performance', // Buffer or String
features: {
//concepts: {},
'keywords': {},
'relations': {},
'sentiment': {
'targets': [
'in'
]
}
}
},
function(err, response) {
if (err) {
reject(err);
} else {
//console.log(JSON.stringify(response, null, 2));
var temparray = [];
for (i in response.keywords){
speakoutput +=response.keywords[i].text;
console.log(JSON.stringify(response.keywords[i].text, null, 2));
temparray.push(response.keywords[i].text);
}
console.log(temparray);
resolve(handlerInput.responseBuilder
.speak(speakoutput)
.reprompt('What do you want to know? you could search data for atm, course search, fed events,')
.getResponse());
}
}
);
}))
},
};