Je construis une application Assistant pour Google Home à l'aide de Dialogflow, Cloud Functions et de la nouvelle NodeJS Client Library V2 pour Actions sur Google. En fait, je suis en train de migrer mon ancien code construit avec V1 vers V2.
Le contexte
J'essaie d'obtenir l'emplacement de l'utilisateur à l'aide de deux intentions distinctes: Request Permission
(intention qui déclenche/envoyer une demande d'autorisation à l'utilisateur) et User Info
(intention qui vérifie si l'utilisateur a donné l'autorisation, puis renvoie les données demandées par l'assistant pour continuer.
Le problème
Le problème est que le même code qui fonctionnait parfaitement sous V1 ne fonctionne pas sous V2. J'ai donc dû refactoriser. Et lorsque je déploie ma fonction cloud, je peux demander l'autorisation de l'utilisateur, obtenir son emplacement, puis utiliser une bibliothèque externe (geocode
), je peux convertir le dernier en forme lisible par l'homme. mais pour certaines raisons (je pense que ses promesses), je ne peux pas résoudre l'objet de promesse et le montrer à l'utilisateur
L'erreur
Je reçois l'erreur ci-dessous:
Le code
Ci-dessous, le code de fonction de mon nuage. J'ai essayé plusieurs versions de ce code, en utilisant la bibliothèque request
, la bibliothèque https
, etc. Pas de chance ... Pas de chance
const {dialogflow, Suggestions,SimpleResponse,Permission} = require('actions-on-google')
const functions = require('firebase-functions');
const geocoder = require('geocoder');
const app = dialogflow({ debug: true });
app.middleware((conv) => {
conv.hasScreen =
conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT');
conv.hasAudioPlayback =
conv.surface.capabilities.has('actions.capability.AUDIO_OUTPUT');
});
function requestPermission(conv) {
conv.ask(new Permission({
context: 'To know who and where you are',
permissions: ['NAME','DEVICE_PRECISE_LOCATION']
}));
}
function userInfo ( conv, params, granted) {
if (!conv.arguments.get('PERMISSION')) {
// Note: Currently, precise locaton only returns lat/lng coordinates on phones and lat/lng coordinates
// and a geocoded address on voice-activated speakers.
// Coarse location only works on voice-activated speakers.
conv.ask(new SimpleResponse({
speech:'Sorry, I could not find you',
text: 'Sorry, I could not find you'
}))
conv.ask(new Suggestions(['Locate Me', 'Back to Menu',' Quit']))
}
if (conv.arguments.get('PERMISSION')) {
const permission = conv.arguments.get('PERMISSION'); // also retrievable with explicit arguments.get
console.log('User: ' + conv.user)
console.log('PERMISSION: ' + permission)
const location = conv.device.location.coordinates
console.log('Location ' + JSON.stringify(location))
// Reverse Geocoding
geocoder.reverseGeocode(location.latitude,location.longitude,(err,data) => {
if (err) {
console.log(err)
}
// console.log('geocoded: ' + JSON.stringify(data))
console.log('geocoded: ' + JSON.stringify(data.results[0].formatted_address))
conv.ask(new SimpleResponse({
speech:'You currently at ' + data.results[0].formatted_address + '. What would you like to do now?',
text: 'You currently at ' + data.results[0].formatted_address + '.'
}))
conv.ask(new Suggestions(['Back to Menu', 'Learn More', 'Quit']))
})
}
}
app.intent('Request Permission', requestPermission);
app.intent('User Info', userInfo);
exports.myCloudFunction = functions.https.onRequest(app);
Toute aide est fortement appréciée. Merci
Vous avez raison à votre dernière hypothèse - votre problème est que vous n'utilisez pas les promesses.
app.intent()
s'attend à ce que la fonction de gestionnaire (userInfo
dans votre cas) renvoie une promesse si elle utilise des appels asynchrones. (Si vous ne l'êtes pas, vous pouvez vous en tirer sans rien retourner.)
Le processus normal consiste à utiliser quelque chose qui retourne une promesse. Cependant, ceci est délicat dans votre cas car la bibliothèque de géocodes n’a pas été mise à jour pour utiliser Promises et vous avez un autre code qui dans la fonction userInfo
ne renvoie rien.
Une réécriture dans ce cas pourrait ressembler à ceci (je n’ai cependant pas testé le code). Dans ce document, je divise les deux conditions de userInfo
en deux autres fonctions afin que l’on puisse renvoyer une promesse.
function userInfoNotFound( conv, params, granted ){
// Note: Currently, precise locaton only returns lat/lng coordinates on phones and lat/lng coordinates
// and a geocoded address on voice-activated speakers.
// Coarse location only works on voice-activated speakers.
conv.ask(new SimpleResponse({
speech:'Sorry, I could not find you',
text: 'Sorry, I could not find you'
}))
conv.ask(new Suggestions(['Locate Me', 'Back to Menu',' Quit']))
}
function userInfoFound( conv, params, granted ){
const permission = conv.arguments.get('PERMISSION'); // also retrievable with explicit arguments.get
console.log('User: ' + conv.user)
console.log('PERMISSION: ' + permission)
const location = conv.device.location.coordinates
console.log('Location ' + JSON.stringify(location))
return new Promise( function( resolve, reject ){
// Reverse Geocoding
geocoder.reverseGeocode(location.latitude,location.longitude,(err,data) => {
if (err) {
console.log(err)
reject( err );
} else {
// console.log('geocoded: ' + JSON.stringify(data))
console.log('geocoded: ' + JSON.stringify(data.results[0].formatted_address))
conv.ask(new SimpleResponse({
speech:'You currently at ' + data.results[0].formatted_address + '. What would you like to do now?',
text: 'You currently at ' + data.results[0].formatted_address + '.'
}))
conv.ask(new Suggestions(['Back to Menu', 'Learn More', 'Quit']))
resolve()
}
})
});
}
function userInfo ( conv, params, granted) {
if (conv.arguments.get('PERMISSION')) {
return userInfoFound( conv, params, granted );
} else {
return userInfoNotFound( conv, params, granted );
}
}
Grâce à @Prisoner, j'ai pu le faire fonctionner. Je n'ai pas eu à modifier ma structure Dialogflow ou quoi que ce soit. Tout ce que je devais faire était de changer la section de géocodage inversé comme suggéré par @Prisoner. Et cela a fonctionné pour moi.
//Reverse Geocoding
return new Promise( function( resolve, reject ){
// Reverse Geocoding
geocoder.reverseGeocode(location.latitude,location.longitude,(err,data) => {
if (err) {
console.log(err)
reject( err );
} else {
// console.log('geocoded: ' + JSON.stringify(data))
console.log('geocoded: ' + JSON.stringify(data.results[0].formatted_address))
conv.ask(new SimpleResponse({
speech:'You currently at ' + data.results[0].formatted_address + '. What would you like to do now?',
text: 'You currently at ' + data.results[0].formatted_address + '.'
}))
conv.ask(new Suggestions(['Back to Menu', 'Learn More', 'Quit']))
resolve()
}
})
});
Je peux maintenant passer à autre chose!