eliza-core
Version:
A rendition of ELIZA program engine by Weizenbaum sharable for all javascript environments
455 lines (454 loc) • 20.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var rxjs_1 = require("rxjs");
var operators_1 = require("rxjs/operators");
var decompo_1 = require("./decompo");
var Reassemble_1 = require("./Reassemble");
var estring = __importStar(require("./estring"));
var mention = __importStar(require("./mention-router"));
var key_1 = require("./key");
var key_goto_1 = require("./key-goto");
var key_stack_1 = require("./key-stack");
var PrePostUtil = __importStar(require("./pre-post-utils"));
var printers = __importStar(require("./printers"));
var utils_1 = require("./utils");
var exceptions_1 = require("./exceptions");
var printSynonyms = true;
var printKeys = true;
var PRINT_PRE_POST = true;
var PRINT_INITIAL_FINAL = true;
function loadEliza(script$, keyFilter) {
return __awaiter(this, void 0, void 0, function () {
var eliza;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
eliza = new ElizaImpl(keyFilter || (function (key) { return true; }));
return [4, eliza.readScript(script$).toPromise()];
case 1:
_a.sent();
return [2, eliza];
}
});
});
}
exports.loadEliza = loadEliza;
function loadElizaInEnglish(script$) {
return __awaiter(this, void 0, void 0, function () {
var eliza;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
eliza = new ElizaImpl(function (key) { return true; }, function (sentence) { return sentence.split(' '); });
return [4, eliza.readScript(script$).toPromise()];
case 1:
_a.sent();
return [2, eliza];
}
});
});
}
exports.loadElizaInEnglish = loadElizaInEnglish;
var ElizaImpl = (function () {
function ElizaImpl(keyFilter, tokenizer) {
this.keyFilter = keyFilter;
this.tokenizer = tokenizer;
this.mem = [];
this.keys = [];
this.synonyms = [];
this.preList = [];
this.postList = [];
this.annotates = [];
this.tweakList = [];
this.initialStr = 'Hello.';
this.finalStr = 'Goodbye.';
this.quitList = [];
this.lastDecomp = [];
this.lastReasemb = [];
this.finished = false;
}
ElizaImpl.prototype.getInitialStr = function () {
return this.initialStr;
};
ElizaImpl.prototype.isFinished = function () {
return this.finished;
};
ElizaImpl.prototype.collect = function (s) {
var _this = this;
var matchedPattern = [
{
tryMatch: function (testStr) { return estring.match(testStr, '*reasmb: *'); },
onMatched: function (matchedParts) {
if (!_this.lastReasemb) {
throw new exceptions_1.ScriptInterpretingError('A Reasmb rule missing decomp rule');
}
_this.lastReasemb.push(new Reassemble_1.Reassemble(matchedParts[1], _this.lastDecomp[_this.lastDecomp.length - 1]));
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*decomp: *'); },
onMatched: function (matchedParts) {
if (!_this.lastDecomp) {
throw new exceptions_1.ScriptInterpretingError('A Decomp rule missing Key Initialization');
}
_this.lastReasemb = [];
var temp = matchedParts[1];
var newMatch = estring.match(temp, '$ *');
_this.lastDecomp.push(new decompo_1.Decomp(newMatch ? newMatch[0] : temp, newMatch ? true : false, _this.lastReasemb));
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*key: * #*'); },
onMatched: function (matchedParts) {
_this.lastDecomp = [];
_this.lastReasemb = null;
var n = 0;
if (matchedParts[2].length > 0) {
n = parseInt(matchedParts[2], 10);
if (isNaN(n)) {
throw new exceptions_1.UnexpectedNumberException(matchedParts[2], 'key');
}
}
_this.keys.push(new key_1.Key(matchedParts[1], n, _this.lastDecomp));
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*key: *'); },
onMatched: function (matchedParts) {
_this.lastDecomp = [];
_this.lastReasemb = null;
_this.keys.push(new key_1.Key(matchedParts[1], 0, _this.lastDecomp));
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*mention: *@* *'); },
onMatched: function (matchedParts) {
var words = JSON.parse("[" + matchedParts[3] + "]");
_this.synonyms.push({
tag: matchedParts[2],
words: words.slice(1),
});
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*annotate: *'); },
onMatched: function (matchedParts) {
var tag = matchedParts[1].trim();
if (tag.length < 1 || _this.annotates.find(function (w) { return w === tag; })) {
throw new exceptions_1.DuplicateAnnotateException(tag);
}
_this.annotates.push(tag);
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*pre: * => *'); },
onMatched: function (matchedParts) {
_this.preList.push({ src: JSON.parse(matchedParts[1]), dest: JSON.parse(matchedParts[2]) });
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*post: * => *'); },
onMatched: function (matchedParts) {
_this.postList.push({ src: JSON.parse(matchedParts[1]), dest: JSON.parse(matchedParts[2]) });
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*tweak: * => *'); },
onMatched: function (matchedParts) {
_this.tweakList.push({ src: JSON.parse(matchedParts[1]), dest: JSON.parse(matchedParts[2]) });
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*initial: *'); },
onMatched: function (matchedParts) {
_this.initialStr = matchedParts[1];
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*final: *'); },
onMatched: function (matchedParts) {
_this.finalStr = matchedParts[1];
},
},
{
tryMatch: function (testStr) { return estring.match(testStr, '*quit: *'); },
onMatched: function (matchedParts) {
_this.quitList.push(" " + matchedParts[1] + " ");
},
},
{
tryMatch: function (testStr) {
var parts = estring.match(testStr, '*: *');
if (parts && _this.annotates.indexOf(estring.trim(parts[0])) > -1) {
return parts;
}
return null;
},
onMatched: function (matchedParts) {
var instruction = estring.trim(matchedParts[0]);
if (!_this.lastReasemb) {
throw new exceptions_1.ScriptInterpretingError('An annotated Reasmb rule missing decomp rule');
}
_this.lastReasemb.push(new Reassemble_1.Reassemble(matchedParts[1], _this.lastDecomp[_this.lastDecomp.length - 1], instruction));
},
},
].find(function (_a) {
var tryMatch = _a.tryMatch, onMatched = _a.onMatched;
var matchedParts = tryMatch(s);
if (matchedParts) {
onMatched(matchedParts);
return true;
}
return false;
});
if (!matchedPattern) {
throw new exceptions_1.UnknownRuleException(s);
}
};
ElizaImpl.prototype.toJson = function () {
var toPrint = {};
if (printKeys) {
toPrint.keys = this.keys.map(function (k) { return printers.snapshotKey(k); });
}
if (printSynonyms) {
toPrint.mentionRoutes = this.synonyms;
}
if (PRINT_PRE_POST) {
toPrint.preList = this.preList;
toPrint.postList = this.postList;
}
if (PRINT_INITIAL_FINAL) {
toPrint.initial = this.initialStr;
toPrint.final = this.finalStr;
toPrint.quitList = this.quitList.join(' ');
}
return toPrint;
};
ElizaImpl.prototype.processHyperInput = function (s) {
var matchedParts = estring.match(s, '*.*');
while (matchedParts) {
var reply = this.sentence(matchedParts[0]);
if (reply) {
return reply;
}
s = estring.trim(matchedParts[1]);
matchedParts = estring.match(s, '*.*');
}
if (s.length > 0) {
var reply = this.sentence(s);
if (reply) {
return reply;
}
}
var m = this.mem.shift();
if (m) {
return { assembled: { reassembled: m } };
}
var key = this.keys.find(function (k) { return k.getKey() === 'xnone'; });
if (key) {
var context = this.fullyDecompose(key, s);
if (context && context.assembled) {
return context;
}
}
return null;
};
ElizaImpl.prototype.processInput = function (s) {
if (typeof s !== 'string') {
throw new exceptions_1.InvalidStringException(s);
}
s = estring.replaceAll(s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
s = estring.replaceAll(s, '@#$%^&*()_-+=~`{[}]|:;<>\\"', ' ');
s = estring.replaceAll(s, ',?!', '...');
s = estring.compress(s);
return this.processHyperInput(s);
};
ElizaImpl.prototype.readScript = function (script$) {
var _this = this;
return rxjs_1.concat(script$, rxjs_1.of('\n')).pipe(operators_1.scan(function (_a, chunk) {
var buffer = _a.buffer;
var split = (buffer + chunk).split('\n');
var rest = split.pop();
return { buffer: rest || '', lines: split };
}, { buffer: '', lines: [''] }), operators_1.concatMap(function (pack) { return pack.lines; }), operators_1.filter(function (line) { return line.trim().length > 0 && !line.startsWith('%'); }), operators_1.tap(function (line) { return _this.collect(line); }));
};
ElizaImpl.prototype.sentence = function (s) {
var _this = this;
s = PrePostUtil.translate(this.preList, s).trim();
s = estring.pad(s);
if (this.quitList.indexOf(s) >= 0) {
this.finished = true;
return { assembled: { reassembled: this.finalStr } };
}
if (this.tokenizer) {
var result_1 = null;
return key_stack_1.buildKeyStack(this.keys.filter(function (k) { return _this.keyFilter(k.getKey()); }), this.tokenizer(s))
.find(function (key) {
var ctx = _this.fullyDecompose(key, s);
if (ctx) {
result_1 = ctx;
return true;
}
return false;
}) ? result_1 : null;
}
var sortedReplyContexts = this.keys.filter(function (k) { return _this.keyFilter(k.getKey()); })
.map(function (key) { return _this.fullyDecompose(key, s); })
.filter(utils_1.notEmpty).sort(function (ctxA, ctxB) {
return (ctxA.matches ||
{ slottedTokens: [{ token: s, scopes: {} }] })
.slottedTokens.filter(function (t) { return Object.keys(t.scopes).length < 1; })
.map(function (t) { return t.token; }).join('').length
- (ctxB.matches ||
{ slottedTokens: [{ token: s, scopes: {} }] })
.slottedTokens.filter(function (t) { return Object.keys(t.scopes).length < 1; })
.map(function (t) { return t.token; }).join('').length;
});
return sortedReplyContexts[0] || null;
};
ElizaImpl.prototype.decompose = function (key, s) {
var _this = this;
var ASSEMBLE_FUNC = this.assemble;
return (key.getDecomp() || []).map(function (decomposition) {
var matches = mention.matchDecomposition(_this.synonyms, s, decomposition.getPattern());
if (!matches) {
return null;
}
return {
decomposition: decomposition, matches: matches,
assembled: null,
};
}).filter(utils_1.notEmpty).sort(function (ctxA, ctxB) {
return (ctxA.matches ||
{ slottedTokens: [{ token: s, scopes: {} }] })
.slottedTokens.filter(function (t) { return Object.keys(t.scopes).length < 1; })
.map(function (t) { return t.token; }).join('').length
- (ctxB.matches ||
{ slottedTokens: [{ token: s, scopes: {} }] })
.slottedTokens.filter(function (t) { return Object.keys(t.scopes).length < 1; })
.map(function (t) { return t.token; }).join('').length;
})
.find(function (ctx) {
ctx.assembled = _this.assemble(ctx.decomposition, ctx.matches.slottedTokens);
if (!ctx.assembled) {
return false;
}
if (ctx.assembled instanceof key_goto_1.GotoKey) {
if (ctx.assembled.getKey()) {
return true;
}
}
else {
return true;
}
return false;
}) || null;
};
ElizaImpl.prototype.fullyDecompose = function (key, s) {
var _this = this;
var decomposeCtx = this.decompose(key, s);
var _loop_1 = function () {
if (decomposeCtx.assembled instanceof key_goto_1.GotoKey) {
var gotoKey = decomposeCtx.assembled;
decomposeCtx = this_1.decompose(gotoKey, s);
return "continue";
}
if (!decomposeCtx.assembled) {
return { value: null };
}
var assembledResult = decomposeCtx.assembled;
assembledResult.reassembled = PrePostUtil
.translate(this_1.tweakList, assembledResult.reassembled);
Object.keys(assembledResult.annotations).forEach(function (k) {
assembledResult.annotations[k] = PrePostUtil
.translate(_this.tweakList, assembledResult.annotations[k]);
});
return { value: {
decomposition: decomposeCtx.decomposition,
matches: decomposeCtx.matches,
assembled: assembledResult,
} };
};
var this_1 = this;
while (decomposeCtx) {
var state_1 = _loop_1();
if (typeof state_1 === "object")
return state_1.value;
}
return null;
};
ElizaImpl.prototype.assemble = function (d, decomposedSlots) {
var _this = this;
var decomposedTokens = decomposedSlots.map(function (s) { return s.token; });
var rule = d.nextRule();
var assembledResult = rule.assemble(decomposedTokens.map(function (token) { return PrePostUtil.translate(_this.postList, token).trim(); }));
if (assembledResult.gotoKey && assembledResult.gotoKey.length > 0) {
var gotoKey = this.keys.find(function (k) { return k.getKey() === assembledResult.gotoKey; });
if (gotoKey && gotoKey.getKey()) {
return new key_goto_1.GotoKey(gotoKey);
}
throw new exceptions_1.GotoLostException(rule.getTemplate());
}
if (!assembledResult.result) {
return null;
}
if (d.isMemoryKey()) {
this.mem.push(assembledResult.result);
return null;
}
return {
reassembled: assembledResult.result,
annotations: d.getAnnotates()
.map(function (annotate) { return annotate.assemble(decomposedTokens); })
.reduce(function (reduced, current) {
if (current.annotation) {
reduced[current.annotation] = current.result + '';
}
return reduced;
}, {}),
};
};
return ElizaImpl;
}());