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

How to get user confirmation for Location and the geo-coordinates in Dialogflow?

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

我需要添加任何意图来确认吗?我在默认欢迎意图中请求位置权限。

代码如下:

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

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

在这种情况下,它将是您的 "confirmation" 意图。

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

我拥有的一个(具有 result.location 的 Intent 名称和 Action)如下所示:

附带说明一下,在您的处理程序中,您试图获取用户名,但除非您已请求许可,否则此名称不可用。你没有征求许可。如果你愿意,你可以在询问他们的位置的同时请求许可,例如

app.askForPermissions("To show your address", [
  app.SupportedPermissions.NAME,
  app.SupportedPermissions.DEVICE_PRECISE_LOCATION
]);

根据您的屏幕截图更新

不清楚你的对话流程是什么意思,所以我做了一些假设。

但是根据您的代码,您请求的许可是出于欢迎意图。然后用户授予权限,您需要一个接受该回复的意图。

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

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

您似乎也在创建上下文,尽管不清楚原因。

根据您发布的代码和您的补充评论更新

代码中有几个问题可能会导致您遇到一些问题,而其他一些问题可能会在将来给您带来麻烦。在评论中回答您的一些问题和一些未提出的问题:

我启用了 Small Talk

这不会造成任何伤害 - 但它可能也无济于事。我建议您禁用它,直到您的对话的核心部分正常工作。

我可以得到坐标

很好 - Intent 正在运行。

但是...

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

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

您想要的是一种在两次调用您的 webhook 之间存储用户信息的方法。 elsewhere 涵盖了很多方法,而且可以相当复杂。但是,一般来说,您可以将值存储在上下文中或 app.data 中,它们将作为同一对话的一部分返回给您。

我第一次询问时没有得到目标地址第二次询问时,有目的地址

您的函数 makeDirection() 包含一个异步操作以获取目标地址的 lat/lon,但是您正在该异步块之外发回回复。

所以发生的事情是您开始 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 是合法的,但试图将其分解以获得特定值并不是最佳做法,尤其是因为用户可能不会准确地说出您认为他们会说的内容。例如,如果他们说 "I'm heading towards somewhere".

怎么办?

更好的方法是让您的 direction_action Intent 采用各种不同的短语并将其中的 "important" 部分(目标)分配给一个参数。然后,在您的 webhook 中,您可以只读取参数的值并将其传递给服务以确定位置。

你也不妨看看最近发布的Place Helper,它类似于设备精确定位助手,但也可以获取用户指定的地址。