Skip to content

Commit 9ac00a3

Browse files
author
Gintautas Miselis
committed
Convert code to Typescript
1 parent d5506b9 commit 9ac00a3

18 files changed

+945
-890
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lib/middleware/*.js
2+
lib/middleware/*.d.ts

.eslintrc.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ env:
22
es6: true
33
node: true
44
mocha: true
5-
extends: 'eslint:recommended'
5+
extends: 'plugin:@typescript-eslint/recommended'
6+
parser: '@typescript-eslint/parser'
67
parserOptions:
7-
ecmaVersion: 2016
8+
project: './tsconfig.json'
9+
plugins:
10+
- '@typescript-eslint'
811
rules:
912
indent:
1013
- error
@@ -19,4 +22,9 @@ rules:
1922
- error
2023
- always
2124
no-console:
22-
- warn
25+
- off
26+
'@typescript-eslint/indent':
27+
- error
28+
- 2
29+
' @typescript-eslint/no-explicit-any':
30+
- warning

README.md

Lines changed: 59 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,30 @@ Otherwise, follow [Botkit's instructions](https://botkit.ai/docs/provisioning/sl
5656
This section walks you through code snippets to set up your Slack bot. If you want, you can jump straight to the [full example](/examples/simple-bot).
5757

5858
In your app, add the following lines to create your Slack controller using Botkit:
59-
```js
60-
const slackController = Botkit.slackbot({ clientSigningSecret: YOUR_SLACK_SIGNING_SECRET });
61-
```
59+
```typescript
60+
import { WatsonMiddleware } from 'botkit-middleware-watson';
61+
import Botkit = require('botkit');
62+
const { SlackAdapter } = require('botbuilder-adapter-slack');
63+
64+
const adapter = new SlackAdapter({
65+
clientSigningSecret: process.env.SLACK_SECRET,
66+
botToken: process.env.SLACK_TOKEN
67+
});
6268

63-
Spawn a Slack bot using the controller:
64-
```js
65-
const slackBot = slackController.spawn({
66-
token: YOUR_SLACK_TOKEN
69+
const controller = new Botkit({
70+
adapter,
71+
// ...other options
6772
});
6873
```
6974

75+
76+
7077
Create the middleware object which you'll use to connect to the Watson Assistant service.
7178

7279
If your credentials are `username` and `password` use:
7380

74-
```js
75-
const watsonMiddleware = require('botkit-middleware-watson')({
81+
```typescript
82+
const watsonMiddleware = new WatsonMiddleware({
7683
username: YOUR_ASSISTANT_USERNAME,
7784
password: YOUR_ASSISTANT_PASSWORD,
7885
url: YOUR_ASSISTANT_URL,
@@ -84,8 +91,8 @@ const watsonMiddleware = require('botkit-middleware-watson')({
8491

8592
If your credentials is `apikey` use:
8693

87-
```js
88-
const watsonMiddleware = require('botkit-middleware-watson')({
94+
```typescript
95+
const watsonMiddleware = new WatsonMiddleware({
8996
iam_apikey: YOUR_API_KEY,
9097
url: YOUR_ASSISTANT_URL,
9198
workspace_id: YOUR_WORKSPACE_ID,
@@ -95,18 +102,17 @@ const watsonMiddleware = require('botkit-middleware-watson')({
95102
```
96103

97104
Tell your Slackbot to use the _watsonMiddleware_ for incoming messages:
98-
```js
99-
slackController.middleware.receive.use(watsonMiddleware.receive);
100-
slackBot.startRTM();
105+
```typescript
106+
controller.middleware.receive.use(watsonMiddleware.receive.bind(watsonMiddleware));
101107
```
102108

103109
Finally, make your bot _listen_ to incoming messages and respond with Watson Assistant:
104-
```js
105-
slackController.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) {
110+
```typescript
111+
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], async function(bot, message) {
106112
if (message.watsonError) {
107-
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
113+
await bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
108114
} else {
109-
bot.reply(message, message.watsonData.output.text.join('\n'));
115+
await bot.reply(message, message.watsonData.output.text.join('\n'));
110116
}
111117
});
112118
```
@@ -125,7 +131,7 @@ If you would like to make your bot to only respond to _direct messages_ using As
125131
#### Using interpret function instead of registering middleware
126132

127133
```js
128-
slackController.hears(['.*'], ['direct_message'], function(bot, message) {
134+
slackController.hears(['.*'], ['direct_message'], async function(bot, message) {
129135
middleware.interpret(bot, message, function() {
130136
if (message.watsonError) {
131137
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
@@ -158,16 +164,16 @@ To use the setup parameter `minimum_confidence`, you have multiple options:
158164

159165
For example:
160166
```js
161-
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention', 'message_received'], function(bot, message) {
167+
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention', 'message_received'], async function(bot, message) {
162168
if (message.watsonError) {
163-
bot.reply(message, "Sorry, there are technical problems."); // deal with watson error
169+
await bot.reply(message, "Sorry, there are technical problems."); // deal with watson error
164170
} else {
165171
if (message.watsonData.intents.length == 0) {
166-
bot.reply(message, "Sorry, I could not understand the message."); // was any intent recognized?
172+
await bot.reply(message, "Sorry, I could not understand the message."); // was any intent recognized?
167173
} else if (message.watsonData.intents[0].confidence < watsonMiddleware.minimum_confidence) {
168-
bot.reply(message, "Sorry, I am not sure what you have said."); // is the confidence high enough?
174+
await bot.reply(message, "Sorry, I am not sure what you have said."); // is the confidence high enough?
169175
} else {
170-
bot.reply(message, message.watsonData.output.text.join('\n')); // reply with Watson response
176+
await bot.reply(message, message.watsonData.output.text.join('\n')); // reply with Watson response
171177
}
172178
}
173179
});
@@ -195,8 +201,8 @@ A common scenario of processing actions is:
195201
### using sendToWatson to update context (possible since v1.5.0)
196202

197203
Using sendToWatson to update context simplifies the bot code compared to solution using updateContext below.
198-
```js
199204

205+
```typescript
200206
function checkBalance(context, callback) {
201207
//do something real here
202208
const contextDelta = {
@@ -208,127 +214,33 @@ function checkBalance(context, callback) {
208214

209215
const checkBalanceAsync = Promise.promisify(checkBalance);
210216

211-
const processWatsonResponse = function (bot, message) {
212-
if (message.watsonError) {
213-
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
214-
}
215-
if (typeof message.watsonData.output !== 'undefined') {
216-
//send "Please wait" to users
217-
bot.reply(message, message.watsonData.output.text.join('\n'));
218-
219-
if (message.watsonData.output.action === 'check_balance') {
220-
const newMessage = clone(message);
221-
newMessage.text = 'balance result';
222-
223-
checkBalanceAsync(message.watsonData.context).then(function (contextDelta) {
224-
return watsonMiddleware.sendToWatsonAsync(bot, newMessage, contextDelta);
225-
}).catch(function (error) {
226-
newMessage.watsonError = error;
227-
}).then(function () {
228-
return processWatsonResponse(bot, newMessage);
229-
});
230-
}
231-
}
232-
};
233-
234-
controller.on('message_received', processWatsonResponse);
235-
```
236-
237-
#### Using updateContext in controller (available since v1.4.0)
238-
239-
Since 1.4.0 it is possible to update context from controller code.
240-
```js
241-
242-
function checkBalance(context, callback) {
243-
//this version of function updates only the context object
244-
context.validAccount = true;
245-
context.accountBalance = 95.33;
246-
callback(null, context);
247-
}
248-
249-
const checkBalanceAsync = Promise.promisify(checkBalance);
250-
251-
const processWatsonResponse = function (bot, message) {
217+
const processWatsonResponse = async (bot, message) => {
252218
if (message.watsonError) {
253-
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
219+
return await bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
254220
}
255221
if (typeof message.watsonData.output !== 'undefined') {
256222
//send "Please wait" to users
257-
bot.reply(message, message.watsonData.output.text.join('\n'));
223+
await bot.reply(message, message.watsonData.output.text.join('\n'));
258224

259225
if (message.watsonData.output.action === 'check_balance') {
260226
const newMessage = clone(message);
261227
newMessage.text = 'balance result';
262228

263-
//check balance
264-
checkBalanceAsync(message.watsonData.context).then(function (context) {
265-
//update context in storage
266-
return watsonMiddleware.updateContextAsync(message.user, context);
267-
}).then(function () {
268-
//send message to watson (it reads updated context from storage)
269-
return watsonMiddleware.sendToWatsonAsync(bot, newMessage);
270-
}).catch(function (error) {
229+
try {
230+
const contextDelta = await checkBalanceAsync(message.watsonData.context);
231+
await watsonMiddleware.sendToWatsonAsync(bot, newMessage, contextDelta);
232+
}catch(error) {
271233
newMessage.watsonError = error;
272-
}).then(function () {
273-
//send results to user
274-
return processWatsonResponse(bot, newMessage);
275-
});
276-
}
277-
}
278-
};
279-
280-
controller.on('message_received', processWatsonResponse);
281-
```
282-
283-
#### Using middleware.after and controller
284-
285-
Before v1.4.0 only middleware.after callback can update context, and only controller can send replies to user.
286-
The downside is that it is impossible to send "Please wait message".
287-
288-
```js
289-
function checkBalance(watsonResponse, callback) {
290-
//middleware.after function must pass a complete Watson respose to callback
291-
watsonResponse.context.validAccount = true;
292-
watsonResponse.context.accountBalance = 95.33;
293-
callback(null, watsonResponse);
294-
}
295-
296-
watsonMiddleware.after = function(message, watsonResponse, callback) {
297-
//real action happens in middleware.after
298-
if (typeof watsonResponse !== 'undefined' && typeof watsonResponse.output !== 'undefined') {
299-
if (watsonResponse.output.action === 'check_balance') {
300-
return checkBalance(watsonResponse, callback);
301-
}
302-
}
303-
callback(null, watsonResponse);
304-
};
305-
306-
const processWatsonResponse = function(bot, message) {
307-
if (message.watsonError) {
308-
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message");
309-
}
310-
311-
if (typeof message.watsonData.output !== 'undefined') {
312-
//send "Please wait" to users
313-
bot.reply(message, message.watsonData.output.text.join('\n'));
314-
315-
if (message.watsonData.output.action === 'check_balance') {
316-
const newMessage = clone(message);
317-
newMessage.text = 'balance result';
318-
//send to watson
319-
watsonMiddleware.interpret(bot, newMessage, function() {
320-
//send results to user
321-
processWatsonResponse(bot, newMessage);
322-
});
234+
}
235+
236+
return await processWatsonResponse(bot, newMessage);
323237
}
324238
}
325239
};
326240

327241
controller.on('message_received', processWatsonResponse);
328-
329242
```
330243

331-
332244
## Implementing event handlers
333245

334246
Events are messages having type different than `message`.
@@ -376,17 +288,17 @@ The `hear()` function can be used on individual handler functions, or can be use
376288

377289
Used on an individual handler:
378290

379-
```js
380-
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], watsonMiddleware.hear, function(bot, message) {
381-
bot.reply(message, message.watsonData.output.text.join('\n'));
291+
```typescript
292+
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], watsonMiddleware.hear, async function(bot, message) {
293+
await bot.reply(message, message.watsonData.output.text.join('\n'));
382294
// now do something special related to the hello intent
383295
});
384296
```
385297

386298
Used globally:
387299

388-
```js
389-
slackController.changeEars(watsonMiddleware.hear);
300+
```typescript
301+
slackController.changeEars(watsonMiddleware.hear.bind(watsonMiddleware));
390302

391303
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) {
392304
bot.reply(message, message.watsonData.output.text.join('\n'));
@@ -419,20 +331,21 @@ middleware.before = function(message, assistantPayload, callback) {
419331
If you need to make use of multiple workspaces in a single bot, workspace_id can be changed dynamically by setting workspace_id property in context.
420332

421333
Example of setting workspace_id to id provided as a property of hello message:
422-
```js
423-
function handleHelloEvent(bot, message) {
424-
message.type = 'welcome';
425-
const contextDelta = {};
334+
```typescript
335+
async function handleHelloEvent(bot, message) {
336+
message.type = 'welcome';
337+
const contextDelta = {};
426338

427-
if (message.workspaceId) {
428-
contextDelta.workspace_id = message.workspaceId;
429-
}
339+
if (message.workspaceId) {
340+
contextDelta.workspace_id = message.workspaceId;
341+
}
430342

431-
watsonMiddleware.sendToWatsonAsync(bot, message, contextDelta).catch(function (error) {
432-
message.watsonError = error;
433-
}).then(function () {
434-
bot.reply(message, message.watsonData.output.text.join('\n'));
435-
});
343+
try {
344+
watsonMiddleware.sendToWatsonAsync(bot, message, contextDelta);
345+
} catch(error) {
346+
message.watsonError = error;
347+
}
348+
await bot.reply(message, message.watsonData.output.text.join('\n'));
436349
}
437350

438351
controller.on('hello', handleHelloEvent);

0 commit comments

Comments
 (0)