wanstan wanstan - 29 days ago 28
Node.js Question

Adding 'typing_on' sender action bubble before each response from Wit.ai chatbot

I've built a flow-base chat bot using FB messenger, Wit.ai and node.js. It's working well, but in order to make the interaction seem more natural I want my bot to pause for a short while and appear to be typing each of its responses.

I want the 'typing' bubble to be displayed briefly before each response my bot sends, ideally being able to define the time the bubble is visible for before the response is sent. At the moment there are sections of my conversation where the bot sends consecutive messages and they are all sent too quickly at once.

The FB Messenger Send API says that either the 'message' or 'sender_action' property must be set. I've tried setting both like so:

const fbMessage = (id, text) => {

if(fruits.apples.indexOf(text) >= 0 || fruits.oranges.indexOf(text) >= 0) {

var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});


} else {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: { text },
});
}

const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};


But I get the following error:

enter image description here

I'm not sure what I need to do - I'm assuming I've got to set up some sort of 'sender_action' bot response that's triggered before each conversational response but I don't know how I'd do this.

Answer

Got it working, can't work out how to control bubble timing but it's fine for now. The code below will make the typing bubble display briefly before each of my bot's responses without mucking up the flow of my conversation.

FB Messenger code:

const typingBubble = (id, text) => {

  var body = JSON.stringify({
      recipient: { id },
      "sender_action":"typing_on"
  });

  const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
  return fetch('https://graph.facebook.com/me/messages?' + qs, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body,
  })
  .then(rsp => rsp.json())
  .then(json => {
    if (json.error && json.error.message) {
      throw new Error(json.error.message);
    }
    return json;
  });
};

const fbMessage = (id, text) => {

  if(scenarioCombos.trends.indexOf(text) >= 0 || scenarioCombos.disruptions.indexOf(text) >= 0) {

    var body = JSON.stringify({
        recipient: { id },
        message: {
            attachment: {
                  "type": "image",
                  "payload": {
                      "url": text
                  }
              }
          },
    });


  } else {
    var body = JSON.stringify({
        recipient: { id },
        message: { text },
    });
  }

  const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
  return fetch('https://graph.facebook.com/me/messages?' + qs, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body,
  })
  .then(rsp => rsp.json())
  .then(json => {
    if (json.error && json.error.message) {
      throw new Error(json.error.message);
    }
    return json;
  });
};

Wit.ai send action code (within 'actions'):

send({sessionId}, {text}) {
    const recipientId = sessions[sessionId].fbid;
    if (recipientId) {
      return typingBubble(recipientId, text), fbMessage(recipientId, text)
    .then(() => null)
    .catch((err) => {
        console.error(
        'Oops! An error occurred while forwarding the response to',
        recipientId,
        ':',
        err.stack || err
        );
    });
    } else {
    console.error('Oops! Couldn\'t find user for session:', sessionId);
    return Promise.resolve()
    }
},