简体   繁体   中英

Google Actions API webhook response on Heroku nodejs

The question: Does Google Actions always work by firing the webhook post on every user input and I just have to work the logic so as to parse the json everytime and react only if my parameter of interest is found? Or is there a way to control the webhook post made by Google Actions API in order to only have it made when the action is completely filled by containing a value for the parameter of interest?

#

The details: I've got this nodejs app deployed on Heroku: https://github.com/quique123/myjsonparser/blob/master/app.js

Im using it as a webhook to a Google Actions API (Number Genie) example. In Number Genie the user starts the game with "Talk to number genie". The Genie responds with Im thinking of a number ... guess it. The user responds with a number and then (and only then) is the logic is run to compare the guess with the answer.

But Im having the api call made on every post request from google home. In other words, the webhook post is made every time the user interacts with the conversation api. It can be seen here where the body contains no user-input-parameter and Heroku responds to "talk to number genie":

2017-04-30T19:00:31.901297+00:00 app[web.1]: headers: {"host":"myjsonparser.herokuapp.com","connection":"close","accept":"*/*","content-type":"application/json; charset=UTF-8","cache-control":"no-cache","pragma":"no-cache","user-agent":"Java/1.8.0_112","x-request-id":"5a7a2c31-9ce5-4b02-9bac-bcef55ad6818","x-forwarded-for":"54.224.155.160","x-forwarded-proto":"https","x-forwarded-port":"443","via":"1.1 vegur","connect-time":"1","x-request-start":"1493578831899","total-route-time":"0","content-length":"573"}
2017-04-30T19:00:31.901347+00:00 app[web.1]: body: {"id":"5478dfb5-54f3-451d-b975-4f984d1ce3cb","timestamp":"2017-04-30T19:00:31.858Z","lang":"en","result":{"source":"agent","resolvedQuery":"44","speech":"","action":"check_guess","actionIncomplete":false,"parameters":{"check_guess":"44"},"contexts":[],"metadata":{"intentId":"c863e1e2-c850-45d8-9b96-b57e0b1ee77e","webhookUsed":"true","webhookForSlotFillingUsed":"false","intentName":"provide_guess"},"fulfillment":{"speech":"","messages":[{"type":0,"speech":""}]},"score":1},"status":{"code":200,"errorType":"success"},"sessionId":"ff2e0c97-552b-40d3-8f06-32e612476897"}
2017-04-30T19:00:31.903553+00:00 app[web.1]: postSwitch {"id":"sw1","state":"on","name":"Koko's Lamp"}
2017-04-30T19:00:31.907017+00:00 heroku[router]: at=info method=POST path="/API/switches/sw1?password=123456" host=myjsonparser.herokuapp.com request_id=5a7a2c31-9ce5-4b02-9bac-bcef55ad6818 fwd="54.224.155.160" dyno=web.1 connect=1ms service=5ms status=200 bytes=253 protocol=https

And when I test it using a number on Google Actions API, you can see in Heroku response to "44" that check_guess is included:

 2017-04-30T19:00:31.901297+00:00 app[web.1]: headers: {"host":"myjsonparser.herokuapp.com","connection":"close","accept":"*/*","content-type":"application/json; charset=UTF-8","cache-control":"no-cache","pragma":"no-cache","user-agent":"Java/1.8.0_112","x-request-id":"5a7a2c31-9ce5-4b02-9bac-bcef55ad6818","x-forwarded-for":"54.224.155.160","x-forwarded-proto":"https","x-forwarded-port":"443","via":"1.1 vegur","connect-time":"1","x-request-start":"1493578831899","total-route-time":"0","content-length":"573"} 2017-04-30T19:00:31.901347+00:00 app[web.1]: body: {"id":"5478dfb5-54f3-451d-b975-4f984d1ce3cb","timestamp":"2017-04-30T19:00:31.858Z","lang":"en","result":{"source":"agent","resolvedQuery":"44","speech":"","action":"check_guess","actionIncomplete":false,"parameters":{"check_guess":"44"},"contexts":[],"metadata":{"intentId":"c863e1e2-c850-45d8-9b96-b57e0b1ee77e","webhookUsed":"true","webhookForSlotFillingUsed":"false","intentName":"provide_guess"},"fulfillment":{"speech":"","messages":[{"type":0,"speech":""}]},"score":1},"status":{"code":200,"errorType":"success"},"sessionId":"ff2e0c97-552b-40d3-8f06-32e612476897"} 2017-04-30T19:00:31.903553+00:00 app[web.1]: postSwitch {"id":"sw1","state":"on","name":"Koko's Lamp"} 2017-04-30T19:00:31.907017+00:00 heroku[router]: at=info method=POST path="/API/switches/sw1?password=123456" host=myjsonparser.herokuapp.com request_id=5a7a2c31-9ce5-4b02-9bac-bcef55ad6818 fwd="54.224.155.160" dyno=web.1 connect=1ms service=5ms status=200 bytes=253 protocol=https 

The problem is that the postSwitch{} happens in both ocassions.

Is this the way Google Actions will always work, and I just have to work the logic so as to parse the json everytime and react only if check_guess is found? Or is there a way to control the webhook post made by Google Actions API in order to only have it made when the action is completely filled by containing a value for the parameter check_guess?

You can only set one webhook (one static URL) that will be called for all actions that are triggered with API.AI. While you will need to parse the JSON (you're using node.js, JSON.parse() isn't THAT difficult), you should be using the result.action field instead of trying to figure out which parameters are set. This will correspond to the Action field that you have set in API.AI.

This assumes that you have the webhook box checked for your action, of course. If not, you won't get a webhook call at all.

So, for example, with the starting intent configured like this:

在此处输入图片说明

It will send this JSON to your webhook.


{
 "originalRequest": {
  "source": "google",
  "data": {
   "surface": {
    "capabilities": [
     {
      "name": "actions.capability.AUDIO_OUTPUT"
     }
    ]
   },
   "inputs": [
    {
     "arguments": [],
     "intent": "assistant.intent.action.MAIN",
     "raw_inputs": [
      {
       "query": "talk to number genie",
       "input_type": 2,
       "annotation_sets": []
      }
     ]
    }
   ],
   "user": {
    "user_id": "kQmX8nX9ovcS9jfb3WKmwLk9YFlHGZH05YGbc8muNI8=",
    "permissions": []
   },
   "device": {
    "locale": "en-US"
   },
   "is_in_sandbox": true,
   "conversation": {
    "conversation_id": "1493637016599",
    "type": 1
   }
  }
 },
 "id": "9444bfe4-3c23-487a-84e7-fcbf1708d9e3",
 "timestamp": "2017-05-01T11:10:16.694Z",
 "lang": "en",
 "result": {
  "source": "agent",
  "resolvedQuery": "GOOGLE_ASSISTANT_WELCOME",
  "speech": "",
  "action": "generate_answer",
  "actionIncomplete": false,
  "parameters": {},
  "contexts": [
   {
    "name": "game",
    "parameters": {},
    "lifespan": 5
   },
   {
    "name": "google_assistant_welcome",
    "parameters": {},
    "lifespan": 0
   },
   {
    "name": "actions_capability_audio_output",
    "parameters": {},
    "lifespan": 0
   }
  ],
  "metadata": {
   "intentId": "56da4637-0419-46b2-b851-d7bf726b1b1b",
   "webhookUsed": "true",
   "webhookForSlotFillingUsed": "false",
   "intentName": "start_game"
  },
  "fulfillment": {
   "speech": "",
   "messages": [
    {
     "type": 0,
     "speech": ""
    }
   ]
  },
  "score": 1
 },
 "status": {
  "code": 200,
  "errorType": "success"
 },
 "sessionId": "1493637016599"
}

While the provide_guess intent might be configured like this

Provide_guess屏幕截图

and provide this JSON to the webhook:


{
 "originalRequest": {
  "source": "google",
  "data": {
   "surface": {
    "capabilities": [
     {
      "name": "actions.capability.AUDIO_OUTPUT"
     }
    ]
   },
   "inputs": [
    {
     "arguments": [
      {
       "raw_text": "42",
       "text_value": "42",
       "name": "text"
      }
     ],
     "intent": "assistant.intent.action.TEXT",
     "raw_inputs": [
      {
       "query": "42",
       "input_type": 2,
       "annotation_sets": []
      }
     ]
    }
   ],
   "user": {
    "user_id": "kQmX8nX9ovcS9jfb3WKmwLk9YFlHGZH05YGbc8muNI8=",
    "permissions": []
   },
   "device": {
    "locale": "en-US"
   },
   "is_in_sandbox": true,
   "conversation": {
    "conversation_token": "[\"_actions_on_google_\",\"game\"]",
    "conversation_id": "1493637749915",
    "type": 2
   }
  }
 },
 "id": "09997ef5-5c0f-4c60-a69f-af06d6e4e3f5",
 "timestamp": "2017-05-01T11:22:34.377Z",
 "lang": "en",
 "result": {
  "source": "agent",
  "resolvedQuery": "42",
  "speech": "",
  "action": "check_guess",
  "actionIncomplete": false,
  "parameters": {
   "guess": "42"
  },
  "contexts": [
   {
    "name": "game",
    "parameters": {
     "guess.original": "42",
     "guess": "42"
    },
    "lifespan": 5
   },
   {
    "name": "_actions_on_google_",
    "parameters": {
     "guessCount": 0,
     "printed": "Welcome back to Number Genie. I'm thinking of a number from %s to %s. What's your first guess?",
     "guess.original": "42",
     "answer": 74,
     "guess": "42",
     "lastPrompt": "Welcome back to Number Genie. I'm thinking of a number from %s to %s. What's your first guess?",
     "steamSoundCount": 0,
     "fallbackCount": 0
    },
    "lifespan": 99
   },
   {
    "name": "actions_capability_audio_output",
    "parameters": {
     "guess.original": "42",
     "guess": "42"
    },
    "lifespan": 0
   }
  ],
  "metadata": {
   "intentId": "1e46ffc2-651f-4ac0-a54e-9698feb88880",
   "webhookUsed": "true",
   "webhookForSlotFillingUsed": "false",
   "intentName": "provide_guess"
  },
  "fulfillment": {
   "speech": "",
   "messages": [
    {
     "type": 0,
     "speech": ""
    }
   ]
  },
  "score": 1
 },
 "status": {
  "code": 200,
  "errorType": "success"
 },
 "sessionId": "1493637749915"
}

In your code, you would check for the value of result.action in your postSwitch() method and can then select the exact operations on your end based on this action (either generateAnswer() or checkGuess() based on your commented out code).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM