Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
799 views
in Technique[技术] by (71.8m points)

api ai - Google Assistant location permissions not stored between requests

With API.AI and the Google Assistant, I'm requesting permission to get the user's name and location. The intent is that I'll be able to ask for permission once, and subsequent requests to my Action will not need to ask again (since this will make for a very stilted conversation every time the user talks to my Action).

What I am finding is that I'm only getting the information in the intent tied to the actions_intent_PERMISSION - the information isn't sent in other intent fulfillments, even if I've already granted the permission. (In the example code below - it ends up re-requesting permission for all of the other intents.)

I'm also not seeing this permission maintained in between invocations of my Action. So every time the Action is triggered, they're (again) asked if they grant the action permission.

Both behaviors seem odd. Application models, in general, don't require me to re-authorize permission to a resource in between invocations of the application, or even while the application is "running". Even web pages preserve authorization during a session. Am I doing something wrong, or is this the behavior as intended?

Code that is doing the fulfillment (this is running in Google Cloud Functions and there is some additional structure that is making these calls through a Promise - this is just the relevant part of the code). The res.send(200) just indicates to API.AI that it should use the responses that are defined there, and that works without problems. The return Promise.resolve(null); just makes sure that other fallback/error conditions aren't executed.


exports.process = function( req, res ){
  var app = new ApiAiApp({request:req, response:res});

  if( app.isPermissionGranted() ){
    res.send( 200 );
    return Promise.resolve( null );
  } else {
    return askPermission( req, res, app );
  }
};

var askPermission = function( req, res, app ){
  //app.tell('foo');
  let namePermission = app.SupportedPermissions.NAME;
  let preciseLocationPermission = app.SupportedPermissions.DEVICE_PRECISE_LOCATION;

  // Ask for more than one permission. User can authorize all or none.
  app.askForPermissions('To address you by name and know your location',
    [namePermission, preciseLocationPermission]);
  return Promise.resolve( null );
};

The API.AI Intent that handles the actions_intent_PERMISSION request:

Location result

Another Intent that should have user/location payload, but which never gets called with that info

simple test

Screen shot from the Simulator demonstrating it always asks for permission, except when its specifically been granted:

simulator screen shot

The JSON sent when initially connecting:


{
 "originalRequest": {
  "source": "google",
  "version": "2",
  "data": {
   "isInSandbox": true,
   "surface": {
    "capabilities": [
     {
      "name": "actions.capability.AUDIO_OUTPUT"
     },
     {
      "name": "actions.capability.SCREEN_OUTPUT"
     }
    ]
   },
   "inputs": [
    {
     "rawInputs": [
      {
       "query": "talk to my test app",
       "inputType": "KEYBOARD"
      }
     ],
     "intent": "actions.intent.MAIN"
    }
   ],
   "user": {
    "locale": "en-US",
    "userId": "APhe68HKWmHGe9cojGOMrX9WKQ0l"
   },
   "device": {},
   "conversation": {
    "conversationId": "1499807128489",
    "type": "NEW"
   }
  }
 },
 "id": "7e301f85-4178-4be6-8b7c-408bad3ef62b",
 "timestamp": "2017-07-11T21:05:28.504Z",
 "lang": "en",
 "result": {
  "source": "agent",
  "resolvedQuery": "GOOGLE_ASSISTANT_WELCOME",
  "speech": "",
  "action": "input.welcome",
  "actionIncomplete": false,
  "parameters": {},
  "contexts": [
   {
    "name": "google_assistant_welcome",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "actions_capability_screen_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "actions_capability_audio_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "google_assistant_input_type_keyboard",
    "parameters": {},
    "lifespan": 0
   }
  ],
  "metadata": {
   "intentId": "f31e371a-db9e-4e00-8002-546ec14d40a9",
   "webhookUsed": "true",
   "webhookForSlotFillingUsed": "false",
   "nluResponseTime": 2,
   "intentName": "Default Welcome Intent"
  },
  "fulfillment": {
   "speech": "I'm not sure, I'm a little confused.",
   "messages": [
    {
     "type": 0,
     "speech": "I'm not sure, I'm a little confused."
    }
   ]
  },
  "score": 1
 },
 "status": {
  "code": 200,
  "errorType": "success"
 },
 "sessionId": "1499807128489"
}

The JSON sent after it asks for permission and I've granted it. As expected originalRequest.data.user has the name and originalRequest.data.device now has the location.


{
 "originalRequest": {
  "source": "google",
  "version": "2",
  "data": {
   "isInSandbox": true,
   "surface": {
    "capabilities": [
     {
      "name": "actions.capability.AUDIO_OUTPUT"
     },
     {
      "name": "actions.capability.SCREEN_OUTPUT"
     }
    ]
   },
   "inputs": [
    {
     "rawInputs": [
      {
       "query": "yes",
       "inputType": "KEYBOARD"
      }
     ],
     "arguments": [
      {
       "rawText": "yes",
       "textValue": "true",
       "name": "PERMISSION"
      }
     ],
     "intent": "actions.intent.PERMISSION"
    }
   ],
   "user": {
    "profile": {
     "displayName": "Allen Firstenberg",
     "givenName": "Allen",
     "familyName": "Firstenberg"
    },
    "locale": "en-US",
    "userId": "APhe68HKWmHGe9cojGOMrX9WKQ0l"
   },
   "device": {
    "location": {
     "coordinates": {
      "latitude": 37.4219806,
      "longitude": -122.0841979
     }
    }
   },
   "conversation": {
    "conversationId": "1499807128489",
    "type": "ACTIVE",
    "conversationToken": "["_actions_on_google_"]"
   }
  }
 },
 "id": "7a75593e-55d0-4962-ad91-564d47e5df13",
 "timestamp": "2017-07-11T21:05:43.391Z",
 "lang": "en",
 "result": {
  "source": "agent",
  "resolvedQuery": "actions_intent_PERMISSION",
  "speech": "",
  "action": "",
  "actionIncomplete": false,
  "parameters": {},
  "contexts": [
   {
    "name": "actions_capability_screen_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "_actions_on_google_",
    "parameters": {},
    "lifespan": 99
   },
   {
    "name": "actions_intent_permission",
    "parameters": {
     "PERMISSION": "true"
    },
    "lifespan": 0
   },
   {
    "name": "actions_capability_audio_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "google_assistant_input_type_keyboard",
    "parameters": {},
    "lifespan": 0
   }
  ],
  "metadata": {
   "intentId": "5d154d71-63f1-43a9-9c18-70d78bfd700f",
   "webhookUsed": "true",
   "webhookForSlotFillingUsed": "false",
   "nluResponseTime": 1,
   "intentName": "Location result"
  },
  "fulfillment": {
   "speech": "you're allowed",
   "messages": [
    {
     "type": 0,
     "speech": "you're allowed"
    }
   ]
  },
  "score": 1
 },
 "status": {
  "code": 200,
  "errorType": "success"
 },
 "sessionId": "1499807128489"
}

JSON sent after I've granted permission (above) and then issued the "simple test" phrase. Note that the user and device fields are missing the information that permission was granted for, but that this is the right intent.


{
 "originalRequest": {
  "source": "google",
  "version": "2",
  "data": {
   "isInSandbox": true,
   "surface": {
    "capabilities": [
     {
      "name": "actions.capability.AUDIO_OUTPUT"
     },
     {
      "name": "actions.capability.SCREEN_OUTPUT"
     }
    ]
   },
   "inputs": [
    {
     "rawInputs": [
      {
       "query": "simple test",
       "inputType": "KEYBOARD"
      }
     ],
     "arguments": [
      {
       "rawText": "simple test",
       "textValue": "simple test",
       "name": "text"
      }
     ],
     "intent": "actions.intent.TEXT"
    }
   ],
   "user": {
    "locale": "en-US",
    "userId": "APhe68HKWmHGe9cojGOMrX9WKQ0l"
   },
   "device": {},
   "conversation": {
    "conversationId": "1499807128489",
    "type": "ACTIVE",
    "conversationToken": "["_actions_on_google_"]"
   }
  }
 },
 "id": "f1804e02-bafc-4656-8726-0955bfb4f75d",
 "timestamp": "2017-07-11T21:05:55.001Z",
 "lang": "en",
 "result": {
  "source": "agent",
  "resolvedQuery": "simple test",
  "speech": "",
  "action": "",
  "actionIncomplete": false,
  "parameters": {},
  "contexts": [
   {
    "name": "actions_capability_screen_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "_actions_on_google_",
    "parameters": {},
    "lifespan": 98
   },
   {
    "name": "actions_capability_audio_output",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "google_assistant_input_type_keyboard",
    "parameters": {},
    "lifespan": 0
   }
  ],
  "metadata": {
   "intentId": "48257e82-3615-4445-8ea2-be21980b7115",
   "webhookUsed": "true",
   "webhookForSlotFillingUsed": "false",
   "nluResponseTime": 4,
   "intentName": "simple test"
  },
  "fulfillment": {
   "speech": "",
   "messages": [
    {
     "type": 0,
     "speech": ""
    }
   ]
  },
  "score": 1
 },
 "status": {
  "code": 200,
  "errorType": "success"
 },
 "sessionId": "1499807128489"
}

Doing this between two sessions yields the same sort of results.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is expected behavior. Right now we recommend persisting user permissioned data on your end, keyed by the User ID. To see how we might recommend doing this, check out the Name Psychic sample. In that sample, we use Firebase Realtime DB to persist the permissioned data for that user across intents/conversations.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...