Skip to content

Commit

Permalink
[Node-SimilarProducts] Update to botbuilder 3.5.1
Browse files Browse the repository at this point in the history
  • Loading branch information
pcostantini committed Jan 10, 2017
1 parent e27a151 commit 57927e4
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 61 deletions.
28 changes: 15 additions & 13 deletions Node/intelligence-SimilarProducts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ A sample bot that illustrates how to use the [Bing Image Search API](https://www

The minimum prerequisites to run this sample are:
* Latest Node.js with NPM. Download it from [here](https://nodejs.org/en/download/).
* The Bot Framework Emulator. To install the Bot Framework Emulator, download it from [here](https://aka.ms/bf-bc-emulator). Please refer to [this documentation article](https://docs.botframework.com/en-us/csharp/builder/sdkreference/gettingstarted.html#emulator) to know more about the Bot Framework Emulator.
* The Bot Framework Emulator. To install the Bot Framework Emulator, download it from [here](https://emulator.botframework.com/). Please refer to [this documentation article](https://github.com/microsoft/botframework-emulator/wiki/Getting-Started) to know more about the Bot Framework Emulator.
* **[Recommended]** Visual Studio Code for IntelliSense and debugging, download it from [here](https://code.visualstudio.com/) for free.
* This sample currently uses a free trial Microsoft Bing Search API key with limited QPS. Please subscribe [here](https://www.microsoft.com/cognitive-services/en-us/subscriptions) to obtain your own key and update the `BING_SEARCH_API_KEY` key in [.env](.env) file to try it out further.

Expand All @@ -22,23 +22,25 @@ The main components are:
* [image-service.js](image-service.js): is the core component illustrating how to call the Bing Image Search RESTful API.
* [app.js](app.js): is the bot service listener receiving messages from the connector service and passing them down to image-service.js and constructing the response.

In this sample we are using the API to get the similar products and send it back to the user. Check out the use of the `imageService.getSimilarProductsFromStream(stream)` method in [app.js](app.js).
In this sample we are using the API to get the similar products and send it back to the user. Check out the use of the `imageService.getSimilarProductsFromStream(stream)` method in [app.js](app.js#L66).

````JavaScript
if (hasImageAttachment(session)) {
var stream = getImageStreamFromAttachment(session.message.attachments[0]);
imageService
.getSimilarProductsFromStream(stream)
.then(visuallySimilarProducts => handleApiResponse(session, visuallySimilarProducts))
.catch(error => handleErrorResponse(session, error));
}
var stream = getImageStreamFromAttachment(session.message.attachments[0]);
imageService
.getSimilarProductsFromStream(stream)
.then(visuallySimilarProducts => handleApiResponse(session, visuallySimilarProducts))
.catch(error => handleErrorResponse(session, error));
}
````
and here is the implementation of `imageService.getSimilarProductsFromStream(stream)` in [image-service.js](image-service.js)

And here is the implementation of `imageService.getSimilarProductsFromStream(stream)` in [image-service.js](image-service.js)

````JavaScript
/**
* Gets the similar products of the image from an image stream
* @param {stream} stream The stream to an image.
* @return (Promise) Promise with visuallySimilarProducts array if succeeded, error otherwise
* @return {Promise} Promise with visuallySimilarProducts array if succeeded, error otherwise
*/
exports.getSimilarProductsFromStream = stream => {
return new Promise(
Expand All @@ -50,15 +52,15 @@ exports.getSimilarProductsFromStream = stream => {
file: stream
},
headers: {
"Ocp-Apim-Subscription-Key": BING_SEARCH_API_KEY
'Ocp-Apim-Subscription-Key': BING_SEARCH_API_KEY
}
};

request.post(requestData, (error, response, body) => {
if (error) {
reject(error);
}
else if (response.statusCode != 200) {
else if (response.statusCode !== 200) {
reject(body);
}
else {
Expand All @@ -67,7 +69,7 @@ exports.getSimilarProductsFromStream = stream => {
});
}
);
}
};
````

### Outcome
Expand Down
68 changes: 34 additions & 34 deletions Node/intelligence-SimilarProducts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@ A Similar Products bot for the Microsoft Bot Framework.
require('dotenv-extended').load();

const builder = require('botbuilder'),
fs = require("fs"),
imageService = require('./image-service'),
restify = require('restify'),
request = require('request').defaults({ encoding: null }),
url = require('url'),
validUrl = require('valid-url');

// Maximum number of hero cards to be returned in the carousel. If this number is greater than 5, skype throws an exception.
const MAX_CARD_COUNT = 5;
// Maximum number of hero cards to be returned in the carousel. If this number is greater than 10, skype throws an exception.
const MAX_CARD_COUNT = 10;

//=========================================================
// Bot Setup
//=========================================================

// Setup Restify Server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3979, () => {
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log('%s listening to %s', server.name, server.url);
});

Expand All @@ -32,9 +31,9 @@ const connector = new builder.ChatConnector({
appPassword: process.env.MICROSOFT_APP_PASSWORD
});

const bot = new builder.UniversalBot(connector);
server.post('/api/messages', connector.listen());

const bot = new builder.UniversalBot(connector);

//=========================================================
// Bots Events
Expand All @@ -47,7 +46,7 @@ bot.on('conversationUpdate', message => {
if (identity.id === message.address.bot.id) {
const reply = new builder.Message()
.address(message.address)
.text("Hi! I am SimilarProducts Bot. I can find you similar products. Try sending me an image or an image URL.");
.text('Hi! I am SimilarProducts Bot. I can find you similar products. Try sending me an image or an image URL.');
bot.send(reply);
}
});
Expand All @@ -67,15 +66,16 @@ bot.dialog('/', session => {
.getSimilarProductsFromStream(stream)
.then(visuallySimilarProducts => handleApiResponse(session, visuallySimilarProducts))
.catch(error => handleErrorResponse(session, error));
}
else if (imageUrl = (parseAnchorTag(session.message.text) || (validUrl.isUri(session.message.text) ? session.message.text : null))) {
imageService
.getSimilarProductsFromUrl(imageUrl)
.then(visuallySimilarProducts => handleApiResponse(session, visuallySimilarProducts))
.catch(error => handleErrorResponse(session, error));
}
else {
session.send("Did you upload an image? I'm more of a visual person. Try sending me an image or an image URL");
} else {
var imageUrl = parseAnchorTag(session.message.text) || (validUrl.isUri(session.message.text) ? session.message.text : null);
if (imageUrl) {
imageService
.getSimilarProductsFromUrl(imageUrl)
.then(visuallySimilarProducts => handleApiResponse(session, visuallySimilarProducts))
.catch(error => handleErrorResponse(session, error));
} else {
session.send('Did you upload an image? I\'m more of a visual person. Try sending me an image or an image URL');
}
}
});

Expand All @@ -84,9 +84,9 @@ bot.dialog('/', session => {
//=========================================================

const hasImageAttachment = session => {
return ((session.message.attachments.length > 0) && (session.message.attachments[0].contentType.indexOf("image") !== -1));
}

return session.message.attachments.length > 0 &&
session.message.attachments[0].contentType.indexOf('image') !== -1;
};
const getImageStreamFromAttachment = attachment => {
var headers = {};
if (isSkypeAttachment(attachment)) {
Expand All @@ -104,19 +104,21 @@ const getImageStreamFromAttachment = attachment => {

headers['Content-Type'] = attachment.contentType;
return request.get({ url: attachment.contentUrl, headers: headers });
}
};

const isSkypeAttachment = attachment => {
if (url.parse(attachment.contentUrl).hostname.substr(-"skype.com".length) == "skype.com") {
if (url.parse(attachment.contentUrl).hostname.substr(-'skype.com'.length) === 'skype.com') {
return true;
}

return false;
}
};

/**
* Gets the href value in an anchor element.
* Skype transforms raw urls to html. Here we extract the href value from the url
* @param {string} input Anchor Tag
* @return {string} Url matched or null
*/
const parseAnchorTag = input => {
var match = input.match("^<a href=\"([^\"]*)\">[^<]*</a>$");
Expand All @@ -125,7 +127,7 @@ const parseAnchorTag = input => {
}

return null;
}
};

//=========================================================
// Response Handling
Expand All @@ -143,16 +145,14 @@ const handleApiResponse = (session, images) => {

// create reply with Carousel AttachmentLayout
var reply = new builder.Message(session)
.text("Here are some visually similar products I found")
.text('Here are some visually similar products I found')
.attachmentLayout(builder.AttachmentLayout.carousel)
.attachments(cards);
session.send(reply);
} else {
session.send('Couldn\'t find similar products images for this one');
}
else {
session.send("Couldn't find similar products images for this one");
}

}
};

const constructCard = (session, image) => {
return new builder.HeroCard(session)
Expand All @@ -162,12 +162,12 @@ const constructCard = (session, image) => {
builder.CardImage.create(session, image.thumbnailUrl)
])
.buttons([
builder.CardAction.openUrl(session, image.hostPageUrl, "Buy from merchant"),
builder.CardAction.openUrl(session, image.webSearchUrl, "Find more in Bing")
])
}
builder.CardAction.openUrl(session, image.hostPageUrl, 'Buy from merchant'),
builder.CardAction.openUrl(session, image.webSearchUrl, 'Find more in Bing')
]);
};

const handleErrorResponse = (session, error) => {
session.send("Oops! Something went wrong. Try again later.");
session.send('Oops! Something went wrong. Try again later.');
console.error(error);
}
};
20 changes: 10 additions & 10 deletions Node/intelligence-SimilarProducts/image-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// https://msdn.microsoft.com/en-us/library/dn760791.aspx
const request = require('request').defaults({ encoding: null });

const BING_API_URL = "https://api.cognitive.microsoft.com/bing/v5.0/images/search?modulesRequested=SimilarProducts&mkt=en-us&form=BCSPRD";
const BING_API_URL = 'https://api.cognitive.microsoft.com/bing/v5.0/images/search?modulesRequested=SimilarProducts&mkt=en-us&form=BCSPRD';

const BING_SEARCH_API_KEY = process.env.BING_SEARCH_API_KEY;

/**
* Gets the similar products of the image from an image stream
* @param {stream} stream The stream to an image.
* @return (Promise) Promise with visuallySimilarProducts array if succeeded, error otherwise
* @return {Promise} Promise with visuallySimilarProducts array if succeeded, error otherwise
*/
exports.getSimilarProductsFromStream = stream => {
return new Promise(
Expand All @@ -22,15 +22,15 @@ exports.getSimilarProductsFromStream = stream => {
file: stream
},
headers: {
"Ocp-Apim-Subscription-Key": BING_SEARCH_API_KEY
'Ocp-Apim-Subscription-Key': BING_SEARCH_API_KEY
}
};

request.post(requestData, (error, response, body) => {
if (error) {
reject(error);
}
else if (response.statusCode != 200) {
else if (response.statusCode !== 200) {
reject(body);
}
else {
Expand All @@ -39,20 +39,20 @@ exports.getSimilarProductsFromStream = stream => {
});
}
);
}
};

/**
* Gets the similar products of the image from an image URL
* @param {string} url The URL to an image.
* @return (Promise) Promise with visuallySimilarProducts array if succeeded, error otherwise
* @return {Promise} Promise with visuallySimilarProducts array if succeeded, error otherwise
*/
exports.getSimilarProductsFromUrl = url => {
return new Promise(
(resolve, reject) => {
const requestData = {
url: BING_API_URL + "&imgurl=" + url,
url: BING_API_URL + '&imgurl=' + url,
headers: {
"Ocp-Apim-Subscription-Key": BING_SEARCH_API_KEY
'Ocp-Apim-Subscription-Key': BING_SEARCH_API_KEY
},
json: true
};
Expand All @@ -61,7 +61,7 @@ exports.getSimilarProductsFromUrl = url => {
if (error) {
reject(error);
}
else if (response.statusCode != 200) {
else if (response.statusCode !== 200) {
reject(body);
}
else {
Expand All @@ -70,4 +70,4 @@ exports.getSimilarProductsFromUrl = url => {
});
}
);
}
};
8 changes: 4 additions & 4 deletions Node/intelligence-SimilarProducts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"auhor": "",
"license": "MIT",
"dependencies": {
"botbuilder": "^3.2.3",
"dotenv-extended": "^1.0.3",
"request": "^2.75.0",
"restify": "^4.1.1",
"botbuilder": "^3.5.1",
"dotenv-extended": "^1.0.4",
"request": "^2.79.0",
"restify": "^4.3.0",
"url": "^0.11.0",
"valid-url": "^1.0.9"
}
Expand Down

0 comments on commit 57927e4

Please sign in to comment.