简体   繁体   中英

Facebook Messenger bot in Node.js

I am trying to make a call to an external API but every time I make an https or any kind request, my bot just gets frozen.

I have tried making the API using different GET method but it just get's stuck whenever I try to make an API call.

[enter image description here][1]

The code to make an API call is in the function ==> 'function sendTextMessage(recipientId, messageText)'

'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const path = require('path');

var Bot = require('messenger-bot')


const http = require('http');
const url = require('url');

//Natural language processing Library
var natural = require('natural');


//Chekc stocks 
var checkStocks = false;



// The rest of the code implements the routes for our Express server.
let app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// Webhook validation
app.get('/webhook', function(req, res) {
  if (req.query['hub.mode'] === 'subscribe' &&
      req.query['hub.verify_token'] === process.env.VERIFY_TOKEN) {
    console.log("Validating webhook");
    res.status(200).send(req.query['hub.challenge']);
  } else {
    console.error("Failed validation. Make sure the validation tokens match.");
    res.sendStatus(403);          
  }
});

// Display the web page
app.get('/', function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(messengerButton);
  res.end();
});

// Message processing
app.post('/webhook', function (req, res) {
  console.log(req.body);
  var data = req.body;

  // Make sure this is a page subscription
  if (data.object === 'page') {

    // Iterate over each entry - there may be multiple if batched
    data.entry.forEach(function(entry) {
      var pageID = entry.id;
      var timeOfEvent = entry.time;

      // Iterate over each messaging event
      entry.messaging.forEach(function(event) {
        if (event.message) {
          receivedMessage(event);
        } else if (event.postback) {
          receivedPostback(event);   
        } else {
          console.log("Webhook received unknown event: ", event);
        }
      });
    });

    // Assume all went well.
    //
    // You must send back a 200, within 20 seconds, to let us know
    // you've successfully received the callback. Otherwise, the request
    // will time out and we will keep trying to resend.
    res.sendStatus(200);
  }
});


//HttpClient to make Request to api's


// Incoming events handling
function receivedMessage(event) {
  var senderID = event.sender.id;
  var recipientID = event.recipient.id;
  var timeOfMessage = event.timestamp;
  var message = event.message;

  console.log("Received message for user %d and page %d at %d with message:", 
    senderID, recipientID, timeOfMessage);
  console.log(JSON.stringify(message));

  var messageId = message.mid;

  var messageText = message.text;
  var messageAttachments = message.attachments;

  if (messageText) {
    // If we receive a text message, check to see if it matches a keyword
    // and send back the template example. Otherwise, just echo the text we received.
    switch (messageText) {
      case 'generic':
        sendGenericMessage(senderID);
        break;

      default:
        sendTextMessage(senderID, messageText);
    }
  } else if (messageAttachments) {
    sendTextMessage(senderID, "Message with attachment received");
  }
}

function receivedPostback(event) {
  var senderID = event.sender.id;
  var recipientID = event.recipient.id;
  var timeOfPostback = event.timestamp;

  // The 'payload' param is a developer-defined field which is set in a postback 
  // button for Structured Messages. 
  var payload = event.postback.payload;

  console.log("Received postback for user %d and page %d with payload '%s' " + 
    "at %d", senderID, recipientID, payload, timeOfPostback);

  // When a postback is called, we'll send a message back to the sender to 
  // let them know it was successful

  sendTextMessage(senderID, "Postback called");
}

//////////////////////////
// Sending helpers
//////////////////////////
function sendTextMessage(recipientId, messageText) {
  // messageText.strip();
  // messageText.lowercase();

  var reply = messageText.toLowerCase();

  //Kunal's Code



  if (reply == 'hey') {
   messageText = 'Hello, welcome to the future';

    }
  else if(reply =='GET_STARTED_PAYLOAD'){
    messageText = 'I am Charles, your personal assistant, you can ask me about investment options.'
  }
  else if(reply =='check stocks')
  {
    messageText = "Can you please tell me the stock symbol for the stock you want to check?";
    checkStocks = true;
  }
  else if(checkStocks)
  {
    console.log("stocks");
    var url = 'https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=AAPL&interval=1min&apikey=I0VJYEWD3R37FUFTXU';


    var request = http.get(url, function(response) {
      //console.log(response.statusCode
      messageText = response.statusCode;
      //You need to implement 'data' for the 'end' to get triggered eventually.

    });


    }

  else{
    messageText="I didn't get you, can you please repeat?"
  }





  // var invalid = 0;
    // if ((messageText.indexOf('Hi')>-1)||(messageText.indexOf('Hello')>-1)||(messageText.indexOf('Hey')>-1)||(messageText.indexOf('Howdy')>-1)) {
    //   messageText = 'Hello, welcome to the future';
    //   invalid = 1;
    // }
    // if ((messageText.indexOf('How')>-1)&&(messageText.indexOf('you')>-1)) {
    //   messageText = 'I am doing well, thank you! How are you?';
    //   invalid = 1;
    // }
    // if ((messageText.indexOf('Who')>-1)&&(messageText.indexOf('you')>-1)) {
    //   messageText = 'I am Charles, your personal assistant, you can ask me about time';
    //   invalid = 1;
    // }
    //  if ((messageText.indexOf('How')>-1)&&(messageText.indexOf('going')>-1)) {
    //   messageText = 'It is going really well, thank you! What about yourself?';
    //   invalid = 1;
    // }
    // if ((messageText.indexOf('What')>-1)&&(messageText.indexOf('your')>-1)&&(messageText.indexOf('name')>-1)) {
    //   messageText = 'I am Charles, your personal assistant, you can ask me about time';
    //   invalid = 1;
    // }
    // if ((messageText.indexOf('What')>-1)&&(messageText.indexOf('time')>-1)) {
    //   messageText = 'It is time for you to get a watch';
    //   invalid = 1;
    // }
    // if (invalid == 0) {
    //   messageText = 'Very well'
    //   invalid = 0;
    // }


  var messageData = {
    recipient: {
      id: recipientId
    },
    message: {
      text: messageText
    }
  };



    callSendAPI(messageData);
}

//Following function can be used for the stock links we wish to implement 
//Right now if you type 'generic' it spits  out a few buttons and URL to Oculus Rift 

function sendGenericMessage(recipientId) {
  var messageData = {
    recipient: {
      id: recipientId
    },
    message: {
      attachment: {
        type: "template",
        payload: {
          template_type: "generic",
          elements: [{
            title: "rift",
            subtitle: "Next-generation virtual reality",
            item_url: "https://www.oculus.com/en-us/rift/",               
            image_url: "http://messengerdemo.parseapp.com/img/rift.png",
            buttons: [{
              type: "web_url",
              url: "https://www.oculus.com/en-us/rift/",
              title: "Open Web URL"
            }, {
              type: "postback",
              title: "Call Postback",
              payload: "Payload for first bubble",
            }],
          }, {
            title: "touch",
            subtitle: "Your Hands, Now in VR",
            item_url: "https://www.oculus.com/en-us/touch/",               
            image_url: "http://messengerdemo.parseapp.com/img/touch.png",
            buttons: [{
              type: "web_url",
              url: "https://www.oculus.com/en-us/touch/",
              title: "Open Web URL"
            }, {
              type: "postback",
              title: "Call Postback",
              payload: "Payload for second bubble",
            }]
          }]
        }
      }
    }
  }; 

  callSendAPI(messageData);
}

function callSendAPI(messageData) {
  request({
    uri: 'https://graph.facebook.com/v2.6/me/messages',
    qs: { access_token: process.env.PAGE_ACCESS_TOKEN },
    method: 'POST',
    json: messageData
  }, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var recipientId = body.recipient_id;
      var messageId = body.message_id;

      console.log("Successfully sent generic message with id %s to recipient %s", 
        messageId, recipientId);
    } else {
      console.error("Unable to send message.");
      console.error(response);
      console.error(error);
    }
  }); 


  var url = 'http://graph.facebook.com/517267866/?fields=picture';

  http.get(url, function(res){
      var body = '';

      res.on('data', function(chunk){
          body += chunk;
      });

      res.on('end', function(){
          var fbResponse = JSON.parse(body);
          console.log("Got a response: ", fbResponse.picture);
      });
  }).on('error', function(e){
        console.log("Got an error: ", e);
});
}


function stocksSendAPI()
{




}

// Set Express to listen out for HTTP requests
var server = app.listen(process.env.PORT || 3000, function () {
  console.log("Listening on port %s", server.address().port);
});

The error is in this part of the code:

var request = http.get(url, function(response) {
  messageText = response.statusCode;

});

The function(response {...} is an asynchronous call, meaning it is run whenever the API returns the response, not immediately after the preceding line. This means that when you get to

callSendAPI(messageData);

the variable messageData has not necessarily been initiated, so it won't run as you were hoping it would. To avoid this, you need to call that function after you know messageData has been initialised by moving it to here:

var request = http.get(url, function(response) {
  messageText = response.statusCode;
  //Initialise the messageData object here
  callSendAPI(messageData);
});

Another tip: if that's your real API key in the URL, you should remove it from this post, and also use it in an environment variable in your code, especially if you're using Git or something to store it non-locally.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM