Search code examples
node.jsbotframework

Using postBack to send bot text message using BotFramework v4 and Node.js


I am trying to send a postBack text message to my bot but I don't know the right syntax.

Here is my code:

if (postback.payload == "WHAT_IS_MENTAL_HEALTH") {
      await turnContext.sendActivity("TO-DO: Forward on 'What Is Mental Health?' to Bot Handler");
      ActionTypes.postBack("What Is Mental Health?");
}

I'm trying to forward on the text "What Is Mental Health?" to my bot so it will pull back the QnA Maker response for that question.

The steps for this are as follows:

  1. User clicks a button on a Facebook Messenger Generic Template Card (e.g. “What Is Mental Health?” Button)
  2. The button sends a postBack payload to the bot (e.g. “WHAT_IS_MENTAL_HEALTH”)
  3. I am detecting the postBack payload from Facebook Messenger (e.g if (postBack.payload == “WHAT_IS_MENTAL_HEALTH”))
  4. Once that particular postBack payload is detected I then want to send an additional postBack to my bot as text (e.g. “What Is Mental Health?”) so it can be interpreted by my QnA and respond with the correct answer which has been programmed into my QnA Knowledge Base.

Solution

  • Facebook Events and the Bot Framework

    When Facebook sends an event to your bot, it sends an Activity with an Event ActivityType. For some events, the event data is in the Activity.Value property. For other events, like a PostBack from a Quick Reply, the activity will be a Message and the data will be in Activity.ChannelData. For example, your bot might receive a postBack event as an activity like this:

    {
        channelId: 'facebook',
        [...]
        type: 'message',
        channelData: {
            recipient: {...},
            sender: {...},
            message: {
                [...],
                quick_reply: {
                    [...],
                    payload: '<your payload>'
                }
            }
        }
    }
    

    Handling Facebook Events

    This answer is going to pull heavily from the Facebook Events Sample. I highly recommend looking at that for additional help.

    Capture Messages and Events

    First, you want to capture the facebook messages and events with onMessage() and onEvent():

    this.onMessage(async (turnContext) => {
        console.log('Processing a Message Activity.');
    
        // Show choices if the Facebook Payload from ChannelData is not handled
        if (!await this.processFacebookPayload(turnContext, turnContext.activity.channelData)) {
            if (turnContext.activity.channelId !== 'facebook') {
                await turnContext.sendActivity('This sample is intended to be used with a Facebook bot.');
            }
            await this.showChoices(turnContext);
        }
    });
    
    this.onEvent(async (turnContext) => {
        console.log('Processing an Event Activity.');
    
        // Analyze Facebook payload from EventActivity.Value
        await this.processFacebookPayload(turnContext, turnContext.activity.value);
    });
    

    Process the Messages/Events

    Facebook can send many types of events. You may want to use an if or switch statement to handle each type:

    async processFacebookPayload(turnContext, data) {
        // At this point we know we are on Facebook channel, and can consume the Facebook custom payload present in channelData.
        const facebookPayload = data;
        if (facebookPayload) {
            if (facebookPayload.postback) {
                // Postback
                await this.onFacebookPostback(turnContext, facebookPayload.postback);
                return true;
            } else if (facebookPayload.optin) {
                // Optin
                await this.onFacebookOptin(turnContext, facebookPayload.optin);
                return true;
            [...]
        }
        return false;
    }
    

    Specifically, Handle a PostBack

    The sample just does:

    async onFacebookPostback(turnContext, postback) {
        console.log('Postback message received.');
        // TODO: Your postBack handling logic here...
    
        // Answer the postback and show choices
        await turnContext.sendActivity('Are you sure?');
        await this.showChoices(turnContext);
    }
    

    As you want to route the question to QnA Maker, you might (using the QnA Maker Sample as guidance):

    async onFacebookPostback(turnContext, postback) {
        // qnaMaker.getAnswers doesn't accept string input, so we need to adjust our turnContext
        //  to match what it expects, which is a string in Activity.Text
        turnContext.activity.text = postback.payload;
        const qnaResults = await this.qnaMaker.getAnswers(turnContext);
    
        // If an answer was received from QnA Maker, send the answer back to the user.
        if (qnaResults[0]) {
            await turnContext.sendActivity(qnaResults[0].answer);
    
        // If no answers were returned from QnA Maker, reply with help.
        } else {
            await turnContext.sendActivity('No QnA Maker answers were found.');
        }
    }