Skip to content

Commit

Permalink
custom recognizer sample for nodejs (#1755)
Browse files Browse the repository at this point in the history
* Adding sample files

* Update readme

* Remove constructor, no longer needed

* Adding null check for intents array before running switch statement

* Remove unnecessary if

* Only mention email address if user had input a valid email address
  • Loading branch information
JSpru authored and Eric Dahlvang committed Oct 28, 2019
1 parent ad51e1c commit 02bce12
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 0 deletions.
14 changes: 14 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
"extends": "standard",
"rules": {
"semi": [2, "always"],
"indent": [2, 4],
"no-return-await": 0,
"space-before-function-paren": [2, {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"template-curly-spacing": [2, "always"]
}
};
3 changes: 3 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
lib
.env
61 changes: 61 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# custom-recognizer-example

This sample bot demonstrates how to implement a custom recognizer. The recognizer code (customRecognizer.js) uses a regex expression to detect an email address in the user input and suggests possible intents if present. Then the bot uses the top intent returned from the recognizer to respond accordingly.

This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back.

## Prerequisites

- [Node.js](https://nodejs.org) version 10.14.1 or higher

```bash
# determine node version
node --version
```

## To run the bot

- Install modules

```bash
npm install
```

- Start the bot

```bash
npm start
```

## Testing the bot using Bot Framework Emulator

[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.

- Install the Bot Framework Emulator version 4.3.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)

### Connect to the bot using Bot Framework Emulator

- Launch Bot Framework Emulator
- File -> Open Bot
- Enter a Bot URL of `http://localhost:3978/api/messages`

## Deploy the bot to Azure

To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions.


## Further reading

- [Bot Framework Documentation](https://docs.botframework.com)
- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
- [Dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0)
- [Gathering Input Using Prompts](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-prompts?view=azure-bot-service-4.0)
- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0)
- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest)
- [Azure Portal](https://portal.azure.com)
- [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/)
- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0)
- [Restify](https://www.npmjs.com/package/restify)
- [dotenv](https://www.npmjs.com/package/dotenv)
53 changes: 53 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/bot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { ActivityHandler } = require('botbuilder');
const CustomRecognizer = require('./customRecognizer');

class MyBot extends ActivityHandler {
constructor() {
super();
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
this.onMessage(async (context, next) => {

// pass the response through custom recognizer to detect email addresses
const recognizer = new CustomRecognizer();
const recognizerResult = recognizer.recognize(context.activity.text);
const intent = recognizerResult.intents.length > 0 ? recognizer.getTopIntent(recognizerResult) : '';

// respond according to the top intent provided by the recognizer
if (intent) {
switch(intent) {
case 'SendEmail':
await context.sendActivity('Your response includes an email address. Would you like to contact us by email?');
break;
case 'SearchForEmailAddress':
await context.sendActivity('Your response includes an email address. Would you like to search for an email address?');
break;
case 'OpenEmailAccount':
await context.sendActivity('Your response includes an email address. Would you like to open an email account?');
break;
default:
await context.sendActivity('Your response includes an email address.');
}
}
await context.sendActivity(`You said '${ context.activity.text }'`);

// By calling next() you ensure that the next BotHandler is run.
await next();
});

this.onMembersAdded(async (context, next) => {
const membersAdded = context.activity.membersAdded;
for (let cnt = 0; cnt < membersAdded.length; ++cnt) {
if (membersAdded[cnt].id !== context.activity.recipient.id) {
await context.sendActivity('Hello and welcome!');
}
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
}

module.exports.MyBot = MyBot;
42 changes: 42 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/customRecognizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class CustomRecognizer {

recognize(text) {
const recognizerResult = {
text: text,
intents: []
};
const regex = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
const isEmailAddress = regex.test(text);
if (isEmailAddress) {
recognizerResult.intents.push({
SearchForEmailAddress: {
score: 60
}
});
recognizerResult.intents.push({
SendEmail: {
score: 90
}
});
recognizerResult.intents.push({
OpenEmailAccount: {
score: 30
}
});
}
return recognizerResult;
}

getTopIntent(recognizerResult) {
const sortedResults = recognizerResult.intents.sort((a, b) => {
const keyA = Object.keys(a);
const keyB = Object.keys(b);
return (a[keyA].score > b[keyB].score) ? -1 : 1;
});
const topIntent = Object.keys(sortedResults[0])[0];
return topIntent;
}

}

module.exports = CustomRecognizer;
51 changes: 51 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const dotenv = require('dotenv');
const path = require('path');
const restify = require('restify');

// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter } = require('botbuilder');

// This bot's main dialog.
const { MyBot } = require('./bot');

// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });

// Create HTTP server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo test your bot, see: https://aka.ms/debug-with-emulator`);
});

// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});

// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${ error }`);
// Send a message to the user
await context.sendActivity(`Oops. Something went wrong!`);
};

// Create the main dialog.
const myBot = new MyBot();

// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.run(context);
});
});
32 changes: 32 additions & 0 deletions MigrationV3V4/Node/custom-recognizer-example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "custom-recognizer-example",
"version": "1.0.0",
"description": "Demonstrate the core capabilities of the Microsoft Bot Framework",
"author": "Generated using Microsoft Bot Builder Yeoman generator v4.5.0",
"license": "MIT",
"main": "index.js",
"scripts": {
"start": "node ./index.js",
"watch": "nodemon ./index.js",
"lint": "eslint .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com"
},
"dependencies": {
"botbuilder": "~4.5.1",
"dotenv": "~8.0.0",
"restify": "~8.3.3"
},
"devDependencies": {
"eslint": "^6.0.1",
"eslint-config-standard": "^13.0.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"nodemon": "~1.19.1"
}
}

0 comments on commit 02bce12

Please sign in to comment.