Я создал чат-бота, который информирует пользователя о членах моей (расширенной) семьи и о том, где они живут. Я создал небольшую базу данных с MySQL, в которой хранятся эти данные, и извлекаю их с помощью скрипта PHP, когда это уместно, в зависимости от взаимодействия пользователя с чатботом.
Мой чат-бот содержит два намерения в дополнение к Default Fallback Intent
и к Default Welcome Intent
:
Names
Location_context
Первое намерение (Names
) обучается по таким фразам, как «Кто такой Джон Смит?» и имеет выходной контекст (называется context
с продолжительностью 10 вопросов). Возможный ответ на этот вопрос: «Джон — мой дядя». Второе намерение (Location_context
) обучается по таким фразам, как «Где он живет?» и имеет входной контекст (из Names
). Возможный ответ на этот вопрос: «Джон живет в Нью-Йорке».
Names
намерение содержит два параметра:
Эти два параметра представляют полное имя, данное пользователем. 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";
}
?>
В диалоге, после запроса, например, «Кто такой Джон Смит?» и получить правильный ответ «Джон мой дядя». тогда я спрашиваю «где он живет?» и я получаю правильный ответ «Джон живет в Нью-Йорке».
Ответ 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
в обоих вопросах пока явно в диалоге $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, как я делаю это в диалоге?
Здесь много всего происходит в дополнение к вашим вопросам. Давайте попробуем разбить их по кусочкам.
Почему я получаю ошибки в ответе изначально?
Так как ini_set('display_errors', 'on');
отправляет любые ошибки на стандартный вывод, который вы отправляете обратно в Dialogflow. Парсер Dialogflow, который отправляет данные в Google, был строгим, поэтому дополнительный вывод вызывал проблемы здесь.
Как я могу увидеть, что происходит?
Вы должны регистрировать вещи, используя что-то вроде журнал ошибок(). Это запишет в файл все, что вы захотите, так что вы сможете увидеть точный JSON, полученный из Dialogflow, и именно то, что, по вашему мнению, вы отправляете обратно.
Вы можете использовать это с чем-то вроде
error_log( $request_body );
чтобы точно увидеть, что такое JSON, который был отправлен из Dialogflow. Это запишет тело в системный журнал ошибок (который, вероятно, HTTP error_log, если вы не установили его в другом месте), так что вы можете проверить его и увидеть все это отправляется вам.
Хорошо, я вижу, что происходит. Чем отличается JSON?
Потому что действия в Google имеют дополнительную информацию, чем то, что доступно через других агентов. Они отправляются вам таким же образом (или должны быть), но их будет больше. Например, вы увидите originalRequest
объект доставлен через JSON.
Тем не менее, вся информация, которую вы ожидаете, должна быть там. Просто больше об этом.
Почему я не вижу, что Dialogflow получает от моего веб-крючка, прежде чем изменить что-то, что нужно отправить в Действия в Google?
Хороший вопрос. Иногда это регистрируется на вкладке «Отладка» в «agentToAssistantDebug», но не всегда. Вам нужно будет использовать другие инструменты, чтобы увидеть, что именно вы отвечаете, как часть тестовой инфраструктуры.
Почему я не получаю context
контекст с Действиями в Google?
Вы на самом деле не опубликовали доказательства того, что это не так. Все, что вы показали, это context[0]
не называется «контекст». Вы должны войти весь context
массив, чтобы увидеть все из них с чем-то вроде
error_log( $json->result->context );
Что вы увидите, так это то, что было задано много контекстов. Это включает в себя один по имени actions_capability_screen_output
который создан в Google для действий, чтобы показать, что вы работаете на устройстве, которое может отображаться на экране. Это, вероятно, также будет иметь имя actions_capability_audio_output
чтобы указать это может говорить результат. Он также должен включать один по имени context
, который вы установили.
Но почему эти другие контексты не имеют given-name
а также last-name
параметры установлены?
Потому что эти параметры не были установлены, когда эти контексты были активны.
Вы не можете просто предполагать, что параметры будут установлены в первом контексте — вам нужно будет найти контекст, в котором вы их установили, и получить значение из этих конкретных контекстов.
Параметры будут только в тех контекстах, где они установлены. (На самом деле, вы можете установить дополнительные параметры в контекстах вывода как часть вашего ответа.)
Если существует более одного контекста, как мне найти тот, который содержит мои параметры?
Перебрать context
массив и искать тот, который соответствует имени, которое вы ожидаете. Затем вы можете получить параметры, которые вы хотите оттуда.
Почему Actions в Google сбрасывает продолжительность жизни до 0?
Это не так. Действия в Google делает установить дополнительные контексты (которые вы видите одним из), которые содержат дополнительную информацию, специфичную для AoG, и имеют срок службы 0 (то есть он будет удален после этого раунда, но они просто установят его снова в следующий раз). Они устанавливают его на 0, потому что некоторые контексты могут меняться каждый раз (в частности, какие поверхности поддерживаются).
Есть ли лучший способ сделать это без контекста?
Не совсем — контексты довольно классные, и они являются лучшим решением для этого.
— ОТВЕТЬТЕ НА МОЮ ПОЧТУ ПЕРЕД ОБНОВЛЕНИЕМ —
Наконец я обнаружил, что получаю 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
цель:
Поэтому я по сути передаю значение 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 (хотя я получаю то, что хочу) …
Я не самый большой эксперт по PHP, но я немного его использовал. Я думаю, что ваша проблема в том, что Dialogflow не интерпретирует ваш результат как JSON, а скорее как простую строку.
Из ошибки я вижу:
Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $.
Предполагая, что ваш ответ действительный JSON тогда вам может потребоваться вручную сообщить Dialogflow, что ответ должен быть интерпретируется как JSON.
Похоже, что вы уже делаете это в верхней части своего ответа PHP, но, возможно, вам следует убедиться, что в ответе JSON нет ничего необычного, что могло бы вызвать вышеуказанную ошибку.