Prashant Warrier
Prashant Warrier

Reputation: 61

Google actions fails to parse JSON response

I've been struggling with getting an assistant app to respond correctly.

This app is written with Google Actions SDK (there are no other components such as Dialogflow or Converse.ai).

The action package for the app looks something like this:

{
    "actions":[
       {
         "description": "Default Welcome Intent",
         "name": "MAIN",
         "fulfillment": {
            "conversationName": "ACTION_INTENT_MAIN"
          },
          "intent": {
             "name": "actions.intent.MAIN",
             "trigger": {
                 "queryPatterns": [
                    "talk to gactions integration"
                  ]
             }
          }
       }
    ],
    "conversations":{
        "ACTION_INTENT_MAIN": {
           "name": "ACTION_INTENT_MAIN",
           "url": "https://my.custom.end/point"
        }
    },
    "locate":"en"
}

This is the JSON request that I recieve on https://my.custom.end/pont:

{
     "user": {
     "userId": "<a-user-id-sent-by-GOOG>",
     "locale": "en-US",
     "lastSeen": "2018-01-31T09:33:07Z"
   },
   "conversation": {
     "conversationId": "1517393479793",
     "type": "NEW"
   },
   "inputs": [
     {
       "intent": "actions.intent.MAIN",
       "rawInputs": [
         {
           "inputType": "KEYBOARD",
           "query": "Talk to Gactions Integration"
         }
       ]
     }
   ],
   "surface": {
     "capabilities": [
       {
         "name": "actions.capability.AUDIO_OUTPUT"
       },
       {
         "name": "actions.capability.SCREEN_OUTPUT"
       },
       {
         "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
       },
       {
         "name": "actions.capability.WEB_BROWSER"
       }
     ]
   },
   "isInSandbox": true,
   "availableSurfaces": [
     {
       "capabilities": [
         {
           "name": "actions.capability.AUDIO_OUTPUT"
         },
         {
           "name": "actions.capability.SCREEN_OUTPUT"
         }
       ]
     }
   ]
 }

An on the simulator, I end up getting this response: API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field.".

I can confirm that the incoming request has the google-actions-api-version set to 2.

This is the sharedDebugInfo section from the Actions on Google simulator:

[
    {
      "name": "ResponseValidation",
      "subDebugEntry": [
        {
          "debugInfo": "API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: \": Cannot find field.\".",
          "name": "UnparseableJsonResponse"
        }
      ]
    }
  ]

The oh-so-informative error message lacks the name of the field that cannot be found.

And this is when I'm doing everything described here

UPDATE - 01 February, 2018, 11:52 AM These are the full contents of the debug tab:

{
  "audioResponse": "//NExAAQaE...",
  "conversationToken": "GidzaW11bG...",
  "debugInfo": {
    "agentToAssistantDebug": {
      "agentToAssistantJson": "{\"conversationToken\":\"{\\\"state\\\":null,\\\"data\\\":{}}\",\"expectUserResponse\":true,\"expectedInputs\":[{\"inputPrompt\":{\"noInputPrompts\":[],\"richInitialPrompt\":{\"items\":[{\"simpleResponse\":{\"textToSpeech\":\"You're now talking to GActions Integration\",\"displayText\":\"You're now talking to GActions Integration\"}},{\"basicCard\":{\"buttons\":[{\"title\":\"Some Reddit to chill\",\"openUrlAction\":{\"url\":\"https://www.reddit.com\"}}],\"formattedText\":\"Here's some simp-wave to relax and chill out to\",\"image\":{\"url\":\"http://tracks.arte.tv/sites/default/files/styles/jscrop_1007x566/public/c_simpsons_2.jpg?itok=INzKpsvK\",\"accessibilityText\":\"A World of Simpsonwave\"},\"title\":\"A World of Simpsonwave\",\"imageDisplayOptions\":\"CROPPED\"}}],\"suggestions\":[]}},\"possibleIntents\":[{\"intent\":\"actions.intent.TEXT\"}]}],\"resetUserStorage\":false,\"userStorage\":\"{}\",\"finalResponse\":null,\"isInSandbox\":true,\"customPushMessage\":null,\"speech\":\"You're now talking to GActions Integration. \",\"displayText\":\"You're now talking to GActions Integration. \"}"
    },
    "assistantToAgentDebug": {
      "assistantToAgentJson": "{\"user\":{\"userId\":\"ABwppHHHw9N9TYh-scJ5GhZtmpfFcQU2xbQBAgW1qhdllI45fimQ5QKFEVRfs2iMm6uCDJIQMApo1UZLmmnif8wqlNARnsVH744\",\"locale\":\"en-US\",\"lastSeen\":\"2018-02-01T06:04:59Z\"},\"conversation\":{\"conversationId\":\"1517465629416\",\"type\":\"NEW\"},\"inputs\":[{\"intent\":\"actions.intent.MAIN\",\"rawInputs\":[{\"inputType\":\"VOICE\",\"query\":\"Talk to Gactions Integration\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"}]}]}",
      "curlCommand": "curl -v https://firedev.arrowai.com/integrations/goog-actions/messages/59f6b4bf8d16126f008b456a/5a619bf72c971189008b4569 -H 'Content-Type: application/json;charset=UTF-8' -H 'Google-Actions-API-Version: 2' -H 'Authorization: eyJhbGciOiJSUzI1NiIsImtpZCI6IjI2YzAxOGIyMzNmZTJlZWY0N2ZlZGJiZGQ5Mzk4MTcwZmM5YjI5ZDgifQ.eyJhdWQiOiJnYWN0aW9ucy1hcnJvd2FpLWludGVncmF0ZSIsImF6cCI6IjQ2NDA5MDk1NDc2Ny0xOWl2bnUxdjFwYXFpdWdodDJqYXJwcTJwaGtmNGRyMS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImV4cCI6MTUxNzQ2NTc0OSwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwianRpIjoiZTgxNzlmN2FkZGYwYWZmYjYwNzk0MDg5MzIyN2E0MWU1NDZkZWMyOCIsImlhdCI6MTUxNzQ2NTYyOSwibmJmIjoxNTE3NDY1MzI5fQ.rmUxBhIirV0UnZvTLYYw4AtRQfNDF-3O6CaoXxD2BDZSufgfKFHz7aIUgJzUillBm4zOLFiV6SnXndIoYCG6JK60YK5tHLpqbV-P3C-5U3N05RuY7hpj1Q_B027bgUv-p7QWlg-7DmPkROmN3b3a_FsUeWqTxx5Bu5M551k_CpKvSSBzPMEB2Cw9TzGkiY9avYrISTLLxWl2JE7qKAT6P0zBbE6cdO04CxGddGNmEPkckRICsdSJ5j_wmjy3I-ItAgx3dKoDfFLW6gCI4y5MFsGFJY6cFc2e01nodslf9GlQzAhR_a4aHRRIDl47HT_b9aKpyULV3kiRR41mUkyYZw'  -A 'Mozilla/5.0 (compatible; Google-Cloud-Functions/2.1; +http://www.google.com/bot.html)' -X POST -d '{\"user\":{\"userId\":\"ABwppHHHw9N9TYh-scJ5GhZtmpfFcQU2xbQBAgW1qhdllI45fimQ5QKFEVRfs2iMm6uCDJIQMApo1UZLmmnif8wqlNARnsVH744\",\"locale\":\"en-US\",\"lastSeen\":\"2018-02-01T06:04:59Z\"},\"conversation\":{\"conversationId\":\"1517465629416\",\"type\":\"NEW\"},\"inputs\":[{\"intent\":\"actions.intent.MAIN\",\"rawInputs\":[{\"inputType\":\"VOICE\",\"query\":\"Talk to Gactions Integration\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"}]}]}'"
    },
    "sharedDebugInfo": [
      {
        "name": "ResponseValidation",
        "subDebugEntry": [
          {
            "debugInfo": "API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: \": Cannot find field.\".",
            "name": "UnparseableJsonResponse"
          }
        ]
      }
    ]
  },
  "response": "Gactions integration isn't responding right now. Try again soon.",
  "visualResponse": {
    "visualElements": []
  }
}

This the agentToAssistantDebug object:

{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "noInputPrompts": [],
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "You're now talking to GActions Integration",
                "displayText": "You're now talking to GActions Integration"
              }
            },
            {
              "basicCard": {
                "buttons": [
                  {
                    "title": "Some Reddit to chill",
                    "openUrlAction": {
                      "url": "https://www.reddit.com"
                    }
                  }
                ],
                "formattedText": "Here's some simp-wave to relax and chill out to",
                "image": {
                  "url": "http://tracks.arte.tv/sites/default/files/styles/jscrop_1007x566/public/c_simpsons_2.jpg?itok=INzKpsvK",
                  "accessibilityText": "A World of Simpsonwave"
                },
                "title": "A World of Simpsonwave",
                "imageDisplayOptions": "CROPPED"
              }
            }
          ],
          "suggestions": []
        }
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ]
    }
  ],
  "resetUserStorage": false,
  "userStorage": "{}",
  "finalResponse": null,
  "isInSandbox": true,
  "customPushMessage": null,
  "speech": "You're now talking to GActions Integration. ",
  "displayText": "You're now talking to GActions Integration. "
}

Additionally, this is the JSON response that is being generated:

{
   "conversationToken": "{\"state\":null,\"data\":{}}",
   "expectUserResponse": true,
   "expectedInputs": [
     {
       "inputPrompt": {
         "noInputPrompts": [],
         "richInitialPrompt": {
           "items": [
             {
               "simpleResponse": {
                 "textToSpeech": "You're now talking to GActions Integration",
                 "displayText": "You're now talking to GActions Integration"
               }
             },
             {
               "basicCard": {
                 "buttons": [
                   {
                     "title": "Some Reddit to chill",
                     "openUrlAction": {
                       "url": "https://www.reddit.com"
                     }
                   }
                 ],
                 "formattedText": "Here's some simp-wave to relax and chill out to",
                 "image": {
                   "url": "http://tracks.arte.tv/sites/default/files/styles/jscrop_1007x566/public/c_simpsons_2.jpg?itok=INzKpsvK",
                   "accessibilityText": "A World of Simpsonwave"
                 },
                 "title": "A World of Simpsonwave",
                 "imageDisplayOptions": "CROPPED"
               }
             }
           ],
           "suggestions": []
         }
       },
       "possibleIntents": [
         {
           "intent": "actions.intent.TEXT"
         }
       ]
     }
   ],
   "resetUserStorage": false,
   "userStorage": "{}",
   "finalResponse": null,
   "isInSandbox": true,
   "customPushMessage": null,
   "speech": "You're now talking to GActions Integration. ",
   "displayText": "You're now talking to GActions Integration. "
 }

Upvotes: 0

Views: 1816

Answers (3)

Patrick
Patrick

Reputation: 11

Hi I think your issue is just you call an object

    "inputPrompt": { 

and an array but both are in the same position look in the explanation below.

    "noInputPrompts": [],

https://developers.google.com/actions/assistant/helpers#calling_the_helper_1

I hope I could help you.

Best regards
Patrick

Upvotes: 0

Nazeem
Nazeem

Reputation: 468

The issue seems to be related with your response JSON. As you can see in the documentation regarding the response JSON.

"speech": "You're now talking to GActions Integration. ",
"displayText": "You're now talking to GActions Integration. "

The above are not valid parameters. Instead your response JSON should look like:

{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "noInputPrompts": [],
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "You're now talking to GActions Integration",
                "displayText": "You're now talking to GActions Integration"
              }
            },
            {
              "basicCard": {
                "buttons": [
                  {
                    "title": "Some Reddit to chill",
                    "openUrlAction": {
                      "url": "https://www.reddit.com"
                    }
                  }
                ],
                "formattedText": "Here's some simp-wave to relax and chill out to",
                "image": {
                  "url": "http://tracks.arte.tv/sites/default/files/styles/jscrop_1007x566/public/c_simpsons_2.jpg?itok=INzKpsvK",
                  "accessibilityText": "A World of Simpsonwave"
                },
                "title": "A World of Simpsonwave",
                "imageDisplayOptions": "CROPPED"
              }
            }
          ],
          "suggestions": []
        }
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ]
    }
  ],
  "resetUserStorage": false,
  "userStorage": "{}",
  "finalResponse": null,
  "isInSandbox": true,
  "customPushMessage": null
}

Upvotes: 2

shortQuestion
shortQuestion

Reputation: 493

Edit if you use the nodejs sdk check if the response from the google sdk function is correct json and if your server answer with correct json. maybe its change the format etc?

Try it with an action.json style like the first. And the more important question how is your response to the request looking? try that json in the style the last code below creates

{
  "locale": "en",
  "actions": [
    {
      "name": "text",
      "intent": {
        "name": "actions.intent.TEXT",
        "trigger": {
          "queryPatterns": [
            "some text"
          ]
        }
      },
      "fulfillment": {
        "conversationName": "conv name"
      }
    },
    {
      "description": "Default Welcome Intent",
      "name": "MAIN",
      "fulfillment": {
        "conversationName": "conv name"
      },
      "intent": {
        "name": "actions.intent.MAIN",
        "trigger": {
          "queryPatterns": [
            "open my test app",
            "open hi fish"
          ]
        }
      }
    }
  ],
  "types": [],
  "conversations": {
    "conv name": {
      "name": "conv name",
      "url": "https://yourendpoint.com/something",
      "fulfillmentApiVersion": 2,
      "in_dialog_intents": [
        {
          "name": "actions.intent.NO_INPUT"
        },
      ]
    }
  }
}

this here is a function that create an valid response:

/**
message = string
slots = array
state = object
**/

    function answerWithMessage(message,slots,state){   
           let display = message.replace(/<[^>]*>/g, '');   
           let voicemessage = message.toLowerCase();

          let jsonResponse = {
            conversationToken: JSON.stringify(state),
            expectUserResponse: true,
            expectedInputs: [
              {
                inputPrompt: {
                  richInitialPrompt: {
                    items: [
                      {
                        simpleResponse: {
                          ssml: voicemessage,
                          displayText: display,
                        },
                      }
                    ],
                  }
                },
                possibleIntents: [
                  {
                    intent: "actions.intent.TEXT"
                  }
                ],
               speechBiasingHints: slots
              }
            ]   
         };   
       return JSON.stringify(jsonResponse,null, 4); 
    }

And here is a repro with example google actions sdk: https://github.com/haukedau/googleActionsInit but the answer there is not completly correct but it will do the work as well above response message style is better.

Upvotes: 0

Related Questions