web-dev-qa-db-fra.com

Erreur: Aucune réponse n'a été définie. Fonctions cloud pour les actions sur Google Assistant

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: 

 enter image description here

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

8
AllJs

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 );
  }
}
10
Prisoner

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! 

2
AllJs