Answering Health Questions via SMS with IBM Watson and Twilio

February 10, 2015
Written by

img-video-jeopardy

Q: “Combining these two APIs can let you quickly query a complex health data set via SMS.”
A: “What are IBM Watson and Twilio?”

You probably remember IBM Watson battling humans in Jeopardy. Now developers can access this same power via the Watson Question and Answer API. Currently IBM has exposed the health and travel data sets via the API. I wanted to build an app that lets me send a question about health in an SMS and get a response from the Watson. This app will allow me to trick my friends into being impressed by my expansive knowledge of healthy living. Today I’m going to show you how I did it using IBM Bluemix, the Watson Question and Answer API, Node.js and Twilio. You can try out the finished product by texting a health related question to: (929) 242-6747

What’s In Our Fannypack

We’ll be using the following technologies to build our app:

Cause I’m Hapi

One of my favorite things to do when I’m building an application like this is to treat it as an opportunity to try new technologies I’ve been hearing about. I thought this application would be a fun excuse to use Hapi.js. Hapi.js is a Node.js HTTP server framework, in a similar vein to Express. If you’re wondering a bit more about Hapi and Node.js I’d highly recommend Matt Harrison’s great post “Express to Hapi.js”.

In order to interact with the Watson Question and Answer API we need to deploy this application to IBM Bluemix. To start, let’s just build the Hapi.js “hello world” application and deploy it to Bluemix to make sure we have everything set up correctly. After that we’ll integrate Watson and Twilio.

We can create a new directory on our location machine called twilio-watson and then initialize a new Node.js project in that directory:

mkdir twilio-watson
cd twilio-watson
npm init

Now we can install the Hapi module:

npm install hapi --save

Next, we’ll use the excellent hello world from the Hapi homepage as the foundation for our application:

var Hapi = require('hapi');

// Create a server with a host and port
var server = new Hapi.Server();

server.connection({
   host: 'localhost',
   port: 8000
});

// Add the route
server.route({
   method: 'GET',
   path:'/hello',
   handler: function (req, reply) {
      reply('hello world');
   }
});

// Start the server
server.start();

We need to make a couple of small changes to be able to deploy this app to Bluemix. On Bluemix, our application won’t be running on port 3000 of localhost. Fortunately, Bluemix provides the host and port that our app is running on in environment variables. Let’s update our code to use these variables if they’re available:

// The IP address of the Cloud Foundry DEA (Droplet Execution Agent) that hosts this application:
var host = (process.env.VCAP_APP_HOST || 'localhost');
// The port on the DEA for communication with the application:
var port = (process.env.VCAP_APP_PORT || 3000);

// Create a server with a host and port
var server = new Hapi.Server();
server.connection({
   host: host,
   port: port
});

We need to do one last thing before we deploy – we’re going to create a manifest.yml. We use this file to make sure Bluemix knows how to start our application:

applications:
- name: [app-name]
  command: node index.js

Make sure to replace [app-name] with an unique name for your application. Now let’s connect the Cloud Foundry CLI tool with Bluemix:

cf api https://api.ng.bluemix.net
cf login

Now we can push our application to Bluemix:

cf push

Confirm we’re seeing “hello world” at [app-name].mybluemix.net/hello

Ask and You Shall Receive

Now that we have deployed our first app to Bluemix, we can start integrating Watson. In order to use the Watson API we need to sign up for the service using Cloud Foundry. We can see all our optional services:

cf marketplace

There are a lot of optional services in the Bluemix marketplace. If you scroll through the list you’ll see the question_and_answer service. This is the one we want to add. We can add it like this:

cf create-service question_and_answer question_and_answer_free_plan [app-name]

We’ll also update our manifest.yml file to include the fact that we’re using the qa-service:

applications:
- services:
  - qa-service
  name: twilio-watson-post
  command: node index.js

We can get responses from the Watson API by making a simple POST request. We’ll use the Node.js request module to make this request. Let’s install it and make sure it’s saved to our package.json file:

npm install request --save

Now we can require it in our index.js:

var Hapi = require('hapi'),
    request = require('request');

Like our port and host values, Bluemix will pass us our Watson API credentials in environment variables. We can retrieve them will the following code after we get set our port and host variables:

var service_url, service_username, service_password;
if (process.env.VCAP_SERVICES) {
  console.log('Parsing VCAP_SERVICES');
  var services = JSON.parse(process.env.VCAP_SERVICES);
  //service name, check the VCAP_SERVICES in bluemix to get the name of the services you have
  var service_name = 'question_and_answer';

  if (services[service_name]) {
    var svc = services[service_name][0].credentials;
    service_url = svc.url;
    service_username = svc.username;
    service_password = svc.password;
  } else {
    console.log('The service '+service_name+' is not in the VCAP_SERVICES, did you forget to bind it?');
  }
}

Next we’ll create a new route called /question:

server.route({
  method: 'POST',
  path: '/question',
  handler: function(req, reply) {

  }
});

Within this route we will make a request to Watson and output response. Let’s start by retrieving our question from the POST data and building out the options for our request:

server.route({
  method: 'POST',
  path: '/question',
  handler: function(req, reply) {
     var question = req.payload.Body;
     var options = {
         url: service_url + '/v1/question/healthcare/',
         method: 'POST',
         headers: {
           'X-synctimeout' : '30'
         },
         auth: {
           'user': service_username,
           'password': service_password
         },
         json: {
             'question': {
               'evidenceRequest': {
                 'items': 1 // the number of answers
               },
               'questionText': question
             }
           }
     };
  }
});

Let’s breakdown this code a bit. First we define that we’re making a request to the Watson healthcare question API and that that request will be a POST request. We also are passing the auth credentials we pulled from Bluemix. We’re then passing JSON indicating that we want to receive 1 piece of evidence (which will be an answer) to our question.

Now that we have our options defined we can use the request library to make the request and output our response to the browser:

request(options, function(error, response, body) {
  reply(body[0].question.evidencelist[0].text);
});

Let’s deploy the new version of our application so we can test it:

cf push

This is a great time to make sure our code is working correctly. Let’s quickly test this using curl:

curl --data "Body=How often should I wash my hands?" http://[your-app-url]/question

“Mr. Watson – Come here – I want to see you”

In order to respond to an SMS we need to send back the answer with TwiML. TwiML is a simple XML format that allows us to give Twilio basic instructions of what to do when an incoming phone call or text message comes into our Twilio phone number. We’ll be using the Twilio Node.js module to help generate our TwiML. Let’s install it:

npm install twilio --save

Now let’s switch out the code in the callback of our request to respond with TwiML instead of just the answer text:

request(options, function(error, response, body) {
  var resp = new twilio.TwimlResponse();
  resp.message(body[0].question.evidencelist[0].text);
  reply(resp.toString()).type('text/xml');
});

That’s it! We can now push our application one last time to Bluemix:

cf push

In order for Twilio to know to POST to our URL we need to add it as the Messaging Request URL for our Twilio phone number:

Now the moment of truth. Text a question to your number. Not sure what to ask? Try the question – “How often should I wash my hands?”. Victory!

If you’re not getting a response as expected, then this blog post on debugging your Twilio applications may help. And you can always use the cf logs command to view the logs from your Bluemix application. You can view the final code on github.

What’s Next?

Thanks to Watson and Twilio we can now trick our friends into thinking we have a wealth of health information. If they ask why you keep checking your phone just say you’re getting text messages from a friend. This app just scratches the surface on what you can do with the Watson APIs. Looking to make an improvement? See if you can get the app to work in more languages. Have any questions or want to show off your sick Twilio + Watson hack? You can find me @rickyrobinett or ricky@twilio.com