Поток Google Ассистента с несколькими обработчиками actions_intent_OPTION

У меня есть веб-перехватчики, настроенные с помощью Dialogflow для шаблонного проекта начального пользовательского интерфейса чат-бота I Занимаюсь на Github. У меня есть бот, интегрированный через Facebook Messenger и Google Assistant. Все Facebook работает нормально, потому что действия отправляют обратно строки, и с ними легко справиться. Но когда Google Assistant пытается обработать элементы типа "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec", для обработки ответа в событии Dialogflow требуется actions_intent_OPTION. Если в моем приложении есть только один, он работает нормально, но когда я добавляю второй элемент списка / элемент карусели типа OptionValueSpec, поток перекрывается. У меня есть подробности на прикрепленном изображении. Я предполагаю, что для обработки списка требуется actions_intent_OPTION, но когда я помещаю это в несколько намерений в разделе событий, поток не знает, как с этим справиться.

Сравнение Facebook Messenger (работающего) с Google Assistant (с ошибкой)

введите здесь описание изображения

Подробный полноэкранный вид Google Assistant

введите здесь описание изображения

Ответы, отправленные в Dialogflow, которые впоследствии будут отправлены в Google Actions ...

Точные ответы, связанные с изображениями пользовательского интерфейса выше.

// working as expected

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "Hey there! This is a guided tour of common components between Facebook Messenger and Google Assistant."
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "You can start coding the sample project at github.com/ianrichard."
        }
      }
    ],
    "suggestions": [{
        "title": "Show me demos!"
      },
      {
        "title": "Show code & docs"
      }
    ]
  }
}

// working as expected

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "Animated GIFs are always fun to add to the mix!"
        }
      },
      {
        "basicCard": {
          "image": {
            "url": "https://somewebsite.com/colbert.gif",
            "accessibilityText": "Stephen Colbert at the beginning of the show being happy."
          }
        }
      }
    ],
    "suggestions": [{
      "title": "What about a card?"
    }]
  }
}

// working as expected

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "Absolutely!"
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "Named for a winding stretch of Hill Country highway, Devil’s Backbone is a Belgian-style tripel. Featuring a beautiful pale-golden color, this ale’s spicy hops and Belgian yeast work together to create a distinctive flavor and aroma. Don’t let the light color fool you, this one has a dark side too. Traditional Belgian brewing techniques add strength without increasing heaviness."
        }
      },
      {
        "basicCard": {
          "image": {
            "url": "https://somewebsite.com/devils-backbone.jpg",
            "accessibilityText": "Devil’s Backbone"
          },
          "title": "Devil’s Backbone",
          "subtitle": "Belgian-Style Tripel",
          "buttons": [{
            "title": "Read More",
            "openUrlAction": {
              "url": "https://realalebrewing.com/beers/devils-backbone/"
            }
          }]
        }
      }
    ],
    "suggestions": [{
      "title": "How about a list?"
    }]
  }
}

// working as expected

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "Absolutely!"
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "Who’s your favorite GOT character!?"
        }
      }
    ]
  },
  "systemIntent": {
    "intent": "actions.intent.OPTION",
    "data": {
      "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
      "listSelect": {
        "items": [{
            "optionInfo": {
              "key": "tyrion"
            },
            "title": "Tyrion Lannister",
            "description": "Peter Dinklage",
            "image": {
              "url": "https://somewebsite.com/got-tyrion.jpg",
              "accessibilityText": "Tyrion Lannister"
            }
          },
          {
            "optionInfo": {
              "key": "daene"
            },
            "title": "Daenerys Targaryen",
            "description": "Emilia Clarke",
            "image": {
              "url": "https://somewebsite.com/got-daenerys.jpg",
              "accessibilityText": "Daenerys Targaryen"
            }
          },
          {
            "optionInfo": {
              "key": "jon"
            },
            "title": "Jon Snow",
            "description": "Kit Harington",
            "image": {
              "url": "https://somewebsite.com/got-jon.jpg",
              "accessibilityText": "Jon Snow"
            }
          }
        ]
      }
    }
  }
}

// if two events with the same actions_intent_OPTION are defined, it goes straight to the end and the list option handler is never invoked

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "The end"
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "Well, that’s the end of the demo.  Hope you enjoyed!"
        }
      }
    ],
    "suggestions": [{
      "title": "Start over"
    }]
  }
}

// otherwise, it will show the last carousel


{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "I drink and I know things!"
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "What are you going to buy your wife from Tiffany?"
        }
      }
    ]
  },
  "systemIntent": {
    "intent": "actions.intent.OPTION",
    "data": {
      "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
      "carouselSelect": {
        "items": [{
            "optionInfo": {
              "key": "sunglasses"
            },
            "title": "Aviator Sunglasses",
            "description": "$360",
            "image": {
              "url": "https://somewebsite.com/tiffany-glasses.jpg",
              "accessibilityText": "Aviator Sunglasses"
            }
          },
          {
            "optionInfo": {
              "key": "ring"
            },
            "title": "Infinity Ring",
            "description": "$200",
            "image": {
              "url": "https://somewebsite.com/tiffany-ring.jpg",
              "accessibilityText": "Infinity Ring"
            }
          },
          {
            "optionInfo": {
              "key": "earrings"
            },
            "title": "Soleste Earrings",
            "description": "$5,600",
            "image": {
              "url": "https://somewebsite.com/tiffany-earrings.jpg",
              "accessibilityText": "Soleste Earrings"
            }
          },
          {
            "optionInfo": {
              "key": "pendant"
            },
            "title": "Infinity Pendant",
            "description": "$250",
            "image": {
              "url": "https://somewebsite.com/tiffany-necklace.jpg",
              "accessibilityText": "Infinity Pendant"
            }
          },
          {
            "optionInfo": {
              "key": "watch"
            },
            "title": "East West Mini",
            "description": "$7,500",
            "image": {
              "url": "https://somewebsite.com/tiffany-watch.jpg",
              "accessibilityText": "East West Mini"
            }
          }
        ]
      }
    }
  }
}

// but the carousel option handler isn't processed correctly :( - keeps repeating this same thing.

{
  "richResponse": {
    "items": [{
        "simpleResponse": {
          "textToSpeech": "What!? None of them?"
        }
      },
      {
        "simpleResponse": {
          "textToSpeech": "What are you going to buy your wife from Tiffany?"
        }
      }
    ]
  },
  "systemIntent": {
    "intent": "actions.intent.OPTION",
    "data": {
      "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
      "carouselSelect": {
        "items": [{
            "optionInfo": {
              "key": "sunglasses"
            },
            "title": "Aviator Sunglasses",
            "description": "$360",
            "image": {
              "url": "https://somewebsite.com/tiffany-glasses.jpg",
              "accessibilityText": "Aviator Sunglasses"
            }
          },
          {
            "optionInfo": {
              "key": "ring"
            },
            "title": "Infinity Ring",
            "description": "$200",
            "image": {
              "url": "https://somewebsite.com/tiffany-ring.jpg",
              "accessibilityText": "Infinity Ring"
            }
          },
          {
            "optionInfo": {
              "key": "earrings"
            },
            "title": "Soleste Earrings",
            "description": "$5,600",
            "image": {
              "url": "https://somewebsite.com/tiffany-earrings.jpg",
              "accessibilityText": "Soleste Earrings"
            }
          },
          {
            "optionInfo": {
              "key": "pendant"
            },
            "title": "Infinity Pendant",
            "description": "$250",
            "image": {
              "url": "https://somewebsite.com/tiffany-necklace.jpg",
              "accessibilityText": "Infinity Pendant"
            }
          },
          {
            "optionInfo": {
              "key": "watch"
            },
            "title": "East West Mini",
            "description": "$7,500",
            "image": {
              "url": "https://somewebsite.com/tiffany-watch.jpg",
              "accessibilityText": "East West Mini"
            }
          }
        ]
      }
    }
  }
}

Ссылки на намерения  введите здесь описание изображения


person Ian Smith    schedule 18.10.2017    source источник
comment
У меня есть довольно хорошее представление о причине и о том, как исправить, но это поможет, если вы обновите свой вопрос, включив в него снимки экрана с двумя намерениями, которые вы пытаетесь сопоставить с actions_intent_OPTION.   -  person Prisoner    schedule 19.10.2017
comment
@Prisoner - я добавил более подробные снимки экрана всего GA, JSON, отправленный в Dialogflow (который впоследствии переходит в GA), а также настройки намерения Dialogflow. Я пробовал использовать строки вместо сущностей, но я все равно обрабатываю ответ вручную в обработчике веб-перехватчика для Google, поэтому на самом деле это не имеет значения. Я также попытался создать собственные имена событий вместо использования actions_intent_OPTION, но при этом GA проигнорирует выбранный элемент.   -  person Ian Smith    schedule 19.10.2017


Ответы (2)


НАКОНЕЦ работает! Спасибо, @Prisoner!

В Dialogflow ...

  1. Первый список, определите выходной контекст
  2. Второй список, определите контекст ввода и контекст вывода
  3. Вопрос после второго списка, определите контекст ввода

В вашем веб-перехватчике ...

(Недостающий кусок головоломки, из-за которого он заработал) Установите контекст вывода для параметров списка

{
    "speech": "",
    "displayText": "",
    "data": { "google": { ... } },
    "contextOut": [
        {
            "name": "carouselExample",
            "lifespan": 0,
            "parameters": null
        }
    ]
}
person Ian Smith    schedule 19.10.2017
comment
Вероятно, вы не хотите срок жизни 0, так как это немедленно удалит контекст или очистит этот контекст. Вероятно, лучше всего будет продолжительность жизни 1. - person Prisoner; 19.10.2017

Вообще говоря, проблема в том, что Dialogflow не знает, где вы находитесь в разговоре, когда получает событие action_intent_OPTION. Для этого события он не пытается выполнить сопоставление сущностей, но проблема диалогового контекста является проблемой в целом (что происходит, например, если у вас есть две разные карусели с перекрывающимися ответами?).

Решение двоякое:

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

  2. Затем вы можете различать два намерения с помощью события option, указав, для какого контекста каждое из них должно запускаться. Dialogflow будет соответствовать как событию, так и контексту, чтобы определить наилучшее намерение для использования.

person Prisoner    schedule 19.10.2017
comment
Спасибо, @Prisoner! Добавлен ответ ниже, потому что комментарий не допускал большого количества текста и форматированной разметки. - person Ian Smith; 19.10.2017
comment
Большой! Если это помогло, всегда приветствуется голос за. - person Prisoner; 19.10.2017
comment
@IanSmith, можете ли вы опубликовать свой код веб-перехватчика, который вы используете для обработки запросов? Совет actions_intent_OPTION был очень полезен .... любопытно посмотреть, как вы вызываете намерения на основе выбора пользователя. - person JWoodall; 15.11.2018
comment
@JWoodall - Просто помните, вы (разработчик) не вызываете Intents. Пользователи запускают намерения на основе текущего состояния (определяемого активными контекстами) и того, что они говорят или делают (в данном случае события). - person Prisoner; 15.11.2018
comment
(Если у вас все еще есть проблемы, публикация намерений и кода, который вы используете в качестве нового вопроса SO, может помочь нам помочь вам с проблемой и помочь другим с аналогичными проблемами.) - person Prisoner; 15.11.2018