简体   繁体   English

在Dialogflow上没有错误时,Google智能助理出错

[英]Error on Google Assistant while no error on Dialogflow

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. 我已经创建了一个包含MySQL的小型数据库,其中存储了这些数据,并且只要这是合适的,我就会使用PHP脚本来获取它们,具体取决于用户与聊天机器人的交互。

My chatbot contains two intents additionally to the Default Fallback Intent and to the Default Welcome Intent : 我的聊天机器人包含Default Fallback IntentDefault Welcome Intent

  • Names
  • Location_context

The first intent ( Names ) is trained by phrases such as 'Who is John Smith?' 第一个意图( Names )是通过诸如“谁是约翰史密斯?”之类的短语训练的。 and has an output context (called context with duration of 10 questions). 并有一个输出上下文(称为context ,持续时间为10个问题)。 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?' 第二个意图( Location_context )由诸如“他住在哪里?”之类的短语训练。 and has an input context (from Names ). 并有一个输入上下文(来自Names )。 A possible answer to this question is 'John is living in New York.' 对这个问题的一个可能的答案是“约翰住在纽约。”

The Names intent contains two parameters: Names intent包含两个参数:

  • parameter names: given-name, last-name. 参数名称:给定名称,姓氏。
  • entities: @sys.given-name, @sys.last-name. 实体:@sys.given-name,@ sys.last-name。
  • value: $given-name, $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. Location_context意图不包含任何参数。

The PHP script is the following: PHP脚本如下:

<?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 eg "Who is John Smith?" 在Dialogflow中,在询问例如“谁是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: Dialogflow对第二个问题的json响应是:

{
  "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." 但是,当我在Google助手中输入完全相同的问题(在Talk to my test app后),我在第一个问题上得到了相同的答案,但我得到的是“住在洛杉矶”。 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. 首先,变量$first_name没有任何值(因为它没有设置),并且位置'洛杉矶'是数据库中最后一个的系列成员的位置。 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. 因此返回此位置是因为$first_name$last_name在mysql查询中没有分配值(因为它们未设置),并且由于某种原因返回了数据库的最后一个人的位置。

It is quite frustrating that I cannot inspect the json response of Google Assistant as I can easily do it in Dialogflow. 令人非常沮丧的是,我无法检查Google智能助理的json响应,因为我可以在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. 然而,在经过一些实验后我发现在Google智能助理中, $lifespan始终为0(在第一个和第二个问题中),并且在第二个问题的json响应中, $first_name$last_name根本没有设置,即使在Dialoglow中,它们被设置,它们包含我在上面发布的json响应中显示的全名。 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). 此外谷歌助理返回actions_capability_screen_output$json->result->contexts[0]->name中,而显然这两个问题在Dialogflow $json->result->contexts[0]->namecontext (上下文的名称) 。

Therefore, the contexts branch of the json response in the second question in Google Assistant seems to be like this: 因此,Google智能助理第二个问题中json响应的contexts分支似乎是这样的:

"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: 另一方面,如上所示,DIalogflow中第二个问题中json响应的contexts分支是:

"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? 为什么Google智能助理无法识别context并且它不会处理与Dialoglow所示相同的json响应?

How can I inspect the entire json response from Google Assistant as I do it in Dialogflow? 如何在Dialogflow中检查Google智能助理的整个json响应?

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'); 因为ini_set('display_errors', 'on'); sends any errors to standard output which is what you're sending back to Dialogflow. 将任何错误发送到标准输出,这是您要发送回Dialogflow的。 Dialogflow's parser that sends things to Google was strict, so the extra output was causing problems here. Dialogflow的解析器向Google发送内容非常严格,因此额外的输出会导致问题。

How can I see what is going on? 我怎么才能看到发生了什么?

You should log things using something like error_log() . 您应该使用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. 这将在文件中记录您想要的任何内容,因此您可以看到来自Dialogflow的确切JSON以及您认为发送回的内容。

You can use this with something like 您可以使用类似的东西

error_log( $request_body );

to see exactly what the JSON is that has been sent from Dialogflow. 确切地看到从Dialogflow发送的JSON是什么。 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. 这将记录身体的系统错误记录(这可能是HTTP的error_log,除非你把它在其他地方),所以你可以检验一下,看看那被发送到你的一切

Ok, I can see what is going on. 好的,我可以看到发生了什么。 Why is the JSON different? 为什么JSON不同?

Because Actions on Google has additional information than what is available through other agents. 因为Google上的操作系统提供的信息多于其他代理商提供的信息。 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. 例如,您将看到通过JSON提供的originalRequest对象。

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? 为什么我不能在更改要发送到Google上的操作之前看到Dialogflow从我的webhook中获取什么?

Good question. 好问题。 This does sometimes get logged in the Debug tab under "agentToAssistantDebug", but not always. 这有时会记录在“agentToAssistantDebug”下的“调试”选项卡中,但并非总是如此。 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? 为什么我没有通过Google上的操作获取context上下文?

You haven't actually posted evidence that you're not. 你实际上没有发表你不是的证据。 All you've shown is that context[0] isn't named "context". 你所展示的只是context[0]没有命名为“context”。 You should log the entire context array to see all of them with something like 您应该记录整个context数组以查看所有这些内容

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. 这包括一个名为actions_capability_screen_output ,该操作由Google上的操作创建,用于指示您正在可以显示到屏幕的设备上运行。 It will probably also have one named actions_capability_audio_output to indicate it can speak the result. 它可能还有一个名为actions_capability_audio_output的表示它可以说出结果。 It should also include one named context , which is the one that you set. 它还应该包含一个命名context ,它是您设置的context

But why don't these other contexts have the given-name and last-name parameters set? 但为什么这些其他上下文没有设置given-namelast-name参数?

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. 遍历context数组并查找与您期望的名称匹配的数组。 You can then get the parameters you want from there. 然后,您可以从那里获得所需的参数。

Why is Actions on Google resetting the lifespan to 0? 为什么Google上的操作会将生命周期重置为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). Google 上的操作设置其他上下文(您看到其中一个),其中包含特定于AoG的其他信息,并且它的生命周期为0(这意味着它将在此轮后删除,但它们将在下一次再次设置它通过)。 They set it to 0 because some of the contexts may change each time (particularly which surfaces are supported). 他们将其设置为0,因为某些上下文可能每次都会更改(特别是支持哪些表面)。

Is there a better way to do this without contexts? 有没有更好的方法在没有上下文的情况下做到这一点?

Not really - contexts are pretty awesome and they're the best solution for this. 不是真的 - 上下文非常棒,它们是最好的解决方案。

I'm not the biggest expert on PHP, but I have used it a bit. 我不是PHP的最大专家,但我已经使用了一点。 I think your issue is that Dialogflow is not interpreting your result as JSON but rather a simple string. 我认为您的问题是Dialogflow不会将您的结果解释为JSON,而是一个简单的字符串。

From the error, I see: 从错误中,我看到:

Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $.

Assuming your response is valid JSON then you may need to manually tell Dialogflow that the response needs to be interpreted as JSON . 假设您的响应是有效的JSON,那么您可能需要手动告诉Dialogflow该响应需要被解释为JSON

It does seem like you're already doing that at the top of your PHP response, but maybe you should verify the JSON response doesn't have anything out of the ordinary that would cause that error above. 看起来你似乎已经在PHP响应的顶部做了这个,但是也许你应该验证JSON响应没有任何异常会导致上面的错误。

-- ANSWER TO MY POST BEFORE UPDATING IT -- - 在更新之前回答我的帖子 -

Finally I discovered that I am getting an Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $. 最后我发现我得到了一个Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $. error unless I comment out these lines in my source code: 错误除非我在源代码中注释掉这些行:

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

If I comment out these two lines then I am not getting any error but the final response is that "is living in Los Angeles" while "John is living in New York Angeles" is the complete/correct response. 如果我评论这两行,那么我没有得到任何错误,但最终的回答是“生活在洛杉矶”,而“约翰住在纽约安吉利斯”是完整/正确的回应。 Obviously, commenting out these two lines does not really solve my problem. 显然,评论这两行并不能真正解决我的问题。 This problem occurs because for some reason Google Assistant does not recognise the context defined for the Names and Location_context intents while Dialogflow properly recognises it. 出现此问题的原因是,由于某些原因,当Dialogflow正确识别它时,Google智能助理无法识别为NamesLocation_context上下文定义定义的上下文。 Because of this, $first_name and $last_name are not even set in the second question ('Where is he living?) and this is why I am getting an incomplete/wrong response to this question. 因此, $first_name$last_name甚至没有在第二个问题中设置('他住在哪里?)这就是我对这个问题得到不完整/错误回答的原因。

FOR AN UPDATED STATEMENT OF MY PROBLEM PLEASE SEE MY EDITED POST ABOVE. 关于我的问题的更新声明请看我上面的编辑。

-- ANSWER TO MY POST AFTER UPDATING IT -- - 在更新后回复我的帖子 -

I can solve my problem if I add the following two parameters in the Location_context intent: 如果我在Location_context intent中添加以下两个参数,我可以解决我的问题:

  • parameter names: given-name, last-name. 参数名称:给定名称,姓氏。
  • entities: @sys.given-name, @sys.last-name. 实体:@sys.given-name,@ sys.last-name。
  • value: #context.given-name, #context.last-name. value:#context.given-name,#context.last-name。

Therefore, I essentially pass the value of the given-name and last-name parameters from the Names intent to the Location_context intent. 所以,我基本上是传递的价值given-namelast-name从参数Names意在将Location_context意图。

If I do this then the contexts branch of the json response in the second question in Google Assistant seems to become like this: 如果我这样做,那么Google智能助理第二个问题中json响应的contexts分支似乎变成这样:

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

(Again I cannot directly inspect the json output from Google Assistant but I am just making some tests to understand the format and the content of the json response from it) (同样,我无法直接检查Google智能助理的json输出,但我只是进行了一些测试,以了解json响应的格式和内容)

In this way I can retrieve the full name of the person through my PHP script and get the right answer ("John is living in New York.") to the second question ("Where is he living?"). 通过这种方式,我可以通过我的PHP脚本检索该人的全名并获得正确的答案(“约翰住在纽约。”)到第二个问题(“他住在哪里?”)。

However, I am still wondering why it is necessary to do this while in Dialogflow this is done without adding any parameters in the Location_context intent... 但是,我仍然想知道为什么有必要在Dialogflow中执行此操作,而无需在Location_context intent中添加任何参数...

Also I am not sure that in this way Google Assistant recognises the context between the two intents since lifespan is again 0 (even though I am getting what I want to get)... 另外我不确定Google Assistant会以这种方式识别两个意图之间的上下文,因为lifespan再次为0(即使我得到了我想要的内容)...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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