-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathfacebookInterceptor.js
196 lines (176 loc) · 8.69 KB
/
facebookInterceptor.js
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
'use strict';
const GoogleTranslator = require('./lib/GoogleTranslator');
const ImageProcessor = require('./lib/ImageProcessor');
const StorageController = require("./lib/StorageController");
const LexController = require("./lib/LexController");
const SimpleTableController = require("./lib/SimpleTableController");
const SessionTracker = require("./lib/SessionTracker");
const AudioConverter = require("./lib/AudioFormatConverter");
const SpeechRecognizer = require("./lib/SpeechRecognizer");
const TextSpeechController = require("./lib/TextSpeechController");
const FacebookMessenger = require("./lib/FacebookMessenger");
const PAGE_TOKEN = process.env.PAGE_TOKEN;
const VERIFY_TOKEN = process.env.VERIFY_TOKEN;
const QRCODE_FUNCTION = process.env.QRCODE_FUNCTION;
const BOT_ALIAS = process.env.BOT_ALIAS;
const BOT_NAME = process.env.BOT_NAME;
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY;
const ATTACHMENT_BUCKET = process.env.ATTACHMENT_BUCKET;
const VOICE_BUCKET = process.env.VOICE_BUCKET;
const VOICE_SITE_URL = process.env.VOICE_SITE_URL;
const SESSION_TABLE_NAME = process.env.SESSION_TABLE_NAME;
const IMAGE_TABLE = process.env.IMAGE_TABLE;
const ALLOWED_LANGUAGES = process.env.ALLOWED_LANGUAGES;
const SPEECH_RECOGNIZE_LANGUAGE = process.env.SPEECH_RECOGNIZE_LANGUAGE;
const SYNTHESIZE_SPEECH_LANGUAGE_HINTS = process.env.SYNTHESIZE_SPEECH_LANGUAGE_HINTS;
const googleTranslator = new GoogleTranslator(GOOGLE_API_KEY, ALLOWED_LANGUAGES);
const lexController = new LexController(BOT_NAME, BOT_ALIAS);
const sessionTracker = new SessionTracker(SESSION_TABLE_NAME);
const facebookMessenger = new FacebookMessenger(PAGE_TOKEN);
exports.handler = (event, context, callback) => {
console.log(JSON.stringify(event));
if (event.queryStringParameters) {
console.log("Handle Verification.");
// process GET request
let queryParams = event.queryStringParameters;
let rVerifyToken = queryParams['hub.verify_token'];
if (rVerifyToken === VERIFY_TOKEN) {
let challenge = queryParams['hub.challenge'];
callback(null, createResponse(200, parseInt(challenge)))
} else {
callback(null, createResponse(500, 'Error, wrong validation token'));
}
} else {
console.log("Handle Facebook Chat.");
// process POST request
let body = JSON.parse(event.body);
console.log(JSON.stringify(body));
//Flat Map
let messagingEvents = body.entry.reduce((list, x) => list.concat(x.messaging), []);
Promise.all(messagingEvents.map(processMessage))
.then(values => {
console.log("Call back without Error");
console.log(JSON.stringify(values));
callback(null, createResponse(200, JSON.stringify(values)));
}).catch(reason => {
console.log(reason);
console.log("Call back with Error");
callback(null, createResponse(200, reason));
});
}
};
const processMessage = messagingEvent => new Promise((resolve, reject) => {
console.log(JSON.stringify(messagingEvent));
let process;
if (messagingEvent.message.attachments) { //Facebook Attachments
let attachments = messagingEvent.message.attachments;
console.log("attachments", JSON.stringify(attachments));
let imageLinks = attachments
.filter(c => c.type === "image")
.map(c => c.payload.url);
let audioLinks = attachments
.filter(c => c.type === "audio")
.map(c => c.payload.url);
if (audioLinks.length === 1) {
console.log("Audio links: " + audioLinks);
process = processAudio(audioLinks[0])
.then(voice => new Promise((resolve, reject) => {
messagingEvent.message = voice.message;
if (messagingEvent.message.text !== "") {
facebookMessenger.sendTextMessage(messagingEvent.sender.id, "You: " + messagingEvent.message.text);
resolve(messagingEvent);
} else {
facebookMessenger.sendTextMessage(messagingEvent.sender.id, "Sorry, I cannot recognize your speech!");
reject("Cannot recognize Audio.");
}
}
))
.then(c => googleTranslator.detectLanguage(c))
.then(c => sessionTracker.restoreLastSession(c))
.then(c => googleTranslator.translateRequest(c));
} else if (imageLinks.length > 0) {
console.log("Image links: " + imageLinks);
process = Promise.all(imageLinks.map(processImage))
.then(imageData => new Promise((resolve, reject) => {
messagingEvent.imageData = imageData;
let sessionAttributes = messagingEvent.sessionAttributes || {};
if (sessionAttributes.currentSlot) {
console.log("Save currentSlot translated text for Images");
sessionAttributes["original_" + sessionAttributes.currentSlot] = "" + imageLinks;
sessionAttributes["translated_" + sessionAttributes.currentSlot] = "" + imageLinks;
}
resolve(messagingEvent);
}
)).then(c => sessionTracker.restoreLastSession(c))
.then(saveImageDataToSessionTable);
} else {
reject("Unsupported file type!");
}
} else {
if (messagingEvent.message && messagingEvent.message.text) {
let text = messagingEvent.message.text;
console.log("Receive a message: " + text);
process = googleTranslator.detectLanguage(messagingEvent)
.then(c => sessionTracker.restoreLastSession(c))
.then(c => googleTranslator.translateRequest(c));
}
}
if (process) {
let textSpeechController = new TextSpeechController(SYNTHESIZE_SPEECH_LANGUAGE_HINTS);
let storageController = new StorageController(VOICE_BUCKET);
process.then(c => lexController.postText(c))
.then(c => sessionTracker.saveCurrentSession(c))
.then(c => googleTranslator.translateReply(c))
.then(c => textSpeechController.getSpeech(c))
.then(c => storageController.uploadToS3(c))
.then(messagingEvent => {
console.log("sendTextMessage", messagingEvent);
let voiceUrl = VOICE_SITE_URL + "/" + messagingEvent.Key;
return facebookMessenger.sendVoiceMessage(messagingEvent.sender.id, voiceUrl)
.then(facebookMessenger.sendTextMessage(messagingEvent.sender.id, messagingEvent.message.reply));
})
.then(resolve)
.catch(reject);
}
});
const saveImageDataToSessionTable = (messagingEvent) => {
return new Promise((resolve, reject) => {
//Save into Session and send send "OK" to Lex.
let sessionAttributes = messagingEvent.sessionAttributes ? messagingEvent.sessionAttributes : {};
//Lex sessionAttributes does not support tree like json!
sessionAttributes.imageData = "true";
messagingEvent.sessionAttributes = sessionAttributes;
let imageTable = new SimpleTableController(IMAGE_TABLE);
imageTable.put({id: messagingEvent.sender.id, data: messagingEvent.imageData})
.then(data => {
messagingEvent.message = {text: "OK", language: googleTranslator.getDefaultLanguages()};
resolve(messagingEvent);
}).catch(reject);
});
};
const processImage = imageLink => {
console.log("processImage:" + imageLink);
let imageProcessor = new ImageProcessor(QRCODE_FUNCTION, ATTACHMENT_BUCKET);
let storageController = new StorageController(ATTACHMENT_BUCKET);
return storageController.downloadToTmp(imageLink)
.then(c => storageController.uploadToS3(c))
.then(c => imageProcessor.qrCodeDecode(c))
.then(c => imageProcessor.detectLabels(c));
};
const processAudio = audioLink => {
console.log("processAudio:" + audioLink);
let audioConverter = new AudioConverter();
let storageController = new StorageController(ATTACHMENT_BUCKET);
let speechRecognizer = new SpeechRecognizer(GOOGLE_API_KEY, SPEECH_RECOGNIZE_LANGUAGE);
return storageController.downloadToTmp(audioLink)
.then(c => storageController.uploadToS3(c))
.then(c => audioConverter.convertToLinear16(c))
.then(c => storageController.uploadToS3(c))
.then(c => speechRecognizer.getText(c));
};
const createResponse = (statusCode, body) => {
return {
statusCode: statusCode,
body: body
}
};