|
|
- var storedVariableValues = {};
- var botAttributes = {};
-
- var lastWildCardValue = '';
- var wildCardArray = [];
-
- var domArray = [];
- var domIndex = 0;
-
- var isAIMLFileLoadingStarted = false;
- var isAIMLFileLoaded = false;
-
- var previousAnswer = '';
- var previousThinkTag = false;
-
- //botAttributes contain things like name, age, master, gender...
- var AIMLInterpreter = function(botAttributesParam){
- var self = this;
- botAttributes = botAttributesParam;
-
- this.loadAIMLFilesIntoArray = function(fileArray){
- isAIMLFileLoadingStarted = true;
- var fileIndex = 0;
- var readAIMLFile = function(filename){
- fileIndex++;
- //console.log(document.getElementById('botdata').import);
- var datastring;
- $(document).ready(function() {
- $.ajax({
- url : filename,
- dataType: "text",
- success : function (data) {
- datastring = data;
- //console.log(datastring);
- new DomJS().parse(datastring, function(err, dom) {
- if(dom == null){
- dom = "<aiml></aiml>";
- }
- var topCategories, topics;
- if (err) {
- // return cb(err);
- }
- if (dom.name === !'aiml') {
- // return cb('Unsupported file');
- }
- domArray[domIndex] = dom;
- domIndex++;
- if(fileIndex < fileArray.length){
- readAIMLFile(fileArray[fileIndex]);
- }
- else{
- console.log('AIML file is loaded!');
- isAIMLFileLoaded = true;
- }
- });
- }
- });
- });
- }
- readAIMLFile(fileArray[fileIndex]);
- };
-
- this.findAnswerInLoadedAIMLFiles = function(clientInput, cb){
- //check if all AIML files have been loaded. If not, call this method again after a delay
- if(isAIMLFileLoaded){
- wildCardArray = [];
- var result = '';
- for(var i = 0; i < domArray.length; i++){
- cleanDom(domArray[i].children);
- result = findCorrectCategory(clientInput, domArray[i].children);
- if(result){
- break;
- }
- }
-
- if(result){
- result = cleanStringFormatCharacters(result);
- previousAnswer = result;
- }
- cb(result, wildCardArray, clientInput);
- }
- else{
- var findAnswerInLoadedAIMLFilesWrapper = function(clientInput, cb){
- return function(){
- self.findAnswerInLoadedAIMLFiles(clientInput, cb);
- };
- };
-
- setTimeout(findAnswerInLoadedAIMLFilesWrapper(clientInput, cb), 1000);
- }
- };
- //restart the DOM in order to load a new AIML File
- this.restartDom = function(){
- domArray=[];
- domIndex=0;
- };
- };
-
-
-
-
- // remove string control characters (like line-breaks '\r\n', leading / trailing spaces etc.)
- var cleanStringFormatCharacters = function(str){
- var cleanedStr = str.replace(/\r\n/gi, '');
- cleanedStr = cleanedStr.replace(/^\s*/, '');
- cleanedStr = cleanedStr.replace(/\s*$/,'');
-
- return cleanedStr;
- }
-
- var cleanDom = function(childNodes){
- for(var i = 0; i < childNodes.length; i++){
- if(childNodes[i].hasOwnProperty('text') & typeof(childNodes[i].text) === 'string'){
-
- // remove all nodes of type 'text' when they just contain '\r\n'. This indicates line break in the AIML file
- if(childNodes[i].text.match(/^\s*\r\n\s*$/gi)){
- childNodes.splice(i, 1);
- }
- }
- }
-
-
- // traverse through whole tree by recursive calls
- for(var j = 0; j < childNodes.length; j++){
- if(childNodes[j].hasOwnProperty('children')){
- cleanDom(childNodes[j].children);
- }
- }
- };
-
- var findCorrectCategory = function(clientInput, domCategories){
- //indexOfSetTagAmountWithWildCard indicates how many sets with wildcard occur so that those sets store the correct wildcard value
- var indexOfSetTagAmountWithWildCard = 0;
-
- var travereseThroughDomToFindMatchingPattern= function(categories){
- for(var i = categories.length-1; i >= 0; i--){
- if(categories[i].name === 'category'){
- //traverse through the dom
- //text gets the value of the current pattern node
- var text = travereseThroughDomToFindMatchingPattern(categories[i].children);
- //check if the input of the user matches the pattern text
- var matches = checkIfMessageMatchesPattern(clientInput, text);
- if(matches){
- //check if a 'that' tag is existing. If yes, check if the text of the that tag matches the previous given answer.
- //If it does not match, continue the traversion through the AIML file
- var isMatchingThat = checkForThatMatching(categories[i].children);
- if(isMatchingThat){
- var text = findFinalTextInTemplateNode(categories[i].children);
- if(text){
- return text;
- }
- break;
- }
- }
- }
- else if(categories[i].name === 'pattern'){
- var text = resolveChildNodesInPatternNode(categories[i].children);
- return text;
- }
- }
- }
-
- var checkForThatMatching = function(categoryChildNodes){
- for(var i = 0; i < categoryChildNodes.length; i++){
- if(categoryChildNodes[i].name === 'that'){
- //if the previous answer of the bot does not match the that-tag text, then return undefined!
- if(categoryChildNodes[i].children[0].text != previousAnswer){
- return false;
- }
- else{
- return true;
- }
- }
- }
- //if no that tag was found, everything 'fits'
- return true;
- }
-
- var resolveChildNodesInPatternNode = function(patternChildNodes){
- var text = '';
-
- for(var i = 0; i < patternChildNodes.length; i++){
- if(patternChildNodes[i].name === 'bot'){
- text = text + botAttributes[patternChildNodes[i].attributes.name];
- }
- else if(patternChildNodes[i].name === 'get'){
- text = text + storedVariableValues[patternChildNodes[i].attributes.name];
- }
- else if(patternChildNodes[i].name === 'set'){
- text = text + patternChildNodes[i].children[0].text;
- }
- else{
- text = text + patternChildNodes[i].text;
- }
- }
-
- return text;
- }
-
- var findFinalTextInTemplateNode = function(childNodesOfTemplate){
- var text = '';
-
- //traverse through template nodes until final text is found
- //return it then to very beginning
-
- for(var i = 0; i < childNodesOfTemplate.length; i++){
- if(childNodesOfTemplate[i].name === 'template'){
- //traverse as long through the dom until final text was found
- //final text -> text after special nodes (bot, get, set,...) were resolved
- return findFinalTextInTemplateNode(childNodesOfTemplate[i].children);
- }
- else if(childNodesOfTemplate[i].name === 'condition'){
- return resolveSpecialNodes(childNodesOfTemplate);
- }
- else if(childNodesOfTemplate[i].name === 'random'){
- //if random node was found, its children are 'li' nodes.
- return resolveSpecialNodes(childNodesOfTemplate);
- }
- else if(childNodesOfTemplate[i].name === 'srai'){
- //take pattern text of srai node to get answer of another category
- var sraiText = '' + findFinalTextInTemplateNode(childNodesOfTemplate[i].children);
- sraiText = sraiText.toUpperCase();
- var referredPatternText = sraiText;
- //call findCorrectCategory again to find the category that belongs to the srai node
- var text = findCorrectCategory(referredPatternText, domCategories);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'li'){
- return findFinalTextInTemplateNode(childNodesOfTemplate[i].children);
- }
- else if(childNodesOfTemplate[i].name === 'br'){
- //br elements are used for putting '\n' into the text
- return resolveSpecialNodes(childNodesOfTemplate);
- }
- else if(childNodesOfTemplate[i].name === 'pattern'){
- //(here it is already checked that this is the right pattern that matches the user input)
- //make use of the functions of the special nodes - bot, set, get...
- resolveSpecialNodes(childNodesOfTemplate[i].children);
- continue;
- }
- else if(childNodesOfTemplate[i].name === 'think'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'bot'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'set'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'get'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'sr'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'star'){
- text = resolveSpecialNodes(childNodesOfTemplate);
- return text;
- }
- else if(childNodesOfTemplate[i].name === 'that'){
-
- }
- else{
- //this is the text of template node
- //after all special functions (bot, get, set,...) were resolved
- //return that text
- text = resolveSpecialNodes(childNodesOfTemplate);
- if((text.match('[\\n|\\t]*[^A-Z|^a-z|^!|^?]*')[0] === '') && (text.indexOf('function ()') === -1)){
- return (text);
- }
- }
- }
- };
-
- var resolveSpecialNodes = function(innerNodes){
- var text = '';
- //concatenate string of all node children - normal text, bot tags, get tags, set tags...
- for(var i = 0; i < innerNodes.length; i++){
-
- if(innerNodes[i].name === 'bot'){
- //replace bot tags by the belonging bot attribute value
- text = text + botAttributes[innerNodes[i].attributes.name];
- }
- else if(innerNodes[i].name === 'get'){
- //replace get tag by belonging variable value
- var getAux = storedVariableValues[innerNodes[i].attributes.name];
- if(getAux === undefined){
- text = text + '';
- }else{
- text = text + getAux;
- }
- }
- else if(innerNodes[i].name === 'set'){
- //store value of set tag text into variable (variable name = attribute of set tag)
- //replace than set tag by the text value
- var aux='';
- if(innerNodes[i].children[0].name === 'star'){
- aux = resolveSpecialNodes(innerNodes[i].children);
- storedVariableValues[innerNodes[i].attributes.name] = aux;
- if(!previousThinkTag){
- text = text + aux;
- }
- }
- else if(innerNodes[i].children[0].text === '*'){
- //the first set-Tag with wildCard gets the first wildCardValue, the second set-Tag with wildCard gets the second wildCardValue etc.
- storedVariableValues[innerNodes[i].attributes.name] = wildCardArray[indexOfSetTagAmountWithWildCard];
- indexOfSetTagAmountWithWildCard++;
- }else{
- storedVariableValues[innerNodes[i].attributes.name] = innerNodes[i].children[0].text;
- }
-
- //If this set tag is a think tag's child
- if(previousThinkTag){
- previousThinkTag=false;
- text= text + '';
- }else{
- text = text + resolveSpecialNodes(innerNodes[i].children);
- }
- }
- else if(innerNodes[i].name === 'br'){
- text = text + '\n';
- }
- else if(innerNodes[i].name === 'think'){
- previousThinkTag=true;
- text = text + resolveSpecialNodes(innerNodes[i].children);
- }
- else if(innerNodes[i].name === 'sr'){
- var result;
-
- //for-loop to go through all loaded AIML files
- for(var j = 0; j < domArray.length; j++){
- result = findCorrectCategory(lastWildCardValue, domArray[j].children);
- //if in one of the dom trees a matching pattern was found, exit this inner loop
- if(result){
- text = text + result;
- break;
- }
- }
- }
- else if(innerNodes[i].name === 'random'){
- //Get a random number and find the li tag chosen
- var randomNumber = Math.floor(Math.random() * (innerNodes[i].children.length));
- text = text + findFinalTextInTemplateNode([innerNodes[i].children[randomNumber]]);
- ;
- }
- else if(innerNodes[i].name === 'star'){
- text = text + lastWildCardValue;
- }
- else if(innerNodes[i].name === 'srai'){
- //take pattern text of srai node to get answer of another category
- var sraiText = '' + findFinalTextInTemplateNode(innerNodes[i].children);
- sraiText = sraiText.toUpperCase();
- var referredPatternText = sraiText;
- //call findCorrectCategory again to find the category that belongs to the srai node
- text = text + findCorrectCategory(referredPatternText, domCategories);
- }
- else if(innerNodes[i].name === 'condition') {
- // condition tag specification: list condition tag
- if(innerNodes[i].attributes.name === undefined){
- if(innerNodes[i].children === undefined){
- return undefined;
- }
- var child;
- for(var c in innerNodes[i].children){
- child = innerNodes[i].children[c];
- if(child.name === 'li'){
- if(child.attributes.value == undefined
- || storedVariableValues[child.attributes.name] === child.attributes.value.toUpperCase()){
- return findFinalTextInTemplateNode(child.children);
- }
- }
- }
- }
- // condition tag specification: multi condition tag
- else if(innerNodes[i].attributes.value !== undefined){
- if (storedVariableValues[innerNodes[i].attributes.name] === innerNodes[i].attributes.value.toUpperCase()) {
- text = text + resolveSpecialNodes(innerNodes[i].children);
- }
- }
- // condition tag specification: single name list condition tags
- else if(innerNodes[i].children !== undefined){
- var child;
- for(var c in innerNodes[i].children){
- child = innerNodes[i].children[c];
- if(child.name === 'li'){
- if(child.attributes.value === undefined
- || storedVariableValues[innerNodes[i].attributes.name] === child.attributes.value.toUpperCase()){
- return resolveSpecialNodes(child.children);
- }
- }
- }
-
- return undefined;
- }
- }
- else if(innerNodes[i].name === undefined){
- //normal text (no special tag)
- text = text + innerNodes[i].text;
- }
- }
-
- text = cleanStringFormatCharacters(text);
- return text;
- }
-
- return travereseThroughDomToFindMatchingPattern(domCategories);
- }
-
- var checkIfMessageMatchesPattern = function(userInput, patternText){
- //convert wildcards in of the pattern node into a regex that matches every char
- var regexPattern = convertWildcardToRegex(patternText);
-
- //add one with the text in function 'convertWildcardToRegex' here a space is added before and after the user input
- //to prevent false matching
- if(userInput.charAt(0) != " "){
- userInput = " " + userInput;
- }
-
- var lastCharacterPosition = userInput.length - 1;
- var lastCharacter = userInput.charAt(lastCharacterPosition);
- if(lastCharacter != " "){
- userInput = userInput + " ";
- }
-
- //match userInput with the regex pattern
- //if it matches, matchedString is defined
- var matchedString = userInput.toUpperCase().match(regexPattern);
-
- if(matchedString){
- //the matched pattern must be at least as long as the user input or must contain the regex
- if(matchedString[0].length >= userInput.length || regexPattern.indexOf('[A-Z|0-9|\\s]*[A-Z|0-9|-]*[A-Z|0-9]*[!|.|?|\\s]*') > -1){
- //if patternText contained a wild card, get the user input that were put into this wild card
- //use original patternText (* is not replaced by regex!)
- var information = getWildCardValue(userInput, patternText);
-
- return true;
- }
- }
- else{
- return false;
- }
- }
-
- var convertWildcardToRegex = function(text){
- var firstCharacter = text.charAt(0);
- //add a space before and after the pattern text (THIS IS LATER ALSO DONE FOR THE USER INPUT)
- //prevents false matchings
- //e.g. (HI as regex also matches HIM or HISTORY, but <space>HI</space> does only match <space>HI</space>)
- if(firstCharacter != "*"){
- var text = " " + text;
- }
- var lastCharacterPosition = text.length - 1;
- var lastCharacter = text.charAt(lastCharacterPosition);
-
- //replace space before wildcard
- var modifiedText = text.replace(' *', '*');
- //replace wildcard (*) by regex
- modifiedText = modifiedText.replace(/\*/g, '[A-Z|0-9|\\s]*[A-Z|0-9|\*|-]*[A-Z|0-9]*[!|.|?|\\s]*');
-
- if(lastCharacter != "*"){
- // text = text + " ";
- //pattern should also match when user inputs ends with a space, ?, ! or .
- modifiedText = modifiedText + '[\\s|?|!|.]*';
- }
-
- return modifiedText;
- }
-
- var getWildCardValue = function(userInput, patternText){
- //get all strings of the pattern that are divided by a *
- //e.g. WHAT IS THE RELATION BETWEEN * AND * -> [WHAT IS THE RELATION BETWEEN , AND ]
- var replaceArray = patternText.split('*');
- var wildCardInput = userInput;
-
- if(replaceArray.length > 1){
- //replace the string of the userInput which is fixed by the pattern
- for(var i = 0; i < replaceArray.length; i++){
- wildCardInput = wildCardInput.replace(new RegExp(replaceArray[i], 'i'), '|');
- }
- //split the wildCardInput string by | to differentiate multiple * inputs
- //e.g. userInput = WHAT IS THE RELATION BETWEEN TIM AND STRUPPI?
- //-> | TIM | STRUPPI
- //-> [TIM, STRUPPI]
- wildCardInput = wildCardInput.split('|');
- //split function can create an array which also includes spaces etc. -> e.g. [TIM, " ", "", STRUPPI, " "]
- //we just want the information
- var wildCardArrayIndex = 0;
- for(var i = 0; i < wildCardInput.length; i++){
- if(wildCardInput[i] != '' && wildCardInput[i] != ' ' && wildCardInput != undefined){
- var wildCard = wildCardInput[i];
- var wildCardLastCharIndex = wildCard.length - 1;
- var firstCharOfWildCard = wildCard.charAt(0);
- var lastCharOfWildCard = wildCard.charAt(wildCardLastCharIndex);
-
- try{
- //harmonize the wildcard string
- //remove first char if it is a space.
- //calculate the last index again since the length of the string changed
- if(firstCharOfWildCard === ' '){
- wildCard = wildCard.splice(0);
- wildCardLastCharIndex = wildCard.length - 1;
- lastCharOfWildCard = wildCard.charAt(wildCardLastCharIndex);
- }
- //if the last char is a space, remove it
- //calculate the last index again since the length of the string changed
- if(lastCharOfWildCard === ' '){
- wildCard = wildCard.substr(0, wildCardLastCharIndex);
- wildCardLastCharIndex = wildCard.length - 1;
- lastCharOfWildCard = wildCard.charAt(wildCardLastCharIndex);
- }
- if(lastCharOfWildCard === '?'){
- wildCard = wildCard.substr(0, wildCardLastCharIndex);
- }
- }
- catch(e){
-
- }
- wildCardArray[wildCardArrayIndex] = wildCard;
- wildCardArrayIndex++;
- }
- }
- }
- if(wildCardArray.length - 1 >= 0){
- lastWildCardValue = wildCardArray[wildCardArray.length - 1];
- }
-
- return wildCardArray;
- }
-
-
|