Giter Club home page Giter Club logo

Comments (18)

Naktibalda avatar Naktibalda commented on September 15, 2024

It is very unlikely that somebody will give you that, especially if you want a Spark specific example.

I could try to help if you shared your code and asked about specific issues with it.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Fair answer, although I'm literally trying to put together a sample bot using the sample code in this readme, especially the section on implementing actions using the updateContext method. So the question is, given that I want to use the code in this section, what is the minimum amount of code that's required in addition to that (that is, registration of the Watson middleware and basic triggers, etc.) for that code to work as expected? (assuming that Watson returns an action to execute, together with a 'please wait', etc.) I think that if you have an answer for Slack, it should be useful to see anyway.

This is what I tried:

  • I hooked up middleware as follows:
    controller.hears(['.*'], ['direct_message'], function(bot, message) {
		 watsonMiddleware.interpret(bot, message, function() {
			   if (message.watsonError) {
				      bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
			   } else {
				    processWatsonResponse(bot, message);
			   }
		 });
	});
- I then used the 'processWatsonResponse' method in that section

Given the above combination, the bot runs into a loop apparently responding always to the same action, which leads me to believe that the sample code in that section is actually not really a working example. I'd be glad to see one such sample that really works. Hope this makes sense.

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

Please show the code of your processWatsonResponse function.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

I took it literally from the relevant section in the readme file. In other words, just copying it below:

    var processWatsonResponse = function (bot, message) {
      if (message.watsonError) {
        return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
      }
      if (typeof message.watsonData.output !== 'undefined') {
        //send "Please wait" to users
        bot.reply(message, message.watsonData.output.text.join('\n'));

       if (message.watsonData.output.action === 'check_balance') {
          var newMessage = clone(message);
          newMessage.text = 'balance result';
          //check balance
         checkBalanceAsync(message.watsonData.context).then(function (context) {
            //update context in storage
            return watsonMiddleware.updateContextAsync(message.user, context);
         }).then(function () {
          //send message to watson (it reads updated context from storage)
           return watsonMiddleware.sendToWatsonAsync(bot, newMessage);
         }).catch(function (error) {
        newMessage.watsonError = error;
      }).then(function () {
        //send results to user
        return processWatsonResponse(bot, newMessage);
      });
     }
    }
   };

Note that I've also used literally the checkBalance function also defined in the same section in the readme.

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

Are you using the latest version of middleware?
I used this exact code in my bot and it worked correctly. The only difference was in fields set by checkBalance function. And I used middleware as a middleware, not with hears.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Ah, interesting. Since you're not using 'hears', could you share your middleware registration? And, are you also using the following statement:
controller.on('message_received', processWatsonResponse);
or is it not necessary?
I suspect that the combination of all these things is what could be causing trouble for me

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

I can't look at my bot code until Monday, but I am pretty sure that it uses controller.on('message_received', processWatsonResponse);

There is nothing special in middleware registration too.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

That is odd. In looking at my code and the logs again, I see the following problems:
1- the context is apparently not getting updated (I am using only temporary storage, not sure whether this is why) with the call to watson.updateContextAsync
2- Also, 'newMessage' appears to still have the field 'watsonData.output.action' set to the 'check_balance' action, which causes the loop :-)

If I manually update the context within newMessage before sending it Watson -inside of processWatsonResponse-, and also clear the 'action' field above, then the process does not loop. However, I've seen it misbehave at times in that the order of the responses might not be the correct one (that is, sometimes I seem to get the 'Please wait' message after the presentation of results (of the action) to the user. :-(.

Thanks for all your help with this!

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

Actually I have delete (newMessage.watsonData); right after var newMessage = clone(message);

I thought that it is unimportant, because watsonData should be overwritten by the next response.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Unless I leave the 'hears' statement in place, Watson is not called at all in my case, which is why I had to leave it in :-(. So there must be something else distinguishing your bot from the sample, I believe. Could you include here your middleware registration steps? (even if there's nothing special to them)

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

To have a persistent storage you have to pass json_file_store option to controller constructor or use a storage module:

var bot_options = {
  json_file_store: __dirname + '/../.data/db/'
};

var controller = Botkit.sparkbot(bot_options);

Middleware registration code:

controller.middleware.receive.use(watsonMiddleware.receive);

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Thanks for providing that. Even with those statements, my code does not appear to call Watson middleware at all unless I include the hears statement.
Here's the complete code I have right now for dealing with Watson (in theory should be pretty much equivalent to what you've described you had - note that I've replaced 'checkBalance' with 'createTicket' but this should not be an issue.).

    var watsonMiddleware = require("botkit-middleware-watson")({
		  username: process.env.watson_username,
		  password: process.env.watson_pass,
		  workspace_id: process.env.watson_id1,
		  version_date: '2017-05-26',
		  minimum_confidence: 0.50, // (Optional) Default is 0.75
	});

     controller.middleware.receive.use(watsonMiddleware.receive);

      var Promise = require("bluebird");
      var clone = require("clone");
	
     function createTicket(context, callback) {
		context.ticketNum = 123;
		context.ticketSuccess = true;
		for (var i = 0; i < 1000000; i++) {
		}
		callback(null, context);
	}
	Promise.promisifyAll(watsonMiddleware);
	var createTicketAsync = Promise.promisify(createTicket);
	
	var processWatsonResponse = function (bot, message) {
		if (typeof message !== 'undefined') {
		  if (typeof message !== 'undefined' && message.watsonError ) {
		    return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
		  }
		  if (typeof message !== 'undefined' && typeof message.watsonData !== 'undefined' &&
				  typeof message.watsonData.output !== 'undefined') {
		    //send "Please wait" to users
		    bot.reply(message, message.watsonData.output.text.join('\n'));

		    if (message.watsonData.output.action  && message.watsonData.output.action === 'create_ticket') {
		      var newMessage = clone(message);
		      newMessage.text = 'Ticket Creation Results';
		     // newMessage.watsonData.action = null; // NOTE: I had to add this to prevent infinite looping
		      createTicketAsync(message.watsonData.context).then(function (context) {
		        //update context in storage
		        return watsonMiddleware.updateContextAsync(message.user, context);
		      }).then(function () {
		        //send message to watson (it reads updated context from storage)
		        return watsonMiddleware.sendToWatsonAsync(bot, newMessage);
		      }).catch(function (error) {
		        newMessage.watsonError = error;
		      }).then(function () {
		        //send results to user
		        return processWatsonResponse(bot, newMessage);
		      });
		    } else {
		    	console.log("Apparently no Watson action is present here...");
		    }
		  }
		  };
	};

     controller.on('message_received', processWatsonResponse);

As I mentioned, this code does not call Watson Middleware at all; the bot responds with the built-in sample responses (I've commented out most of the sample skills file, but still a few things remain in there, like the basic hello greeting, etc.).

from botkit-middleware.

germanattanasio avatar germanattanasio commented on September 15, 2024

Hey @pgoldweic where you able to fix this issue?

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Thanks for asking. I got the code above working only when I do the following 3 things:
1- comment out the "controller.on('message_received', ...)" statement
2- use 'hears' as in the following:

controller.hears(['.*'], ['direct_message'], function(bot, message) {
	 watsonMiddleware.interpret(bot, message, function() {
		   if (message.watsonError) {
			      bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
		   } else {
			   processWatsonResponse (bot, message);
		   }
	 });
});

3- comment out the middleware registration line

In summary: I cannot get the example code working 'literally'. I think it's pretty unclear from the documentation how to combine the example code (for processing actions) with the middleware registration requirements.

Aside from this, I am now running into the problem that there are two messages presented to the user almost simultaneously (the 'please wait...' message that gets sent first within 'processWatsonResponse', and the next message for the user (that presumable explains to the user the results of having executed the action (in my example this action is 'createTicket', while the docs had a 'checkBalance')). The documentation does not cover this at all (that is, how to prevent these messages from being presented to the user simultaneously? Do we need to use 'startConversation'? Would be great if the example code for handling actions accounted for this problem and offered a solution.

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

It looks like you need a hands-on assistance, it should be something trivial, but you haven't shared your code yet, so we have no idea what went wrong.

I've read through CiscoSparkbot.js

  1. It calls receiveMessage.
  2. receiveMessage runs receive middleware and emits message_receive event after getting a result from middleware.
  3. CiscoSparkbot handles message_received event and emits direct_message event.

Everything looks correct, please provide your code.

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Thanks for providing that list of steps @Naktibalda; that's quite helpful. At least now I understand that any 'hears' statement (that filters on 'direct_message' events) will execute after the 'controller.on('message_received', processWatsonResponse);'

BTW, I did provide my code above (a big chunk of code, almost literally the sample code for implementing app actions using Watson middleware). In any case, I got the basic behavior working by using the 3 things I mentioned above, that is:
1- no middleware registration for Watson
2- a 'hears' statement that filters events and only calls middleware on 'direct_message'
3- no 'on message_received' event handler

For the record, here is the code once again:

var watsonMiddleware = require("botkit-middleware-watson")({
	  username: process.env.watson_username,
	  password: process.env.watson_pass,
	  workspace_id: process.env.watson_id1,
	  version_date: '2017-05-26',
	  minimum_confidence: 0.50, // (Optional) Default is 0.75
});

 controller.hears(['.*'], ['direct_message'], function(bot, message) {
 watsonMiddleware.interpret(bot, message, function() {
	   if (message.watsonError) {
		      bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
	   } else {
		   processWatsonResponse (bot, message);
	   }
 });

});

  var Promise = require("bluebird");
  var clone = require("clone");

 function createTicket(context, callback) {
	context.ticketNum = 123;
	context.ticketSuccess = true;
	for (var i = 0; i < 1000000; i++) { // faking something happens
	}
	callback(null, context);
}
Promise.promisifyAll(watsonMiddleware);
var createTicketAsync = Promise.promisify(createTicket);

var processWatsonResponse = function (bot, message) {
	if (typeof message !== 'undefined') {
	  if (typeof message !== 'undefined' && message.watsonError ) {
	    return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
	  }
	  if (typeof message !== 'undefined' && typeof message.watsonData !== 'undefined' &&
			  typeof message.watsonData.output !== 'undefined') {
	    //send "Please wait" to users
	    bot.reply(message, message.watsonData.output.text.join('\n'));

	    if (message.watsonData.output.action  && message.watsonData.output.action === 'create_ticket') {
	      var newMessage = clone(message);
	      newMessage.text = 'Ticket Creation Results';
	      newMessage.watsonData.action = null; // this was needed to prevent infinite loop
	      createTicketAsync(message.watsonData.context).then(function (context) {
	        //update context in storage
	        return watsonMiddleware.updateContextAsync(message.user, context);
	      }).then(function () {
	        //send message to watson (it reads updated context from storage)
	        return watsonMiddleware.sendToWatsonAsync(bot, newMessage);
	      }).catch(function (error) {
	        newMessage.watsonError = error;
	      }).then(function () {
	        //send results to user
	        return processWatsonResponse(bot, newMessage);
	      });
	    } else {
	    	console.log("Apparently no Watson action is present here...");
	    }
	  }
	  };
};

My current issue then is that I am getting the two replies to the user essentially simultaneously (the first being the 'please wait...', the second reply being the response given to the user after this 'createTicket' action is taken. I am wondering whether I need to do something explicit to prevent that (e.g. use 'startConversation' or something like it? I have no experience with conversations in Botkit yet), or whether this is happening simply due to the shape of my 'createTicket' function (which is imitating the 'checkBalance' of the example).

from botkit-middleware.

Naktibalda avatar Naktibalda commented on September 15, 2024

Instead of heating CPU with for (var i = 0; i < 1000000; i++) { }
you could use setTimeout(function() { callback(null, context); }, 5000);

from botkit-middleware.

pgoldweic avatar pgoldweic commented on September 15, 2024

Thanks, that actually worked! So in fact it was the silly function causing the problem after all :-). Glad that it's not necessary to use 'startConversation' to get this to work.
Thanks again for your help @Naktibalda

from botkit-middleware.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.