forked from AakashSorathiya/ChatBot-UI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
598 lines (405 loc) · 14.3 KB
/
index.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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
//---------------------------------- Credentials Section ----------------------------------//
// All credentials come from credentials.js which isnt on github
// Information needed to access the api.ai bot, only thing needed to be changed
// Emoji Bot
var accessToken = credentialsAccessToken;
//var bot name is used for the firebase database
var botName = credentialsBotName;
var baseUrl = credentialsBaseUrl;
// Initialize Firebase
var config = credentialsConfig;
// The format for config is as follows
// Set the configuration for your app
// TODO: Replace with your project's config object
// You can get this information by creating a project and clicking connect with web or start with web
// var config = {
// apiKey: "apiKey",
// authDomain: "projectId.firebaseapp.com",
// databaseURL: "https://databaseName.firebaseio.com",
// storageBucket: "bucket.appspot.com"
// };
firebase.initializeApp(config);
// Key for this instance of the chat interface
var newKey = firebase.database().ref(botName).push().key;
console.log("Key for this chat instance = " + newKey);
//---------------------------------- Main Code Area ----------------------------------//
// Variables to be used for storing the last message sent and recieved for the database
var lastSentMessage = "";
var lastRecievedMessage = 1;
var ButtonClicked = false;
var DEFAULT_TIME_DELAY = 3000;
// Variable for the chatlogs div
var $chatlogs = $('.chatlogs');
$('document').ready(function(){
// Hide the switch input type button initially
$("#switchInputType").toggle();
// If the switch input type button is pressed
$("#switchInputType").click(function(event) {
// Toggle which input type is shown
if($('.buttonResponse').is(":visible")) {
$("#switchInputType").attr("src", "Images/multipleChoice.png");
}
else {
$("#switchInputType").attr("src", "Images/keyboard.png");
}
$('textarea').toggle();
$('.buttonResponse').toggle();
});
//----------------------User Sends Message Methods--------------------------------//
// Method which executes once the enter key on the keyboard is pressed
// Primary function sends the text which the user typed
$("textarea").keypress(function(event) {
// If the enter key is pressed
if(event.which === 13) {
// Ignore the default function of the enter key(Dont go to a new line)
event.preventDefault();
ButtonClicked = false;
// Call the method for sending a message, pass in the text from the user
send(this.value);
// reset the size of the text area
$(".input").attr("rows", "1");
// Clear the text area
this.value = "";
if($("#switchInputType").is(":visible")) {
$("#switchInputType").toggle();
$('.buttonResponse').remove();
}
}
});
// If the user presses the button for voice input
$("#rec").click(function(event) {
// Call the method to switch recognition to voice input
switchRecognition();
});
// If the user selects one of the dynamic button responses
$('.chat-form').on("click", '.buttonResponse', function() {
ButtonClicked = true;
// Send the text on the button as a user message
send(this.innerText);
// Show the record button and text input area
//$('#rec').toggle();
$('textarea').toggle();
// Hide the button responses and the switch input button
$('.buttonResponse').toggle();
$('#switchInputType').hide();
// Remove the button responses from the div
$('.buttonResponse').remove();
});
})
// Method which takes the users text and sends an AJAX post request to API.AI
// Creates a new Div with the users text, and recieves a response message from API.AI
function send(text) {
// Create a div with the text that the user typed in
$chatlogs.append(
$('<div/>', {'class': 'chat self'}).append(
$('<p/>', {'class': 'chat-message', 'text': text})));
// Find the last message in the chatlogs
var $sentMessage = $(".chatlogs .chat").last();
// Check to see if that message is visible
checkVisibility($sentMessage);
// update the last message sent variable to be stored in the database and store in database
lastSentMessage = text;
storeMessageToDB();
// AJAX post request, sends the users text to API.AI and
// calls the method newReceivedMessage with the response from API.AI
$.ajax({
type: "POST",
url: baseUrl + "query?v=20150910",
contentType: "application/json; charset=utf-8",
dataType: "json",
headers: {
"Authorization": "Bearer " + accessToken
},
data: JSON.stringify({ query: text, lang: "en", sessionId: "somerandomthing" }),
success: function(data) {
console.log(data);
// Pass the response into the method
newRecievedMessage(JSON.stringify(data.result.fulfillment.speech, undefined, 2));
},
error: function() {
newRecievedMessage("Internal Server Error");
}
});
}
//----------------------User Receives Message Methods--------------------------------//
// Method called whenver there is a new recieved message
// This message comes from the AJAX request sent to API.AI
// This method tells which type of message is to be sent
// Splits between the button messages, multi messages and single message
function newRecievedMessage(messageText) {
// Variable storing the message with the "" removed
var removedQuotes = messageText.replace(/[""]/g,"");
// update the last message recieved variable for storage in the database
lastRecievedMessage = removedQuotes;
// If the message contains a <ar then it is a message
// whose responses are buttons
if(removedQuotes.includes("<ar"))
{
buttonResponse(removedQuotes);
}
// if the message contains only <br then it is a multi line message
else if (removedQuotes.includes("<br"))
{
multiMessage(removedQuotes);
}
// There arent multiple messages to be sent, or message with buttons
else
{
// Show the typing indicator
showLoading();
// After 3 seconds call the createNewMessage function
setTimeout(function() {
createNewMessage(removedQuotes);
}, DEFAULT_TIME_DELAY);
}
}
// Method which takes messages and splits them based off a the delimeter <br 2500>
// The integer in the delimeter is optional and represents the time delay in milliseconds
// if the delimeter is not there then the time delay is set to the default
function multiMessage(message)
{
// Stores the matches in the message, which match the regex
var matches;
// List of message objects, each message will have a text and time delay
var listOfMessages = [];
// Regex used to find time delay and text of each message
var regex = /\<br(?:\s+?(\d+))?\>(.*?)(?=(?:\<br(?:\s+\d+)?\>)|$)/g;
// While matches are still being found in the message
while(matches = regex.exec(message))
{
// if the time delay is undefined(empty) use the default time delay
if(matches[1] == undefined)
{
matches[1] = DEFAULT_TIME_DELAY;
}
// Create an array of the responses which will be buttons
var messageText = matches[2].split(/<ar>/);
// Create a message object and add it to the list of messages
listOfMessages.push({
text: messageText[0],
delay: matches[1]
});
}
// loop index
var i = 0;
// Variable for the number of messages
var numMessages = listOfMessages.length;
// Show the typing indicator
showLoading();
// Function which calls the method createNewMessage after waiting on the message delay
(function theLoop (listOfMessages, i, numMessages)
{
// Method which executes after the timedelay
setTimeout(function ()
{
// Create a new message from the server
createNewMessage(listOfMessages[i].text);
// If there are still more messages
if (i++ < numMessages - 1)
{
// Show the typing indicator
showLoading();
// Call the method again
theLoop(listOfMessages, i, numMessages);
}
}, listOfMessages[i].delay);
// Pass the parameters back into the method
})(listOfMessages, i, numMessages);
}
// Method called whenever an <ar tag is found
// The responses for this type of message will be buttons
// This method parses out the time delays, message text and button responses
// Then creates a new message with the time delay and creates buttons for the responses
function buttonResponse(message)
{
// Stores the matches in the message, which match the regex
var matches;
// Used to store the new HTML div which will be the button
var $input;
// send the message to the multi message method to split it up, message will be sent here
multiMessage(message);
// Regex used to find time delay, text of the message and responses to be buttons
var regex = /\<br(?:\s+?(\d+))?\>(.*?)(?=(?:\<ar(?:\s+\d+)?\>)|$)/g;
// Seach the message and capture the groups which match the regex
matches = regex.exec(message);
console.log(matches);
// Create an array of the responses which will be buttons
var buttonList = message.split(/<ar>/);
// Remove the first element, The first split is the actual message
buttonList = buttonList.splice(1);
console.log(buttonList);
// Array which will store all of the newly created buttons
var listOfInputs = [];
// Loop through each response and create a button
for (var index = 0; index < buttonList.length; index++)
{
// Store the current button response
var response = buttonList[index];
// Create a new div element with the text for the current button response
$input = $('<div/>', {'class': 'buttonResponse' }).append(
$('<p/>', {'class': 'chat-message', 'text': response}));
// add the new button to the list of buttons
listOfInputs.push($input);
}
// Show the typing indicator
showLoading();
// After the time delay call the createNewMessage function
setTimeout(function() {
// Hide the send button and the text area
// $('#rec').toggle();
$('textarea').toggle();
// Show the switch input button
$("#switchInputType").show();
// For each of the button responses
for (var index = 0; index < listOfInputs.length; index++) {
// Append to the chat-form div which is at the bottom of the chatbox
listOfInputs[index].appendTo($('#buttonDiv'));
}
}, matches[1]);
}
// Method to create a new div showing the text from API.AI
function createNewMessage(message) {
// Hide the typing indicator
hideLoading();
// take the message and say it back to the user.
//speechResponse(message);
// // Show the send button and the text area
// $('#rec').css('visibility', 'visible');
// $('textarea').css('visibility', 'visible');
// Append a new div to the chatlogs body, with an image and the text from API.AI
$chatlogs.append(
$('<div/>', {'class': 'chat friend'}).append(
$('<div/>', {'class': 'user-photo'}).append($('<img src="Images/ana.JPG" />')),
$('<p/>', {'class': 'chat-message', 'text': message})));
// Find the last message in the chatlogs
var $newMessage = $(".chatlogs .chat").last();
// Call the method to see if the message is visible
checkVisibility($newMessage);
}
//------------------------------------------- Database Write --------------------------------------------------//
function storeMessageToDB() {
var date = new Date();
console.log(date);
if (lastRecievedMessage == 1) {
var storeMessage = firebase.database().ref(botName).child(newKey).push({
UserResponse: lastSentMessage,
Time: date + ""
});
}
else {
var storeMessage = firebase.database().ref(botName).child(newKey).push({
Question: lastRecievedMessage,
UserResponse: lastSentMessage,
ButtonClicked: ButtonClicked,
Time: date + ""
});
}
}
// Funtion which shows the typing indicator
// As well as hides the textarea and send button
function showLoading()
{
$chatlogs.append($('#loadingGif'));
$("#loadingGif").show();
// $('#rec').css('visibility', 'hidden');
// $('textarea').css('visibility', 'hidden');
$('.chat-form').css('visibility', 'hidden');
}
// Function which hides the typing indicator
function hideLoading()
{
$('.chat-form').css('visibility', 'visible');
$("#loadingGif").hide();
// Clear the text area of text
$(".input").val("");
// reset the size of the text area
$(".input").attr("rows", "1");
}
// Method which checks to see if a message is in visible
function checkVisibility(message)
{
// Scroll the view down a certain amount
$chatlogs.stop().animate({scrollTop: $chatlogs[0].scrollHeight});
}
//----------------------Voice Message Methods--------------------------------//
//Voice stuff
var recognition;
function startRecognition() {
console.log("Start")
recognition = new webkitSpeechRecognition();
recognition.onstart = function(event) {
console.log("Update");
updateRec();
};
recognition.onresult = function(event) {
var text = "";
for (var i = event.resultIndex; i < event.results.length; ++i) {
text += event.results[i][0].transcript;
}
setInput(text);
stopRecognition();
};
recognition.onend = function() {
stopRecognition();
};
recognition.lang = "en-US";
recognition.start();
}
function stopRecognition() {
if (recognition) {
console.log("Stop Recog");
recognition.stop();
recognition = null;
}
updateRec();
}
function switchRecognition() {
if (recognition) {
console.log(" Stop if");
stopRecognition();
} else {
startRecognition();
}
}
function setInput(text) {
$(".input").val(text);
send(text);
$(".input").val("");
}
function updateRec() {
if (recognition) {
$("#rec").attr("src", "Images/MicrophoneOff.png");
} else {
$("#rec").attr("src", "Images/microphone.png");
}
}
function speechResponse(message)
{
var msg = new SpeechSynthesisUtterance();
// These lines list all of the voices which can be used in speechSynthesis
//var voices = speechSynthesis.getVoices();
//console.log(voices);
msg.default = false;
msg.voiceURI = "Fiona";
msg.name = "Fiona";
msg.localService = true;
msg.text = message;
msg.lang = "en";
msg.rate = .9;
msg.volume = 1;
window.speechSynthesis.speak(msg);
}
//----------------------------------------- Resize the textarea ------------------------------------------//
$(document)
.one('focus.input', 'textarea.input', function(){
var savedValue = this.value;
this.value = '';
this.baseScrollHeight = this.scrollHeight;
this.value = savedValue;
})
.on('input.input', 'textarea.input', function(){
var minRows = this.getAttribute('data-min-rows')|0, rows;
this.rows = minRows;
rows = Math.ceil((this.scrollHeight - this.baseScrollHeight) / 17);
this.rows = minRows + rows;
});