UNPKG

eliza-core

Version:

A rendition of ELIZA program engine by Weizenbaum sharable for all javascript environments

410 lines (409 loc) 17.4 kB
import * as tslib_1 from "tslib"; import { of, concat } from 'rxjs'; import { scan, tap, concatMap, filter } from 'rxjs/operators'; import { Decomp } from './decompo'; import { Reassemble } from './Reassemble'; import * as estring from './estring'; import * as mention from './mention-router'; import { Key } from './key'; import { GotoKey } from './key-goto'; import { buildKeyStack } from './key-stack'; import * as PrePostUtil from './pre-post-utils'; import * as printers from './printers'; import { notEmpty } from './utils'; import { UnexpectedNumberException, UnknownRuleException, GotoLostException, ScriptInterpretingError, DuplicateAnnotateException, InvalidStringException, } from './exceptions'; var printSynonyms = true; var printKeys = true; var PRINT_PRE_POST = true; var PRINT_INITIAL_FINAL = true; export function loadEliza(script$, keyFilter) { return tslib_1.__awaiter(this, void 0, void 0, function () { var eliza; return tslib_1.__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]; } }); }); } export function loadElizaInEnglish(script$) { return tslib_1.__awaiter(this, void 0, void 0, function () { var eliza; return tslib_1.__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]; } }); }); } 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 ScriptInterpretingError('A Reasmb rule missing decomp rule'); } _this.lastReasemb.push(new 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 ScriptInterpretingError('A Decomp rule missing Key Initialization'); } _this.lastReasemb = []; var temp = matchedParts[1]; var newMatch = estring.match(temp, '$ *'); _this.lastDecomp.push(new 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 UnexpectedNumberException(matchedParts[2], 'key'); } } _this.keys.push(new 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(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 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 ScriptInterpretingError('An annotated Reasmb rule missing decomp rule'); } _this.lastReasemb.push(new 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 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 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 concat(script$, of('\n')).pipe(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: [''] }), concatMap(function (pack) { return pack.lines; }), filter(function (line) { return line.trim().length > 0 && !line.startsWith('%'); }), 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 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(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(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 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 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 GotoKey(gotoKey); } throw new 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; }());