');
$('body').append(datalist);
} else {
datalist.html('');
}
for (i = 0; i < examplePhrases.length; i++) {
datalist.append($(' '));
}
//console.log(examplePhrases);
$('#chatBotCommandDescription').html(description);
}
// type writer
function playConversation(state, pauseLength) {
setTimeout(function() {
var newValue = '';
if ($(inputs).val() != '|') {
newValue += $(inputs).val();
}
newValue += state.currentInput.slice(state.start,state.start+1);
$(inputs).val(newValue);
state.start++;
if (state.start < state.currentInput.length) {
// keep typing
playConversation(state, pauseLength);
} else {
// press enter and wait for some time and then write the next entry
ChatBot.addChatEntry(state.currentInput, "human");
ChatBot.react(state.currentInput);
$(inputs).val(state.currentInput);
setTimeout(function() {
state.conversationArrayIndex++;
state.conversationArrayIndex = state.conversationArrayIndex % state.conversationArray.length;
// did we cycle through the conversation array? if so, stop
if (state.conversationArrayIndex == 0) {
$('#chatBotConversationLoadingBar').remove();
sampleConversationRunning = false;
return;
}
state.start = 0;
$(inputs).val('|');
state.currentInput = state.conversationArray[state.conversationArrayIndex];
playConversation(state, pauseLength);
}, pauseLength);
var chclb = $('#chatBotConversationLoadingBar');
if (chclb.size() == 0) {
chclb = $('
');
chclb.css('position','absolute');
$('body').append(chclb);
}
var left = $(inputs).offset().left;
var top = $(inputs).offset().top + $(inputs).outerHeight() - 3;
chclb.css('left',left+'px');
chclb.css('top',top+'px');
chclb.animate({
width: $(inputs).outerWidth()+'px',
}, pauseLength, function() {
chclb.css('width','0');
});
}
}, Math.random()*120+10);
}
return {
Engines: {
// the webknox API: http://webknox.com/api
webknox: function (apiKey) {
// patterns that the engine can resolve
var capabilities = [
"Ask for stock prices like 'stock price apple' or '[company] stock'.",
"Ask for distances as in 'how far is Perth from Melbourne' or 'distance between [place1] and [place2]'.",
"Want to know what the weather is like, just ask like 'weather in San Diego, California'.",
"Let WebKnox tell you a joke, just say 'tell me a joke'.",
"Convert units, e.g. '2.4 miles in kilometers' or '4 tablespoons to ml?'.",
"Get synonyms for a word, e.g. 'synonyms for car'.",
"Ask for quotes like 'quotes about [topic]' or 'quotes about love'.",
"Ask for quotes from a person 'quotes by [person]' or 'quotes by aristotle'.",
"Ask for recipes like 'spaghetti recipes' or 'chocolate donuts'.",
"Ask for nutrient contents like 'vitamin a in 2 carrots' or 'calories is 1 cup of butter'.",
"Convert ingredients like '2 cups of butter in grams'.",
"If you want more results, just say 'more'.",
"For more similar results say 'more like the first/second/third...'.",
"Or just ask anything that comes to mind like 'Who was pope in 1499?' or 'Who directed braveheart?'.",
];
// the context id for the current conversation
var contextId = Math.random() * 100000;
return {
react: function (query) {
$.get('https://webknox-question-answering.p.mashape.com/questions/converse?mashape-key=' + apiKey + '&contextId=' + contextId + '&text=' + encodeURIComponent(query), function (data) {
var content = data.answerText;
if (data.media != undefined) {
content += ' ';
for (var i = 0; i < data.media.length; i++) {
var ob = data.media[i];
content += '' +
'
' +
'
' + ob.title + '
' +
'
' +
'
Details
' +
'
' +
'
More like this
' +
'
' +
'
';
}
}
ChatBot.addChatEntry(content, "bot");
ChatBot.thinking(false);
});
},
getCapabilities: function () {
return capabilities;
},
getSuggestUrl: function() {
return 'https://webknox-question-answering.p.mashape.com/questions/converse/suggest?mashape-key=' + apiKey + '&query=';
}
}
},
// the spoonacular API: http://spoonacular.com/food-api
spoonacular: function (apiKey) {
// patterns that the engine can resolve
var capabilities = [
"Ask for recipes like 'chicken recipes' or 'spaghetti with shrimp'",
"Ask for nutrient contents like 'vitamin a in 2 carrots' or 'calories is 1 cup of butter'",
"Convert something with '2 cups of butter in grams'",
"If you want more results, just say 'more'",
"For more similar results say 'more like the first/second/third...'",
"Let spoonacular tell you a joke, just say 'tell me a joke'.",
"Want to learn some food trivia, just say 'food trivia'.",
];
// the context id for the current conversation
var contextId = Math.random() * 100000;
return {
react: function (query) {
$.get('https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/food/converse?mashape-key=' + apiKey + '&contextId=' + contextId + '&text=' + encodeURIComponent(query), function (data) {
var content = data.answerText;
if (data.media != undefined) {
content += ' ';
for (var i = 0; i < data.media.length; i++) {
var ob = data.media[i];
content += '' +
'
' +
'
' + ob.title + '
' +
'
' +
'
Details
' +
'
' +
'
More like this
' +
'
' +
'
';
}
}
ChatBot.addChatEntry(content, "bot");
ChatBot.thinking(false);
});
},
getCapabilities: function () {
return capabilities;
},
getSuggestUrl: function() {
return 'https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/food/converse/suggest?mashape-key=' + apiKey + '&query=';
}
}
},
duckduckgo: function () {
// patterns that the engine can resolve
var capabilities = [
"Ask what something is like 'What is DNA'?",
"Ask where something is like 'Where is China'?",
"Ask about a person like 'Who is Bill Gates'?",
"Say a movie/person/location name like 'Braveheart' to get information about that entity",
"Say a something like 'simpsons characters' to get information about that phrase",
];
return {
react: function (query) {
$.ajax({
type: 'GET',
url: 'https://api.duckduckgo.com/?format=json&pretty=1&q=' + encodeURIComponent(query),
dataType: 'jsonp'
}).done(function (data) {
var content = data.AbstractText;
// no direct answer? tell about related topics then
if (content == '' && data.RelatedTopics.length > 0) {
content = 'I found multiple answers for you:
';
var media = [];
for (var i = 0; i < data.RelatedTopics.length; i++) {
var ob = data.RelatedTopics[i];
if (ob.Result == undefined) {
continue;
}
if (ob.Icon.URL != '' && ob.Icon.URL.indexOf(".ico") < 0) {
media.push(ob.Icon.URL);
}
content += '' + ob.Result.replace("", " ") + '
';
}
///content += ' ' +
for (i = 0; i < media.length; i++) {
var m = media[i];
content += ' ';
}
} else {
if (data.Image != undefined && data.Image != '') {
content += ' ';
content += '' +
'
' +
'
' + data.Heading + '
' +
'
';
}
}
ChatBot.addChatEntry(content, "bot");
ChatBot.thinking(false);
});
},
getCapabilities: function () {
return capabilities;
},
getSuggestUrl: function() {
return null;
}
}
}
},
init: function (options) {
var settings = jQuery.extend({
// these are the defaults.
botName: 'Bot',
humanName: 'You',
thinkingHtml: ' ',
inputs: '',
inputCapabilityListing: true,
engines: [],
patterns: [],
normalizer: [],
addChatEntryCallback: function(entryDiv, text, origin) {
entryDiv.addClass('appear');
}
}, options);
botName = settings.botName;
humanName = settings.humanName;
thinkingHtml = settings.thinkingHtml;
inputs = settings.inputs;
inputCapabilityListing = settings.inputCapabilityListing;
engines = settings.engines;
patterns = settings.patterns;
addChatEntryCallback = settings.addChatEntryCallback;
normalizer = settings.normalizer;
// update the command description
updateCommandDescription();
// input capability listing?
if (inputCapabilityListing) {
$(inputs).attr("list", "chatBotCommands");
}
// listen to inputs on the defined fields
$(inputs).keyup(function (e) {
if (e.keyCode == 13) {
ChatBot.addChatEntry($(this).val(), "human");
ChatBot.react($(this).val());
}
//console.log($(this).val());
});
},
setBotName: function (name) {
botName = name;
},
setHumanName: function (name) {
humanName = name;
$('.chatBotChatEntry.human .origin').html(name);
},
addChatEntry: function addChatEntry(text, origin) {
if (text == undefined) {
return;
}
if (text == '') {
text = 'Sorry, I have no idea.';
}
var entryDiv = $('
');
entryDiv.html('' + (origin == 'bot' ? botName : humanName) + ' ' + text);
$('#chatBotHistory').prepend(entryDiv);
if (addChatEntryCallback != undefined) {
addChatEntryCallback.call(this, entryDiv, text, origin);
}
},
thinking: function (on) {
var ti = $('#chatBotThinkingIndicator');
if (on) {
if (!sampleConversationRunning) {
$(inputs).attr('disabled', 'disabled');
}
ti.html(thinkingHtml);
} else {
if (!sampleConversationRunning) {
$(inputs).removeAttr('disabled');
$(inputs).val('');
$(inputs).focus();
}
ti.html('');
}
},
react: function react(text) {
this.thinking(true);
// normalize the human text
normalizer.map( method => {
if(
String.prototype[ method ] instanceof Function
) {
// string immuable object
text = text[ method ]();
} else if( method instanceof Function ) {
text = method( text ) || text;
}
} ) ;
// check for custom patterns
for (var i = 0; i < patterns.length; i++) {
var pattern = patterns[i];
var r = new RegExp(pattern.regexp, "i");
var matches = text.match(r);
//console.log(matches);
if (matches) {
switch (pattern.actionKey) {
case 'rewrite':
text = pattern.actionValue;
for (var j = 1; j < matches.length; j++) {
text = text.replace("$" + j, matches[j]);
}
//console.log("rewritten to " + text);
if (pattern.callback != undefined) {
pattern.callback.call(this, matches);
}
break;
case 'response':
// var response = text.replace(r, pattern.actionValue);
var response = pattern.actionValue;
if (response != undefined) {
for (var j = 1; j < matches.length; j++) {
response = response.replace("$" + j, matches[j]);
}
this.addChatEntry(response, "bot");
}
ChatBot.thinking(false);
if (pattern.callback != undefined) {
pattern.callback.call(this, matches);
}
return;
}
break;
}
}
for (var e = 0; e < engines.length; e++) {
var engine = engines[e];
engine.react(text);
}
},
playConversation: function (conversation, pauseLength) {
if (pauseLength == undefined) {
pauseLength = 3000;
}
if (sampleConversationRunning) {
return false;
}
$(inputs).val('');
sampleConversationRunning = true;
var state = {
start: 0,
conversationArrayIndex: 0,
conversationArray: conversation,
currentInput: conversation[0]
};
playConversation(state, pauseLength);
return true;
},
addPatternObject: function (obj) {
patterns.push(obj);
updateCommandDescription();
},
addPattern: function (regexp, actionKey, actionValue, callback, description) {
var obj = {
regexp: regexp,
actionKey: actionKey,
actionValue: actionValue,
description: description,
callback: callback
};
this.addPatternObject(obj);
}
}
}();