DialogFlow V2 Webhook - ожидает речевых ответов сразу, а не после асинхронных запросов

У меня есть DialhoFlow V2 node.js webhook.

У меня есть намерение, которое вызывается с помощью действия webhook:

const { WebhookClient } = require('dialogflow-fulfillment');
const app = new WebhookClient({request: req, response: res});

function exampleIntent(app) {

   app.add("Speak This Out on Google Home!");   // this speaks out fine. no error. 
}

Теперь, если у меня есть асинхронный запрос, который успешно завершается, и я делаю app.add в блоке успеха следующим образом:

 function exampleIntent(app) {  
      myClient.someAsyncCall(function(result, err) {
          app.add("This will not be spoken out");  // no dice  :(
      }
      // app.add("but here it works... so it expects it immediately");
  }

... тогда поток диалога не ожидает возврата речи. Я получаю ошибку в объекте Response:

  "message": "Failed to parse Dialogflow response into AppResponse, exception thrown with message: Empty speech response",

Как я могу заставить DialogFlow V2 ждать завершения асинхронных операций Webhook, вместо этого ожидая немедленного речевого ответа?

ПРИМЕЧАНИЕ. Эта проблема появилась только в версии V2. В V1 app.ask отлично работал в хвостовой части асинхронных вызовов.

exampleIntent вызывается основным преобразователем приложения следующим образом:

let actionMap = new Map();
actionMap.set("my V2 intent name", exampleIntent);
app.handleRequest(actionMap);

И мой асинхронный запрос внутри myClient.someAsyncCall использует Promises:

exports.someAsyncCall = function someAsyncCall(callback) {
    var apigClient = getAWSClient(); // uses aws-api-gateway-client
    apigClient.invokeApi(params, pathTemplate, method, additionalParams, body)
    .then(function(result){
        var result = result.data;
        var message = result['message'];
        console.log('SUCCESS: ' + message);
        callback(message, null);  // this succeeds and calls back fine. 
    }).catch( function(error){
        console.log('ERROR: ' + error);
        callback(error, null);
    });
};

1 ответ

Решение

Причина, по которой он работал в V1, заключается в том, что ask() будет на самом деле отправить запрос.

С V2 вы можете позвонить add() несколько раз, чтобы отправить все пользователю в том же ответе. Так что он должен знать, когда он должен отправить сообщение. Это делается как часть работы с ответом вашего обработчика.

Если ваш обработчик синхронен, он немедленно отправляет ответ.

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

Поскольку ваш звонок уже использует Обещания, значит, вы в очень хорошей форме! Важной частью является то, что вы также возвращаете обещание и работаете с ним. Таким образом, что-то вроде этого может быть вашим асинхронным вызовом (который возвращает Promise):

exports.someAsyncCall = function someAsyncCall() {
    var apigClient = getAWSClient(); // uses aws-api-gateway-client
    return apigClient.invokeApi(params, pathTemplate, method, additionalParams, body)
    .then(function(result){
        var result = result.data;
        var message = result['message'];
        console.log('SUCCESS: ' + message);
        return Promise.resolve( message );
    }).catch( function(error){
        console.log('ERROR: ' + error);
        return Promise.reject( error );
    });
};

и тогда ваш обработчик намерений будет что-то вроде

function exampleIntent(app) {  
  return myClient.someAsyncCall()
    .then( function( message ){
      app.add("You should hear this message": message);
      return Promise.resolve();
    })
    .catch( function( err ){
      app.add("Uh oh, something happened.");
      return Promise.resolve();  // Don't reject again, or it might not send the reply
    })
}
Другие вопросы по тегам