/* Michael Murtaugh Following Charles Hayden's 1990's interpretation implemented in Java (C) 2018 and released under the Free Art License 1.3 See LICENSE.txt and http://artlibre.org/licence/lal/en/ Use the accompanying eliza_script_to_json.py to prepare the rules in JSON format */ function chatbot (rules, debug) { var saved_statements = []; function process_rules (rules) { // transfrom / pre-process the rules function looping_iterator (l) { var next = function () { var ret = l[next.i]; if (++next.i >= l.length) { next.i = 0 }; return ret; }; next.length = l.length; next.i = 0; next.items = l; return next; } // index pre + post and tokenize results function _index (name) { var new_value = {}; rules[name].forEach(function (x) { var words = tokenize(x), word = words.shift(); new_value[word] = words; }) rules[name] = new_value; } _index("pre"); _index("post"); // index synonmys by first word var new_synon = {}; rules.synon.forEach(function (x) { var words = tokenize(x); new_synon[words[0]] = words; }) rules.synon = new_synon; // index keywords by name rules.keywords_by_token = {}; rules.keywords.forEach(function (x) { rules.keywords_by_token[x.token] = x; x.rules.forEach(function (r) { // ensure list if (!Array.isArray(r.reasmb)) { r.reasmb = [r.reasmb]; } // wrap the reasmb list in a looping iterator that perserves its state r.reasmb = looping_iterator(r.reasmb); }); }); } // function trim (text) { return text.replace(/\s+$/, "").replace(/\s+/, ""); } function trimword (text) { return text .replace(/[^a-zA-Zéèàöùç]+$/, "") .replace(/^[^a-zA-Zéèàöùç]+/, ""); } function tokenize (text) { return (trimword(text).split(/\s+/).map(trimword)); } // used for both pre + post subs function sub (tokens, subst) { for (var i=0, l=tokens.length; i i(cannot|cant|...)(.+) // * i* @belief *you * ==> (belief|feel|think|believe|wish) // * i @belief i * var ret = pattern .replace(/ *\* */g, "*") // compact spaces around stars .replace(/\*/g, "(.*?)") .replace(/@(\w+)/, function (match, word) { var syn = rules.synon[word.toLowerCase()]; if (syn) { return "("+syn.join("|")+")"; } else { console.log("Missing @synonym", word); return match; } }); return "^"+ret+"$"; } function match_decomp (pattern, tokens) { var ppat = compile_pattern(pattern); if (debug) { console.log("compile_pattern.in", pattern); console.log("compile_pattern.out", ppat); } var ppat = new RegExp(ppat, "i"); return ppat.exec(tokens.join(" ")); } function do_post (txt) { var tokens = tokenize(txt); tokens = sub(tokens, rules.post); return tokens.join(" "); } function do_reasmb (reasmb, match, tokens) { if (Array.isArray(match)) { return reasmb.replace(/\((\d+)\)/, function (m, n) { return do_post(match[parseInt(n)]); // apply POST substitutions here to matching input }); } else { return reasmb; } } function apply_keywords (keywords, tokens) { for (var i=0, l=keywords.length; i 0)) { if (debug) { console.log("using saved statement"); } return saved_statements.shift(); } var loop = true; while (loop) { loop = false; if (debug) { console.log("trying keyword", keyword.token); } for (var ri=0, rl = keyword.rules.length; ri