Search code examples
node.jsibm-cloudibm-watsonwatson-conversationwatson-discovery

Node.js - Combine IBM Watson Discovery and Conversation Services


I know this may seem complicated but I have spent a week and a half trying to do this and can not figure it out. Hopefully someone can point me in the right direction. Thank you so much!

I am working with IBM Watson and Node.js to create a conversation bot. I have created the bot and used one of IBM's example programs (Conversation-Simple) to make a website to interact with the bot. Everything with it works. I am now trying to use Watson's Discovery to search documents and answer a question with the query response. I have Discovery working where you can query it and have a Node.js program to query it.

I am now trying to connect the two! When Conversation is ready to query Discovery it will move to the intent called query.

It looks like this is where Watson gives the response and the variable of the response is currentText. I could be wrong but it looks like it is.

  function buildMessageDomElements(newPayload, isUser) {
    var textArray = isUser ? newPayload.input.text : newPayload.output.text;
    if (Object.prototype.toString.call( textArray ) !== '[object Array]') {
      textArray = [textArray];
    }
    var messageArray = [];

    textArray.forEach(function(currentText) {
      if (currentText) {
        var messageJson = {
          // <div class='segments'>
          'tagName': 'div',
          'classNames': ['segments'],
          'children': [{
            // <div class='from-user/from-watson latest'>
            'tagName': 'div',
            'classNames': [(isUser ? 'from-user' : 'from-watson'), 'latest', ((messageArray.length === 0) ? 'top' : 'sub')],
            'children': [{
              // <div class='message-inner'>
              'tagName': 'div',
              'classNames': ['message-inner'],
              'children': [{
                // <p>{messageText}</p>
                'tagName': 'p',
                'text': currentText
              }]
            }]
          }]
        };
        messageArray.push(Common.buildDomElement(messageJson));
      }
    });

    return messageArray;
  }

When it goes to respond here (or if it is somewhere else) how can I check if the intent is query and if it is query Watson Discovery?

This is how I currently query Discovery:

url2 = 'fakeURL'

var request = require("request");
var myJSON = require("JSON");
global var body1;
function getMyBody(url, callback) {
  request(
  {
    url: url,
    auth: {'user': 'fakeUsername','pass': 'fakePassword'},
    json: true
  },
  function (error, response, body) {
    if (error || response.statusCode !== 200) {
      return callback(error || {statusCode: response.statusCode});
    }
    else{
      callback(null, JSON.parse(JSON.stringify(body.results)));
    }
  });
}

getMyBody(url2, function test8(err, body) {
    body1 = body[0];
    console.log(body1)
  }
);

This code currently prints:

{ id: 'a3990d05fee380f8d0e9b99fa87188a7',
    score: 1.0697575,
    os: { OperatingSystem: 'Windows 10 Professional' },
    price: '174.99',
    text: 'Lenovo ThinkCentre M58 Business Desktop Computer, Intel Core 2 Duo 30 GHz Processor, 8GB RAM, 2TB Hard Drive, DVD, VGA, Display Port, RJ45, Windows 10 Professional (Certified Refurbished)',
    url: 'https://www.amazon.com/Lenovo-ThinkCentre-M58-Professional-Refurbished/dp/B01M4MD9C1?SubscriptionId=AKIAJXXNMXU323WLP4SQ&tag=creek0a-20&linkCode=xm2&camp=2025&creative=165953&creativeASIN=B01M4MD9C1',
    highlight: { text: [Array] } }

The response to the user I want to be the value of text and the value of URL.

This is the whole program from IBM https://github.com/watson-developer-cloud/conversation-simple


Solution

  • Like this example from IBM Developers: conversation-with-discovery. You can follow the same logic programming. But I really recommend check out the project and the video in the end of this answer.

    Summary:

    You can see in the workspace, the call for discovery is one action variable inside the Advanced JSON (Dialog node) called call_discovery.

    "action":{"call_discovery: ""},

    Basically, have one intent with the name out_of_scope, because if the user tells something that doesn't have any answer in the intents or some conditions in the Conversation, the call for discovery will happen and return one object with the documents according to the message from user.

    Create one context variable inside the Conversation service:

    {
      "context": {
        "callDiscovery": true
      },
      "output": {
        "text": {
          "values": [
            "Wait for the response, I'll check out."
          ],
          "selection_policy": "sequential"
        }
      }
    }
    

    After creates one context variable (Example: "callDiscovery": true) inside the Node in your Chatbot in the Advanced JSON for call the discovery service, you need to use code for identify if you arrived at the part where you need to make call for Discovery. Will be something like using the function updateMessage inside the conversation-simple example:

    function updateMessage(input, response) {
      var callDiscovery ;
      if (!response.output) {
        response.output = {};
    
        //THE CONTEXT VARIABLE callDiscovery
      } else if (response.context.callDiscovery === true){
          //CREATE ONE NEW FUNCTION WITH YOUR CODE
          getMyBody(url, callback, response); //response parameter for send the message
        }
    }
    

    And, in your function getMyBody (THE FUNCTION that returns the prints in your Question[id, text, url, etc]), you need to send the message to the user, something like:

    url2 = 'fakeURL'
    
    var request = require("request");
    var myJSON = require("JSON");
    var body1;
    function getMyBody(url, callback, response) {
      request(
      {
        url: url,
        auth: {'user': 'fakeUsername','pass': 'fakePassword'},
        json: true
      },
      function (error, response, body) {
        if (error || response.statusCode !== 200) {
          return callback(error || {statusCode: response.statusCode});
        }
        else{
          callback(null, JSON.parse(JSON.stringify(body.results)));
        }
      });
    }
    
    getMyBody(url2, function test8(err, body) {
        body1 = body[0];
        console.log(body1);
        var sendMessage = ("I've find this results: "+ body1.text + "And you can see the url: "+ body1.url)// you said body1.text and body1.url
        response.output.text[0] = sendMessage;
        return res.json(response);  
      });   
    
    }
    

    Note: According to the project conversation-simple, you need to use the response parameter for sending the message for the user, then, you need to set the parameter in your function that calls for Discovery, and to add the following code above in your function.

    • See the Official video by IBM Watson talking about this project and showing one good example to call the Discovery service and sends the result for the user.