Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error on Google Assistant while no error on Dialogflow

Tags:

I created a chatbot which informs the user about the members of my (extended) family and about where they are living. I have created a small database with MySQL which has these data stored and I fetch them with a PHP script whenever this is appropriate depending on the interaction of the user with the chatbot.

My chatbot contains two intents additionally to the Default Fallback Intent and to the Default Welcome Intent:

  • Names
  • Location_context

The first intent (Names) is trained by phrases such as 'Who is John Smith?' and has an output context (called context with duration of 10 questions). A possible answer to this question is 'John is my uncle.'. The second intent (Location_context) is trained by phrases such as 'Where is he living?' and has an input context (from Names). A possible answer to this question is 'John is living in New York.'

The Names intent contains two parameters:

  • parameter names: given-name, last-name.
  • entities: @sys.given-name, @sys.last-name.
  • value: $given-name, $last-name.

These two parameters represent the full name given by the user. The Location_context intent does not contain any parameters.

The PHP script is the following:

<?php

$dbServername = '******************';
$dbUsername = '******************';
$dbPassword = '******************';
$dbName = '******************';
$conn = mysqli_connect($dbServername, $dbUsername, $dbPassword, $dbName);

// error_reporting(E_ALL);
// ini_set('display_errors', 'on');

header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];

if($method == 'POST'){
    $requestBody = file_get_contents('php://input');
    $json = json_decode($requestBody);

    $action = $json->result->action;
    $first_name = $json->result->contexts[0]->parameters->{'given-name'};
    $last_name = $json->result->contexts[0]->parameters->{'last-name'};
    $lifespan = $json->result->contexts[0]->lifespan;

    $sql = "SELECT * FROM family WHERE name LIKE '%$first_name%$last_name%';";
    $result = mysqli_query($conn, $sql);
    $resultCheck = mysqli_num_rows($result);
    if ($resultCheck > 0) {
       while ($row = mysqli_fetch_assoc($result)) {
            $person = $row;
       }

       switch ($action) {
           case 'Name':
               $speech= "$first_name is my" . $person["name"] . ".";
               break;  
           case 'Location':
               $speech = "$first_name is living in {$person["location"]}.";
               break;
           default:
               $speech = "Please ask me something more relevant to my family";
               break;
       } 
    }
    else {

        $speech = "Sorry, $first_name $last_name is not a member of my family.";

    }

    $response = new \stdClass();
    $response->speech = $speech;
    $response->displayText = $speech;
    $response->source = "agent";
    echo json_encode($response);
}
else
{
    echo "Method not allowed";
}
?>

In Dialogflow, after asking e.g. "Who is John Smith?" and getting the correct answer "John is my uncle." then I am asking "Where is he living?" and I am getting the correct answer "John is living in New York.". The json response from Dialogflow for the second question is:

{
  "id": "*****************************",
  "timestamp": "2018-04-04T08:26:39.993Z",
  "lang": "en",
  "result": {
    "source": "agent",
    "resolvedQuery": "Where is he living"
    "action": "Location",
    "actionIncomplete": false,
    "parameters": {},
    "contexts": [
      {
        "name": "context",
        "parameters": {
          "given-name.original": "John",
          "last-name.original": "Smith",
          "given-name": "John",
          "last-name": "Smith"
        },
        "lifespan": 9
      }
    ],
    "metadata": {
      "intentId": "*****************************",
      "webhookUsed": "true",
      "webhookForSlotFillingUsed": "false",
      "webhookResponseTime": 93,
      "intentName": "Location_context"
    },
    "fulfillment": {
      "speech": "John is living in New York.”,
      "displayText": "John is living in New York.",
      "messages": [
        {
          "type": 0,
          "speech": "John is living in New York."
        }
      ]
    },
    "score": 1
  },
  "status": {
    "code": 200,
    "errorType": "success",
    "webhookTimedOut": false
  },
  "sessionId": "*****************************"
}

However, when I enter exactly the same questions (after entering Talk to my test app) in Google assistant, I am getting the same answer at the first question but I am getting "is living in Los Angeles." for the second question. Notice two things in this answer. Firstly, the variable $first_name does not have any value (because it is not set) and that the location 'Los Angeles' is the location of the family member which is last in the database. Therefore this location is returned because $first_name and $last_name have no value assigned (as they are not set) in the mysql query and for some reason the location of the last person of the database is returned.

It is quite frustrating that I cannot inspect the json response of Google Assistant as I can easily do it in Dialogflow. However, after experimenting a bit I found out that in Google Assistant $lifespan is always 0 (both in the first and the second question) and that $first_name and $last_name are not set at all in the json response of the second question even though in Dialoglow they are set and they contain the full name as it shown above in the json response I posted. Also Google Assistant returns actions_capability_screen_output for $json->result->contexts[0]->name in both questions while obviously in Dialogflow $json->result->contexts[0]->name is context (the name of the context).

Therefore, the contexts branch of the json response in the second question in Google Assistant seems to be like this:

"contexts": [
          {
            "name": "actions_capability_screen_output",
            "parameters": {},
            "lifespan": 0
          }
        ]

On the other hand, as I showed above, the contexts branch of the json response in the second question in DIalogflow is:

"contexts": [
      {
        "name": "context",
        "parameters": {
          "given-name.original": "John",
          "last-name.original": "Smith",
          "given-name": "John",
          "last-name": "Smith"
        },
        "lifespan": 9
      }
    ]

Why Google Assistant does not recognise context and it does not process the same json response as shown by Dialoglow?

How can I inspect the entire json response from Google Assistant as I do it in Dialogflow?

like image 525
Outcast Avatar asked Apr 03 '18 09:04

Outcast


1 Answers

There is a lot going on here in addition to your questions. Let's try to break them down bit by bit.

Why was I getting errors in the response initially?

Because ini_set('display_errors', 'on'); sends any errors to standard output which is what you're sending back to Dialogflow. Dialogflow's parser that sends things to Google was strict, so the extra output was causing problems here.

How can I see what is going on?

You should log things using something like error_log(). This will record in a file whatever you want, so you can see the exact JSON that has come from Dialogflow and exactly what you think you are sending back.

You can use this with something like

error_log( $request_body );

to see exactly what the JSON is that has been sent from Dialogflow. This will log the body to the system error logger (which is probably the HTTP error_log unless you set it elsewhere) so you can examine it and see everything that is being sent to you.

Ok, I can see what is going on. Why is the JSON different?

Because Actions on Google has additional information than what is available through other agents. These are sent to you in the same way (or should be), but there will be more of it. For example, you'll see an originalRequest object delivered through JSON.

However - all the information you expect should be there. Just more of it.

Why can't I see what Dialogflow gets from my webhook before changing things to send to Actions on Google?

Good question. This does sometimes get logged in the Debug tab under "agentToAssistantDebug", but not always. You'll need to use other tools to see exactly what you're replying as part of a test infrastructure.

Why am I not getting the context context with Actions on Google?

You haven't actually posted evidence that you're not. All you've shown is that context[0] isn't named "context". You should log the entire context array to see all of them with something like

error_log( $json->result->context );

What you will see is that there are many contexts that have been set. This includes one named actions_capability_screen_output which is created by Actions on Google to indicate that you're running on a device that can display to a screen. It will probably also have one named actions_capability_audio_output to indicate it can speak the result. It should also include one named context, which is the one that you set.

But why don't these other contexts have the given-name and last-name parameters set?

Because these parameters weren't set when those contexts were active.

You can't just assume the parameters will be set on the first context - you'll need to look for the context where you have set them and get the value out of those specific contexts.

Parameters will only be on the contexts where they are set. (In fact, you can set additional parameters in output contexts as part of your reply.)

If there is more than one context, how do I find the one that contains my parameters?

Loop through the context array and look for one that matches the name you are expecting. You can then get the parameters you want from there.

Why is Actions on Google resetting the lifespan to 0?

It isn't. Actions on Google does set additional contexts (which you see one of) which contain additional information specific to AoG, and it has a lifespan of 0 (meaning it will be removed after this round, but they'll just set it again the next time through). They set it to 0 because some of the contexts may change each time (particularly which surfaces are supported).

Is there a better way to do this without contexts?

Not really - contexts are pretty awesome and they're the best solution for this.

like image 175
Prisoner Avatar answered Sep 22 '22 13:09

Prisoner