Error: No response has been set. Cloud Functions for Actions on Google Assistant

Error: No response has been set. Cloud Functions for Actions on Google Assistant

我正在为 Google 主页构建一个 Assistant 应用程序,使用 DialogflowCloud Functions 和新的 NodeJS 客户端 库 V2,用于 Google 上的 Actions。事实上,我正在将使用 V1 构建的旧代码迁移到 V2。

背景

我正在尝试使用两个单独的意图获取用户的位置:Request Permission(向用户请求 triggers/send 权限的意图)和 User Info(检查用户是否授予权限,然后 returns 助手请求的数据继续。

问题

问题是在 V1 上运行良好的相同代码在 V2 上运行不正常。所以我不得不做一些重构。当我部署我的云函数时,我能够成功请求用户的许可,获取他的位置,然后使用外部库 (geocode),我可以将 latlong 转换为人类可读的形式。但由于某些原因(我认为它的承诺)我无法解析承诺对象并将其显示给用户

错误

我收到以下错误:

代码

下面是我的云函数代码。我尝试了此代码的多个版本,使用 request 库、https 库等。运气不好……运气不好

    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);

非常感谢任何帮助。谢谢

您最后的猜测是正确的 - 您的问题是您没有使用 Promises。

如果使用异步调用,

app.intent() 期望处理函数(在您的情况下为 userInfo)return Promise。 (如果你不是,你可以 return 什么都不做。)

正常的做法是使用 returnPromise。但是,这在您的情况下很棘手,因为地理编码库尚未更新为使用 Promises,并且您在 userInfo 函数中有其他代码没有 return 任何东西。

在这种情况下重写可能看起来像这样(但是我还没有测试代码)。在其中,我将 userInfo 中的两个条件分解为另外两个函数,因此可以 return 一个 Promise。

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

多亏了@Prisoner,我才能够让它发挥作用。我不必修改我的 Dialogflow 结构或任何东西。我所要做的就是将反向地理编码部分更改为@Prisoner 建议的内容。它对我有用。

//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()
      }
   })
});

我现在可以继续做其他事情了!