如何在Dialogflow中获取位置和地理坐标的用户确认?

时间:2018-04-01 12:40:28

标签: firebase webhooks actions-on-google dialogflow

我正在使用对话框流程为Google助手制作应用。我的应用程序使用部署在firebase上的webhook功能。主要问题是如何获取用户位置 - 我需要将坐标传递给URL。我可以提示消息获取位置权限,但是如何确认并获取坐标。

我是否需要添加任何确认意图?我要求默认欢迎意图中的位置许可。JEP 286: Scoping Choices enter image description here enter image description here enter image description here enter image description here

代码如下:

'use strict';

process.env.DEBUG = 'actions-on-google:*';
const App = require('actions-on-google').DialogflowApp;

const functions = require('firebase-functions');



//----global variables-----
const http = require('https');
var body = "";
var body2="";
var address="";
var latitude="";
var longitude="";
var lati="";
var long="";


//------ADDRESS_ACTION to tell the current address based on current coordinates----
const ADDRESS_ACTION = 'address_action';

//-----DIRECTION_INTENT to output the map guidence through basic card------
const DIRECTION_INTENT = 'direction_action';

//--------during welcome intent, ask the permiisions------
const DIR_PERMISS_CONF= 'intent.welcome';

exports.addressMaker = functions.https.onRequest((request, response) => {
  const app = new App({request, response});
  console.log('Request headers: ' + JSON.stringify(request.headers));
  console.log('Request body: ' + JSON.stringify(request.body));


  function welcomeIntentDirection (app) 
  {
    app.askForPermission("Hi! Welcome to !To show address/direction",app.SupportedPermissions.DEVICE_PRECISE_LOCATION);
    if (app.isPermissionGranted()) 
    {
     // app.tell('You said ' + app.getRawInput());
    }
    else
    {
     // app.tell('You said ' + app.getRawInput());
    }

  }



function makeDirection(app)
{

  //-------here we are extraction what user said, we will extract the place name, it is for "direction to PLACE_NAME"-------

  var stringRequest=JSON.stringify(request.body);
  var jsonRequest=JSON.parse(stringRequest);
  var jsonSpeech=jsonRequest.originalRequest.data.inputs[0].rawInputs[0].query;
  var arr=jsonSpeech.split("to");
  var placeName=arr[1].trim();

  //------Current Location--------------
  let deviceCoordinates = app.getDeviceLocation().coordinates;
  latitude=deviceCoordinates.latitude;
  longitude=deviceCoordinates.longitude;



//-----now send this place name to api to get coordinates-----
 var req2= http.get("https://api.url-with-PARAMETER-placeName",function(res){

  res.on("data", function(chunk2){ body2 += chunk2;  });
  res.on('end', function()
  {
    if (res.statusCode === 200) 
    {
      var data2 = JSON.parse(body2);

      try
      {
          lati=data2.geometry.lat;
          long=data2.geometry.lng;
      }catch(e){app.tell("Invalid or non-existent address");}    
    }
  });
});


//-------------------Here BUILDING the CARD (Rich RESPONSE)-----------------------
  app.ask(app.buildRichResponse()
    // Create a basic card and add it to the rich response
    .addSimpleResponse('Your directions are here:')
    .addBasicCard(app.buildBasicCard()

      .addButton('Start Guidence', 'https://www.google.com/maps/dir/?api=1&origin='+latitude+','+longitude+'&destination='+lati+','+long+'')
      .setImage('https://png.pngtree.com/element_origin_min_pic/16/11/30/a535f05d9d512610e25a036b50da036f.jpg', 'Image alternate text')
      .setImageDisplay('CROPPED')
  )
);

}


  function makeAddress (app) 
      {
        let deviceCoordinates = app.getDeviceLocation().coordinates;
        latitude=deviceCoordinates.latitude;
        longitude=deviceCoordinates.longitude;
        var req=http.get("https://api.url/reverse?coords="+latitude+","+longitude+"", 
        function(res)
        {
          res.on("data", function(chunk){ body += chunk;  });

          res.on('end', function()
          {
            if (res.statusCode === 200) 
            {
                try 
                {
                  var data = JSON.parse(body);
                  address=data.words;
                  app.tell('Alright, your address is '+address);
                } catch (e) { }
            }
            else 
            {
              app.tell("Unable to contact to server +"+res.statusCode);
            }

          });

        });
      }

  // d. build an action map, which maps intent names to functions
  let actionMap = new Map();
  actionMap.set(DIR_PERMISS_CONF,welcomeIntentDirection);
  actionMap.set(ADDRESS_ACTION, makeAddress);
  actionMap.set(DIRECTION_INTENT, makeDirection);



app.handleRequest(actionMap);
});

1 个答案:

答案 0 :(得分:1)

是的,您需要一个Intent来处理来自用户的响应。 Dialogflow的模型是用户的所有响应都需要通过意图来处理。

在这种情况下,它将是您的“确认”意图。

您没有显示Intent的屏幕截图(如果您还有其他问题,请更新问题以包含它),但它需要处理事件actions_intent_PERMISSION。处理此活动时,您不需要任何培训短语。

我拥有的一个(具有Intent名称和result.location的动作)看起来像这样:

enter image description here

作为旁注,在您的处理程序中,您正在尝试获取用户名,但除非您要求获得权限,否则此名称不可用。你没有要求许可。如果你愿意,你可以在你用

之类的东西询问他们的位置时同意
app.askForPermissions("To show your address", [
  app.SupportedPermissions.NAME,
  app.SupportedPermissions.DEVICE_PRECISE_LOCATION
]);

根据您的屏幕截图更新

目前还不清楚你的谈话流程是什么,所以我做了一些假设。

但根据您的代码,您会因欢迎意图而要求获得许可。然后,用户授予权限,您需要一个接受该回复的意图。

我没有看到接受该回复的意图。

为了接受回复,您需要一个处理事件actions_intent_PERMISSION的Intent,正如我在上面的屏幕截图中所示。

您似乎也在创建上下文,但目前尚不清楚原因。

根据您发布的代码和其他评论

更新

代码存在一些问题,可能会导致您遇到的一些问题,以及可能导致您将来遇到问题的其他一些问题。在评论和一些未提出的问题中回答您的一些问题:

我启用了Small Talk

这并没有伤害任何东西 - 但它可能也没有任何帮助。我建议你禁用它,直到你的对话的核心部分工作。

我可以获得坐标

好 - 所以Intent正在工作。

但是...

我看到你将坐标存储在一个全局变量中。这适用于这种情况(但不完全,请参阅您的下一个问题),但如果不止一个人正在使用该操作,则不会扩展,因为值可能会在用户会话之间混淆。

换句话说:如果您在webhook中使用全局变量,则每个人都可以访问这些值。这非常糟糕。

您想要的是一种在您的webhook调用之间存储用户信息的方法。有许多方法可以涵盖elsewhere并且可以参与其中。但是,一般情况下,您可以将值存储在上下文或app.data中,并且它们将作为同一对话的一部分返回给您。

我第一次询问时,我没有收到目的地地址 和 当我第二次询问时,它有目的地地址

您的函数makeDirection()包含一个异步操作来获取目标地址的纬度/经度,但是您要在该异步块之外发送回复。

所以会发生什么是启动http调用,然后代码继续,并将回复发送给具有空目标的用户。稍后,回调完成并设置目的地,但第一次呼叫为时已晚。但是当你第二次调用它时,它会经历相同的例程(启动异步调用,然后在调用完成之前立即发回一些东西),但是之前运行的值被设置,因为你已经在全局变量中设置它们

要解决此问题,您需要将app.ask()作为异步回调的一部分进行调用。这可能看起来像这样:

http.get("https://api.url-with-PARAMETER-placeName",function(res){

  res.on("data", function(chunk2){ body2 += chunk2;  });
  res.on('end', function(){
    if (res.statusCode === 200){
      var data2 = JSON.parse(body2);

      try{
        lati=data2.geometry.lat;
        long=data2.geometry.lng;
        app.ask( 
          app.buildRichResponse()
            .addThingsToRichResponse()
        );
      } catch(e){
        app.tell("Invalid or non-existent address");
      }
    }
  });
});

获取用户对目的地的评论的问题

您尝试获取用户目的地的代码很奇怪。获得rawInputs是合法的,但试图将其拆分以获得特定值并非最佳做法,尤其是因为用户可能没有准确地说出您认为他们会说的内容。例如,如果他们说“我正朝着某个地方”会怎么样。

最好让你的direction_action意图采用各种不同的短语,并将其中的“重要”部分(目的地)分配给参数。然后,在您的webhook中,您可以只读取参数的值并将其传递给服务以确定位置。

您还可以查看最近公布的Place Helper,它与设备精确位置助手类似,但也获取用户指定的地址。