Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom recognizer sample for nodejs #1755

Merged
merged 6 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
}