Ошибка в Google Assistant при отсутствии ошибки в Dialogflow

Я создал чат-бота, который информирует пользователя о членах моей (расширенной) семьи и о том, где они живут. Я создал небольшую базу данных с MySQL, в которой хранятся эти данные, и я извлекаю их с помощью сценария PHP, когда это необходимо, в зависимости от взаимодействия пользователя с чат-ботом.

Мой чат-бот содержит два намерения в дополнение к Default Fallback Intent и Default Welcome Intent:

  • Names
  • Location_context

Первое намерение (Names) тренируется с помощью таких фраз, как «Кто такой Джон Смит?» и имеет выходной контекст (называемый context с продолжительностью 10 вопросов). Возможный ответ на этот вопрос: «Джон - мой дядя». Второе намерение (Location_context) тренируется с помощью таких фраз, как «Где он живет?» и имеет входной контекст (из Names). Возможный ответ на этот вопрос: «Джон живет в Нью-Йорке».

Намерение Names содержит два параметра:

  • имена параметров: имя-имя, фамилия.
  • сущности: @ sys.given-name, @ sys.last-name.
  • значение: $ given-name, $ last-name.

Эти два параметра представляют полное имя, данное пользователем. Намерение Location_context не содержит никаких параметров.

Скрипт 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";
}
?>

В Dialogflow, спросив, например, "Кто такой Джон Смит?" и получив правильный ответ «Джон - мой дядя». затем я спрашиваю: "Где он живет?" и я получаю правильный ответ: «Джон живет в Нью-Йорке». Ответ в формате json от Dialogflow на второй вопрос:

{
  "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": "*****************************"
}

Однако, когда я ввожу точно такие же вопросы (после ввода Talk to my test app) в Google Ассистент, я получаю тот же ответ на первый вопрос, но получаю «живет в Лос-Анджелесе». по второму вопросу. Обратите внимание на две вещи в этом ответе. Во-первых, переменная $first_name не имеет никакого значения (потому что она не установлена) и что местоположение «Лос-Анджелес» - это местоположение члена семьи, который находится последним в базе данных. Следовательно, это местоположение возвращается, потому что $first_name и $last_name не имеют присвоенного значения (поскольку они не установлены) в запросе mysql, и по какой-то причине возвращается местоположение последнего человека в базе данных.

Довольно неприятно, что я не могу проверить json-ответ Google Assistant, поскольку я могу легко сделать это в Dialogflow. Однако, немного поэкспериментировав, я обнаружил, что в Google Assistant $lifespan всегда равен 0 (как в первом, так и во втором вопросе), и что $first_name и $last_name вообще не установлены в json-ответе на второй вопрос, хотя в Dialoglow они установлены, и они содержат полное имя, как показано выше в ответе json, который я опубликовал. Также Google Assistant возвращает actions_capability_screen_output для $json->result->contexts[0]->name в обоих вопросах, тогда как, очевидно, в Dialogflow $json->result->contexts[0]->name - это context (имя контекста).

Следовательно, ветвь contexts ответа json во втором вопросе в Google Assistant выглядит так:

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

С другой стороны, как я показал выше, ветвь contexts ответа json во втором вопросе в DIalogflow:

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

Почему Google Assistant не распознает context и не обрабатывает тот же ответ json, что и Dialoglow?

Как я могу проверить весь ответ json от Google Assistant, как я это делаю в Dialogflow?

Это кажется странным, и на данный момент я не могу воспроизвести это в своих тестах, используя только этот JSON. Можете ли вы обновить свой вопрос, включив в него результаты вкладки «Отладка» симулятора Ассистента? Можете ли вы также уточнить, используете ли вы протокол Dialogflow V1 или V2 (включите снимок экрана вашего экрана настроек, маскируя конфиденциальную информацию, если вы не уверены).

Prisoner 03.04.2018 15:22

Если возможно, можете ли вы также включить источник PHP, который генерирует этот ответ?

Prisoner 03.04.2018 15:22

Спасибо за ваш ответ. Я готов предоставить все эти подробности, однако думаю, что мой пост станет очень длинным. Я думаю, что лучше задать новый вопрос по этому поводу, связанный с более сложным чат-ботом, который я создал на основе этого.

Outcast 03.04.2018 15:54

Лучше всего иметь что-то простое и воспроизводимое. Если я не могу воспроизвести его с помощью JSON, это говорит о том, что есть что-то еще немного другое, что не так. Обнаружение ошибки в простейшем случае должно помочь вам исправить ее в более сложном.

Prisoner 03.04.2018 16:01

Итак, отредактировал свой пост, и я предоставил всю информацию, которую вы просили. (Я пытался скрыть какую-либо конфиденциальную информацию, но если я что-то пропустил, вы можете отредактировать мое сообщение, чтобы исправить это)

Outcast 03.04.2018 16:20

Это действительно озадачивает. Этого не должно быть, но попробуйте изменить строку echo "Method not allowed"; на что-то, что отправляет ответ JSON, который был бы действителен (например, текстовая форма объекта, для которого установлены речь и displayText).

Prisoner 03.04.2018 17:05

Я не делаю того, что делал (!!), но я наконец получаю ответ, хотя и неправильный. Google Assistant возвращает следующий ответ: «живет в Лос-Анджелесе». Это означает, что, во-первых, он по какой-то причине пропускает имя, а во-вторых, (из-за этого?) Он всегда возвращает местоположение последнего члена семьи в базе данных (только последний член семьи в базе данных живет в Лос-Анджелесе). Расстраивает то, что сам Dialogflow или даже его веб-демонстрация реагируют абсолютно нормально. Что из этого можно понять?

Outcast 03.04.2018 17:10

Для всего этого он предполагает, что либо метод на самом деле не является POST, и / или вы не получаете тело JSON. Я не совсем уверен, почему это может происходить, но добавление журнала, чтобы точно видеть, что отправляется на ваш веб-перехватчик в этих случаях, может помочь.

Prisoner 03.04.2018 17:18

Хорошо, но если это не POST или JSON, то почему я получаю правильный ответ в Dialogflow? Также я сказал за несколько минут, что наконец-то получил ответ даже в Google Assistant, поэтому нет проблем с методом POST или форматом JSON, но у меня сложилось впечатление, что по какой-то причине он не передает правильным образом имя человека через контекст.

Outcast 03.04.2018 17:30

(хотя он передает имя через контекст в самом Dialogflow)

Outcast 03.04.2018 17:38

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!! !!!! ‌ !!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!! Я ОБНОВИЛ СВОЮ ПИСЬМО ВЫШЕ, ПОЭТОМУ ВЫ МОЖЕТЕ ПРОИГНОРИРОВАТЬ ВСЕ ВЫШЕ КОММЕНТАРИИ. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!! !!!! ‌ !!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!!!!!!!!! ‌ !!!!!!!!!!!!

Outcast 04.04.2018 13:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
5
11
1 064
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я не самый большой специалист по PHP, но я немного им пользовался. Я думаю, ваша проблема в том, что Dialogflow интерпретирует ваш результат не как JSON, а как простую строку.

Из ошибки вижу:

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

Предполагая, что ваш ответ - действительный JSON, вам может потребоваться вручную сообщить Dialogflow, что ответ должен быть интерпретируется как JSON.

Кажется, что вы уже делаете это в верхней части своего ответа PHP, но, возможно, вам следует убедиться, что в ответе JSON нет ничего необычного, что могло бы вызвать указанную выше ошибку.

(ЭТО ОТВЕТ НА МОЙ ЗАПИСЬ ДО ОБНОВЛЕНИЯ. ДЛЯ ОБНОВЛЕННОГО ИЗЛОЖЕНИЯ МОЕЙ ПРОБЛЕМЫ, ПОЖАЛУЙСТА, СМОТРИТЕ МОЙ ОТредактированный пост ВЫШЕ.)

Outcast 04.04.2018 15:02

- ОТВЕТЬ НА МОЙ ЗАПИСЬ ПЕРЕД ОБНОВЛЕНИЕМ -

Наконец, я обнаружил, что получаю ошибку Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $., если не закомментирую эти строки в исходном коде:

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

Если я закомментирую эти две строки, то я не получу никакой ошибки, но окончательный ответ будет таким, что «живет в Лос-Анджелесе», а «Джон живет в Нью-Йорке» - это полный / правильный ответ. Очевидно, что комментирование этих двух строк на самом деле не решает мою проблему. Эта проблема возникает из-за того, что по какой-то причине Google Assistant не распознает контекст, определенный для намерений Names и Location_context, в то время как Dialogflow правильно его распознает. Из-за этого $first_name и $last_name даже не указаны во втором вопросе («Где он живет?»), И поэтому я получаю неполный / неправильный ответ на этот вопрос.

ДЛЯ ОБНОВЛЕННОГО ИЗЛОЖЕНИЯ МОЕЙ ПРОБЛЕМЫ ПОЖАЛУЙСТА, СМОТРИТЕ МОЙ ОТредактированный пост ВЫШЕ.

- ОТВЕТ НА МОЙ ЗАПИСЬ ПОСЛЕ ОБНОВЛЕНИЯ -

Я могу решить свою проблему, если добавлю следующие два параметра в намерение Location_context:

  • имена параметров: имя-имя, фамилия.
  • сущности: @ sys.given-name, @ sys.last-name.
  • значение: # context.given-name, # context.last-name.

Поэтому я по существу передаю значение параметров given-name и last-name из намерения Names в намерение Location_context.

Если я сделаю это, то ветвь contexts ответа json во втором вопросе в Google Assistant, похоже, станет такой:

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

(Опять же, я не могу напрямую проверить вывод json из Google Assistant, но я просто провожу несколько тестов, чтобы понять формат и содержимое ответа json от него)

Таким образом, я могу получить полное имя человека через свой PHP-скрипт и получить правильный ответ («Джон живет в Нью-Йорке») на второй вопрос («Где он живет?»).

Однако мне все еще интересно, почему это необходимо делать, когда в Dialogflow это делается без добавления каких-либо параметров в намерение Location_context ...

Также я не уверен, что таким образом Google Assistant распознает контекст между двумя намерениями, поскольку lifespan снова равен 0 (хотя я получаю то, что хочу получить) ...

Ответ принят как подходящий

Помимо ваших вопросов, здесь много всего происходит. Попробуем разбить их по крупицам.

Почему изначально я получал ошибки в ответе?

Потому что ini_set('display_errors', 'on'); отправляет любые ошибки на стандартный вывод, который вы отправляете обратно в Dialogflow. Парсер Dialogflow, который отправляет данные в Google, был строгим, поэтому дополнительный вывод здесь вызывал проблемы.

Как я могу увидеть, что происходит?

Вы должны регистрировать вещи, используя что-то вроде журнал ошибок(). Это запишет в файл все, что вы хотите, чтобы вы могли видеть точный JSON, полученный из Dialogflow, и именно то, что, по вашему мнению, вы отправляете обратно.

Вы можете использовать это с чем-то вроде

error_log( $request_body );

чтобы точно узнать, какой JSON был отправлен из Dialogflow. Это зарегистрирует тело в системном журнале ошибок (который, вероятно, является HTTP error_log, если вы не установите его в другом месте), чтобы вы могли изучить его и увидеть отправленный вам все.

Хорошо, я вижу, что происходит. Чем отличается JSON?

Потому что в Actions on Google есть дополнительная информация, чем та, которую можно получить через других агентов. Они отправляются вам таким же образом (или должны быть), но их будет больше. Например, вы увидите объект originalRequest, доставленный через JSON.

Однако вся ожидаемая информация должна быть там. Просто больше.

Почему я не могу увидеть, что Dialogflow получает от моего веб-перехватчика, прежде чем изменить данные для отправки в Actions on Google?

Хороший вопрос. Иногда это происходит на вкладке «Отладка» в «agentToAssistantDebug», но не всегда. Вам нужно будет использовать другие инструменты, чтобы точно знать, на что вы отвечаете в рамках тестовой инфраструктуры.

Почему я не получаю контекст context с помощью Actions on Google?

На самом деле вы не опубликовали доказательств того, что это не так. Все, что вы показали, это то, что context[0] не назван «контекст». Вы должны зарегистрировать весь массив context, чтобы увидеть их все с чем-то вроде

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

Вы увидите, что установлено множество контекстов. Сюда входит один с именем actions_capability_screen_output, который создается Actions on Google, чтобы указать, что вы работаете на устройстве, которое может отображаться на экране. Вероятно, он также будет иметь имя actions_capability_audio_output, чтобы указать, что он может озвучивать результат. Он также должен включать один с именем context, который вы установили.

Но почему в этих других контекстах не установлены параметры given-name и last-name?

Потому что эти параметры не были установлены, когда эти контексты были активны.

Вы не можете просто предположить, что параметры будут установлены в первом контексте - вам нужно будет найти контекст, в котором вы их установили, и получить значение из этих конкретных контекстов.

Параметры будут только в тех контекстах, где они установлены. (Фактически, вы можете установить дополнительные параметры в контексте вывода как часть своего ответа.)

Если существует более одного контекста, как мне найти тот, который содержит мои параметры?

Прокрутите массив context и найдите тот, который соответствует ожидаемому имени. Затем вы можете получить оттуда нужные параметры.

Почему Actions on Google сбрасывает срок жизни до 0?

Это не так. Действия в Google делает устанавливают дополнительные контексты (которые вы видите в одном из), которые содержат дополнительную информацию, относящуюся к AoG, и имеют срок жизни 0 (то есть он будет удален после этого раунда, но они просто установят его снова в следующий раз. через). Они устанавливают его на 0, потому что некоторые контексты могут изменяться каждый раз (в частности, какие поверхности поддерживаются).

Есть ли лучший способ сделать это без контекстов?

Не совсем - контексты довольно хороши, и они лучшее решение для этого.

Спасибо за обстоятельный ответ. Позвольте мне ответить на некоторые моменты. Что касается вашей точки 'Why am I not getting the context context with Actions on Google?', я проверил с isset(), существуют ли параметры given-name и last-name, когда задается второй вопрос, а их нет. Кроме того, name в ветви contexts почему-то является "actions_capability_screen_output".

Outcast 04.04.2018 15:47

Что касается вашей точки Is there a better way to do this without contexts?, я полностью согласен, и поэтому я использовал контекст, но я мог делать то, что хотел, в Dialogflow, даже не передавая значение параметров явно, путем определения новых параметров в намерении Location_context. Главный вопрос, на который до сих пор нет ответа, заключается в том, почему вывод json, который попадает в мой PHP-скрипт из Google Assistant, отличается от того, который показан в Dialogflow.

Outcast 04.04.2018 15:50

* вывод json, который достигает моего PHP-скрипта из Google Assistant -> json-вывод, который достигает моего PHP-скрипта при использовании Google Assistant

Outcast 04.04.2018 15:57

Также, честно говоря, я не понимаю вашего мнения о error_log(). Мой PHP-скрипт загружен как приложение на Heroku, так что Dialogflow может отправлять POST-запрос с помощью своего веб-перехватчика. Возможно, мне нужен инструмент для проверки контента, отправляемого с веб-перехватчиков, но я не понимаю, в чем польза error_log() для моей цели. Если я чего-то упускаю, пожалуйста, объясните мне.

Outcast 04.04.2018 16:05

Хм ... Возможно, я получаю больше данных, чем я думал ... позвольте мне немного проверить ... но я должен найти подходящий инструмент, чтобы изучить это должным образом ...

Outcast 04.04.2018 16:36

Хорошо, хорошо .... вы выиграли :) ... очень хороший ответ, и вы были абсолютно правы в своем «Почему я не получаю контекст context с помощью Actions on Google?» раздел....

Outcast 06.04.2018 12:29

Рад, что это помогло!

Prisoner 06.04.2018 12:35

Другие вопросы по теме