Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

app.js 6.1 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  1. /*-----------------------------------------------------------------------------
  2. A Similar Products bot for the Microsoft Bot Framework.
  3. -----------------------------------------------------------------------------*/
  4. // This loads the environment variables from the .env file
  5. require('dotenv-extended').load();
  6. var builder = require('botbuilder'),
  7. restify = require('restify'),
  8. request = require('request').defaults({ encoding: null }),
  9. url = require('url'),
  10. validUrl = require('valid-url'),
  11. imageService = require('./image-service');
  12. // Maximum number of hero cards to be returned in the carousel. If this number is greater than 10, skype throws an exception.
  13. var MAX_CARD_COUNT = 10;
  14. //=========================================================
  15. // Bot Setup
  16. //=========================================================
  17. // Setup Restify Server
  18. var server = restify.createServer();
  19. server.listen(process.env.port || process.env.PORT || 3978, function () {
  20. console.log('%s listening to %s', server.name, server.url);
  21. });
  22. // Create chat bot
  23. var connector = new builder.ChatConnector({
  24. appId: process.env.MICROSOFT_APP_ID,
  25. appPassword: process.env.MICROSOFT_APP_PASSWORD
  26. });
  27. server.post('/api/messages', connector.listen());
  28. // Gets the similar images by checking the type of the image (stream vs URL) and calling the appropriate image service method.
  29. var bot = new builder.UniversalBot(connector, function (session) {
  30. if (hasImageAttachment(session)) {
  31. var stream = getImageStreamFromMessage(session.message);
  32. imageService
  33. .getSimilarProductsFromStream(stream)
  34. .then(function (visuallySimilarProducts) { handleApiResponse(session, visuallySimilarProducts); })
  35. .catch(function (error) { handleErrorResponse(session, error); });
  36. } else {
  37. var imageUrl = parseAnchorTag(session.message.text) || (validUrl.isUri(session.message.text) ? session.message.text : null);
  38. if (imageUrl) {
  39. imageService
  40. .getSimilarProductsFromUrl(imageUrl)
  41. .then(function (visuallySimilarProducts) { handleApiResponse(session, visuallySimilarProducts); })
  42. .catch(function (error) { handleErrorResponse(session, error); });
  43. } else {
  44. session.send('Did you upload an image? I\'m more of a visual person. Try sending me an image or an image URL');
  45. }
  46. }
  47. });
  48. //=========================================================
  49. // Bots Events
  50. //=========================================================
  51. //Sends greeting message when the bot is first added to a conversation
  52. bot.on('conversationUpdate', function (message) {
  53. if (message.membersAdded) {
  54. message.membersAdded.forEach(function (identity) {
  55. if (identity.id === message.address.bot.id) {
  56. var reply = new builder.Message()
  57. .address(message.address)
  58. .text('Hi! I am SimilarProducts Bot. I can find you similar products. Try sending me an image or an image URL.');
  59. bot.send(reply);
  60. }
  61. });
  62. }
  63. });
  64. //=========================================================
  65. // Utilities
  66. //=========================================================
  67. function hasImageAttachment(session) {
  68. return session.message.attachments.length > 0 &&
  69. session.message.attachments[0].contentType.indexOf('image') !== -1;
  70. }
  71. function getImageStreamFromMessage(message) {
  72. var headers = {};
  73. var attachment = message.attachments[0];
  74. if (checkRequiresToken(message)) {
  75. // The Skype attachment URLs are secured by JwtToken,
  76. // you should set the JwtToken of your bot as the authorization header for the GET request your bot initiates to fetch the image.
  77. // https://github.com/Microsoft/BotBuilder/issues/662
  78. connector.getAccessToken(function (error, token) {
  79. var tok = token;
  80. headers['Authorization'] = 'Bearer ' + token;
  81. headers['Content-Type'] = 'application/octet-stream';
  82. return request.get({ url: attachment.contentUrl, headers: headers });
  83. });
  84. }
  85. headers['Content-Type'] = attachment.contentType;
  86. return request.get({ url: attachment.contentUrl, headers: headers });
  87. }
  88. function checkRequiresToken(message) {
  89. return message.source === 'skype' || message.source === 'msteams';
  90. }
  91. /**
  92. * Gets the href value in an anchor element.
  93. * Skype transforms raw urls to html. Here we extract the href value from the url
  94. * @param {string} input Anchor Tag
  95. * @return {string} Url matched or null
  96. */
  97. function parseAnchorTag(input) {
  98. var match = input.match("^<a href=\"([^\"]*)\">[^<]*</a>$");
  99. if (match && match[1]) {
  100. return match[1];
  101. }
  102. return null;
  103. }
  104. //=========================================================
  105. // Response Handling
  106. //=========================================================
  107. function handleApiResponse(session, images) {
  108. if (images && images.constructor === Array && images.length > 0) {
  109. var productCount = Math.min(MAX_CARD_COUNT, images.length);
  110. var cards = new Array();
  111. for (var i = 0; i < productCount; i++) {
  112. cards.push(constructCard(session, images[i]));
  113. }
  114. // create reply with Carousel AttachmentLayout
  115. var reply = new builder.Message(session)
  116. .text('Here are some visually similar products I found')
  117. .attachmentLayout(builder.AttachmentLayout.carousel)
  118. .attachments(cards);
  119. session.send(reply);
  120. } else {
  121. session.send('Couldn\'t find similar products images for this one');
  122. }
  123. }
  124. function constructCard(session, image) {
  125. return new builder.HeroCard(session)
  126. .title(image.name)
  127. .subtitle(image.hostPageDisplayUrl)
  128. .images([
  129. builder.CardImage.create(session, image.thumbnailUrl)
  130. ])
  131. .buttons([
  132. builder.CardAction.openUrl(session, image.hostPageUrl, 'Buy from merchant'),
  133. builder.CardAction.openUrl(session, image.webSearchUrl, 'Find more in Bing')
  134. ]);
  135. }
  136. function handleErrorResponse(session, error) {
  137. session.send('Oops! Something went wrong. Try again later.');
  138. console.error(error);
  139. }
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...