New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

botkit-middleware-watson

Package Overview
Dependencies
Maintainers
4
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

botkit-middleware-watson - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

11

CHANGELOG.md

@@ -0,1 +1,10 @@

## v1.4.0
The following changes were introduced with the v1.4.0 release:
* Added `updateContext` function to middleware.
* `interpret` is just an alias of `receive`.
* `sendToWatson` is a new alias of `receive`.
* Fixed error handling in `utils.updateContext`.
* If any error happens in `receive`, it is assigned to `message.watsonError`
## v1.3.1

@@ -47,2 +56,2 @@

* Added hears function to middleware
* Added `hears` function to middleware

63

lib/middleware/index.js

@@ -62,50 +62,2 @@ /**

interpret: function(bot, message, callback) {
var before = Promise.promisify(middleware.before);
var after = Promise.promisify(middleware.after);
if (!middleware.conversation) {
debug('Creating Conversation object with parameters: ' + JSON.stringify(config, 2, null));
middleware.conversation = new ConversationV1(config);
}
if (!message.text || ignoreType.indexOf(message.type) !== -1 || message.reply_to || message.bot_id) {
// Ignore messages initiated by Slack. Reply with dummy output object
message.watsonData = {
output: {
text: []
}
};
callback();
}
middleware.storage = bot.botkit.storage;
readContext(message.user, middleware.storage).then(function(userContext) {
var payload = {
workspace_id: config.workspace_id,
input: {
text: message.text
}
};
if (userContext) {
payload.context = userContext;
}
return payload;
}).then(function(payload) {
return before(message, payload);
}).then(function(watsonRequest) {
return postMessage(middleware.conversation, watsonRequest);
}).then(function(watsonResponse) {
return after(message, watsonResponse);
}).then(function(watsonResponse) {
message.watsonData = watsonResponse;
return updateContext(message.user, middleware.storage, watsonResponse);
}).catch(function(error) {
debug('Error: %s', JSON.stringify(error, null, 2));
}).done(function(response) {
callback(null);
});
},
receive: function(bot, message, next) {

@@ -127,3 +79,3 @@ var before = Promise.promisify(middleware.before);

};
next();
return next();
}

@@ -154,2 +106,3 @@

}).catch(function(error) {
message.watsonError = error;
debug('Error: %s', JSON.stringify(error, Object.getOwnPropertyNames(error), 2));

@@ -162,4 +115,16 @@ }).done(function(response) {

middleware.interpret = middleware.receive;
middleware.sendToWatson = middleware.receive;
middleware.updateContext = function(user, context, callback) {
watsonUtils.updateContext(
user,
middleware.storage,
{ context: context },
callback
);
};
debug('Middleware: ' + JSON.stringify(middleware, null, 2));
return middleware;
};

@@ -20,2 +20,7 @@ /**

storage.users.get(userId, function(err, user_data) {
if (err) {
//error is returned if nothing is stored yet, so it is the best to ignore it
debug('User: %s, read context error: %s', userId, err);
}
if (user_data && user_data.context) {

@@ -32,4 +37,4 @@ debug('User: %s, Context: %s', userId, JSON.stringify(user_data.context, null, 2));

var updateContext = function(userId, storage, watsonResponse, callback) {
readContext(userId, storage, function(error, user_data) {
if (error) return callback(error);
readContext(userId, storage, function(err, user_data) {
if (err) return callback(err);

@@ -44,5 +49,6 @@ if (!user_data) {

if (err) return callback(err);
debug('User: %s, Updated Context: %s', userId, JSON.stringify(watsonResponse.context, null, 2));
callback(null, watsonResponse);
});
debug('User: %s, Updated Context: %s', userId, JSON.stringify(watsonResponse.context, null, 2));
callback(null, watsonResponse);
});

@@ -54,8 +60,6 @@ };

conversation.message(payload, function(err, response) {
if (err) {
callback(err);
} else {
debug('Conversation Response: %s', JSON.stringify(response, null, 2));
callback(null, response);
}
if (err) return callback(err);
debug('Conversation Response: %s', JSON.stringify(response, null, 2));
callback(null, response);
});

@@ -62,0 +66,0 @@ };

{
"name": "botkit-middleware-watson",
"version": "1.3.1",
"version": "1.4.0",
"description": "A middleware for using Watson Conversation in a Botkit-powered bot.",

@@ -26,10 +26,11 @@ "main": "lib/middleware/index.js",

"botkit": "^0.2.2",
"nock": "^8.1.0",
"mocha": "^3.1.0"
"mocha": "^3.4.2",
"nock": "^8.2.1",
"sinon": "^2.3.5"
},
"dependencies": {
"bluebird": "^3.4.6",
"debug": "^2.2.0",
"watson-developer-cloud": "^2.4.1"
"bluebird": "^3.5.0",
"debug": "^2.6.8",
"watson-developer-cloud": "^2.32.1"
}
}

@@ -11,5 +11,13 @@ # Use IBM Watson's Conversation service to chat with your Botkit-powered Bot! [![Build Status](https://travis-ci.org/watson-developer-cloud/botkit-middleware.svg?branch=master)](https://travis-ci.org/watson-developer-cloud/botkit-middleware)

* Exposes the following functions to developers:
* `before`: pre-process requests before sending to Watson Conversation (Conversation).
* `after` : post-process responses before forwarding them to Botkit.
## Function Overview
* `receive`: used as [middleware in Botkit](#bot-setup).
* `interpret`: an alias of `receive`, used in [message-filtering](#message-filtering) and [implementing app actions](#implementing-app-actions).
* `sendToWatson`: another alias of `receive`, use the one that looks the best in context.
* `hear`: used for [intent matching](#intent-matching).
* `updateContext`: used in [implementing app actions](#implementing-app-actions).
* `before`: [pre-process](#before-and-after) requests before sending to Watson Conversation (Conversation).
* `after`: [post-process](#before-and-after) responses before forwarding them to Botkit.
## Installation

@@ -33,3 +41,3 @@ ```sh

Otherwise, follow [Botkit's instructions](https://github.com/howdyai/botkit/blob/master/readme-slack.md) to create your Slack bot from scratch. When your bot is ready, you are provided with a Slack token.
Otherwise, follow [Botkit's instructions](https://github.com/howdyai/botkit/blob/master/docs/readme-slack.md) to create your Slack bot from scratch. When your bot is ready, you are provided with a Slack token.

@@ -58,3 +66,3 @@ ### Bot setup

workspace_id: YOUR_WORKSPACE_ID,
version_date: '2016-09-20',
version_date: '2017-05-26',
minimum_confidence: 0.50, // (Optional) Default is 0.75

@@ -73,55 +81,150 @@ });

slackController.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) {
if (message.watsonError) {
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
} else {
bot.reply(message, message.watsonData.output.text.join('\n'));
}
});
```
The middleware attaches the `watsonData` object to _message_. This contains the text response from Conversation.
If any error happened in middleware, error is assigned to `watsonError` property of the _message_.
Then you're all set!
### Middleware Functions
The _watsonMiddleware_ object provides some useful functions which can be used for customizing the question-answering pipeline.
## Features
They come in handy to:
- Respond to incoming messages
- Make database updates
- Update the context in the payload
- Call some external service before/after calling Conversation
- Filter out irrelevant intents by overwriting Botkit's hears function
### Message filtering
When middleware is registered, the receive function is triggered on _every_ message.
If you would like to make your bot to only respond to _direct messages_ using Conversation, you can achieve this in 2 ways:
#### `receive`
The _receive_ function is the one which gets triggered on incoming bot messages. One needs to bind it to the Botkit's receive middleware in order for it to work.
#### Using interpret function instead of registering middleware
```js
slackController.hears(['.*'], ['direct_message'], function(bot, message) {
middleware.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 {
bot.reply(message, message.watsonData.output.text.join('\n'));
}
});
});
```
#### Using middleware wrapper
```js
// Connect to Watson middleware
slackController.middleware.receive.use(middleware.receive);
var receiveMiddleware = function (bot, message, next) {
if (message.type === 'direct_message') {
watsonMiddleware.receive(bot, message, next);
} else {
next();
}
};
slackController.middleware.receive.use(receiveMiddleware);
```
Then simply respond to messages as follows:
### Implementing app actions
Conversation side of app action is documented in [Developer Cloud](https://www.ibm.com/watson/developercloud/doc/conversation/develop-app.html#implementing-app-actions)
A common scenario of processing actions is
* Send message to user "Please wait while I ..."
* Perform action
* Persist results in conversation context
* Send message to Watson with updated context
* Send result message(s) to user.
#### Using middleware.after and controller
Before v1.4.0 only middleware.after callback can update context, and only controller can send replies to user.
The downside is that it is impossible to send "Please wait message".
```js
slackController.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) {
bot.reply(message, message.watsonData.output.text.join('\n'));
});
function checkBalance(watsonResponse, callback) {
//middleware.after function must pass a complete Watson respose to callback
watsonResponse.context.validAccount = true;
watsonResponse.context.accountBalance = 95.33;
callback(null, watsonResponse);
}
watsonMiddleware.after = function(message, watsonResponse, callback) {
//real action happens in middleware.after
if (typeof watsonResponse !== 'undefined' && typeof watsonResponse.output !== 'undefined') {
if (watsonResponse.output.action === 'check_balance') {
return checkBalance(watsonResponse, callback);
}
}
callback(null, watsonResponse);
};
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';
//send to watson
watsonMiddleware.interpret(bot, newMessage, function() {
//send results to user
processWatsonResponse(bot, newMessage);
});
}
}
};
controller.on('message_received', processWatsonResponse);
```
#### Using updateContext in controller (available since v1.4.0)
Since 1.4.0 it is possible to update context from controller code.
```js
Note: The receive function is triggered on _every_ message. Please consult the [Botkit's guide](https://github.com/howdyai/botkit#receive-middleware) to the receive middleware to know more about it.
function checkBalance(context, callback) {
//this version of function updates only the context object
context.validAccount = true;
context.accountBalance = 95.33;
callback(null, watsonResponse);
}
#### `interpret`
Promise.promisifyAll(watsonMiddleware);
var checkBalanceAsync = Promise.promisify(checkBalance);
The `interpret()` function works very similarly to the receive function but unlike the receive function,
- it is not mapped to a Botkit function so doesn't need to be added as a middleware to Botkit
- doesn't get triggered on all events
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'));
The _interpret_ function only gets triggered when an event is _heard_ by the controller. For example, one might want your bot to only respond to _direct messages_ using Conversation. In such scenarios, one would use the interpret function as follows:
if (message.watsonData.output.action === 'check_balance') {
var newMessage = clone(message);
newMessage.text = 'balance result';
```js
slackController.hears(['.*'], ['direct_message'], function(bot, message) {
middleware.interpret(bot, message, function(err) {
if (!err)
bot.reply(message, message.watsonData.output.text.join('\n'));
});
});
//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);
});
}
}
};
controller.on('message_received', processWatsonResponse);
```
#### `hear`
### Intent matching
The Watson middleware also includes a `hear()` function which provides a mechanism to

@@ -165,3 +268,3 @@ developers to fire handler functions based on the most likely intent of the user.

```js
middleware.before = function(message, conversationPayload, callback) {
middleware.before = function(message, conversationPayload, callback) {
// Code here gets executed before making the call to Conversation.

@@ -168,0 +271,0 @@ callback(null, customizedPayload);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc