function SuperScript(options, callback) { EventEmitter.call(this); var mongoose; var self = this; options = options || {}; // Create a new connection if non is provided. if (options.mongoose) { mongoose = options.mongoose; } else { mongoose = require("mongoose"); mongoose.connect("mongodb://localhost/superscriptDB"); } this._plugins = []; this.normalize = null; this.question = null; // this is to turn off/on global sentence splitting / chunking if(options.chunking || options.chunking === false) { this.chunking = options.chunking; } else { this.chunking = true; } Utils.mkdirSync("./plugins"); this.loadPlugins("./plugins"); this.loadPlugins(process.cwd() + "/plugins"); // this.intervalId = setInterval(this.check.bind(this), 500); this.factSystem = options.factSystem ? options.factSystem : facts.create("systemDB"); this.topicSystem = gTopicsSystem(mongoose, this.factSystem); // This is a kill switch for filterBySeen which is useless in the editor. this.editMode = options.editMode || false; // We want a place to store bot related data this.memory = options.botfacts ? options.botfacts : this.factSystem.createUserDB("botfacts"); this.scope = {}; this.scope = _.extend(options.scope || {}); this.scope.bot = this; this.scope.facts = this.factSystem; this.scope.topicSystem = this.topicSystem; this.scope.botfacts = this.memory; this.users = new Users(mongoose, this.factSystem); norm.loadData(function () { self.normalize = norm; new qtypes(function (question) { self.question = question; debug.verbose("System Loaded, waiting for replies"); callback(null, self); }); }); }
before(function(done){ norm.loadData(function(){ // Why didn't I pass this back in the CB?!? normalize = norm; new qtypes(function(question) { questions = question; Concepts.readFiles(data, function(facts) { concept = facts; done(); }); }); }); });
Utils.walk(path, function (err, files) { if (err) { console.error(err); } norm.loadData(function () { var sums = {}; var itor = function (file, next) { if (file.match(/\.(ss)$/i)) { checksum.file(file, function (err4, sum) { if (err4) { console.error(err4); } sums[file] = sum; if (cache[file]) { if (cache[file] !== sum) { next(true); } else { next(false); } } else { next(true); } }); } else { next(false); } }; async.filter(files, itor, function (toLoad) { async.map(toLoad, parseFiles(factSystem), function (err4, res) { if (err4) { console.log(err4); } for (var i = 0; i < res.length; i++) { topics = mergex(topics, res[i].topics); gambits = mergex(gambits, res[i].gambits); convos = mergex(convos, res[i].convos); replys = mergex(replys, res[i].replys); } var data = { topics: topics, gambits: gambits, convos: convos, replys: replys, checksums: sums }; var endTime = new Date().getTime(); var topicCount = Object.keys(topics).length; var gambitsCount = Object.keys(gambits).length; var convoCount = Object.keys(convos).length; var replysCount = Object.keys(replys).length; console.log("Time to Process", (endTime - startTime) / 1000, "seconds"); console.log("Number of topics %s parsed.", topicCount); console.log("Number of gambits %s parsed.", gambitsCount); console.log("Number of replies %s parsed.", replysCount); console.log("Number of convos %s parsed.", convoCount); if (data !== "") { if (topicCount === 0 && triggerCount === 0 && replyCount === 0) { callback(null, {}); } else { // console.log(JSON.stringify(data, null, 2)); callback(null, data); } } else { callback(new Error("No data")); } }); }); }); });
module.exports = function(mongoose, facts) { var Utils = require("../utils"); var regexreply = require("../parse/regexreply"); var debug = require("debug")("Gambit"); var norm = require("node-normalizer"); var _ = require("underscore"); var findOrCreate = require('mongoose-findorcreate'); var gNormalizer; norm.loadData(function() { gNormalizer = norm; debug("Normaizer Loaded."); }); /** I trigger is the matching rule behind a piece of input. It lives in a topic or several topics. A trigger also contains one or more replies. **/ var gambitSchema = new mongoose.Schema({ id: {type: String, index: true, default: Utils.genId()}, // This is the input string that generates a rule, // In the event we want to export this, we will use this value. // Make this filed conditionally required if trigger is supplied input: { type: String }, // The Trigger is a partly baked regex. trigger: {type: String, index: true}, // If the trigger is a Question Match isQuestion: {type: Boolean, default: false}, // If the trigger is a Answer Type Match qType: {type: String, default: ""}, qSubType: {type: String, default: ""}, // The filter function for the the expression filter: {type: String, default: ""}, // An array of replies. replies: [{ type: String, ref: 'Reply' }], // replies: [Reply.schema], // This will redirect anything that matches elsewhere. // If you want to have a conditional rediect use reply redirects // TODO, change the type to a ID and reference another gambit directly // this will save us a lookup down the road (and improve performace.) redirect: {type: String, default: ""} }); gambitSchema.pre('save', function (next) { var that = this; // FIXME: This only works when the replies are populated which is not always the case. // that.replies = _.uniq(that.replies, function(item, key, id) { // return item.id; // }); // If input was supplied, we want to use it to generate the trigger if (that.input) { var input = gNormalizer.clean(that.input); // We want to convert the input into a trigger. regexreply.parse(input, facts, function(trigger) { that.trigger = trigger; next(); }); } else { // Otherwise we populate the trigger normally next(); } }); gambitSchema.methods.addReply = function(replyData, callback) { if (!replyData) return callback("No data"); var gambit = this; var reply = new Reply(replyData); var topic = this; reply.save(function(err){ if (err) return callback(err); gambit.replies.addToSet(reply._id); gambit.save(function(err){ callback(err, reply); }); }); }; // TODO - Test against Qtypes too. gambitSchema.methods.doesMatch = function(message, cb) { var that = this; var match = false; regexreply.postParse(this.trigger, message, null, function(regexp) { var compiledRE = new RegExp('^' + regexp + '$', "i"); debug("Try to match (clean)'" + message.clean + "' against " + that.trigger + " (" + regexp + ")"); debug("Try to match (lemma)'" + message.lemString + "' against " + that.trigger + " (" + regexp + ")"); match = message.clean.match(compiledRE); if (!match) match = message.lemString.match(compiledRE); cb(null, match); }); }; gambitSchema.plugin(findOrCreate); try { return mongoose.model('Gambit', gambitSchema); } catch(e) { return mongoose.model('Gambit'); } };