UNPKG

speech-rule-engine

Version:

A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.

405 lines 16.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.process = process; exports.output = output; exports.keypress = keypress; exports.assembleSpeechStructure = assembleSpeechStructure; const AuralRendering = __importStar(require("../audio/aural_rendering.js")); const Enrich = __importStar(require("../enrich_mathml/enrich.js")); const HighlighterFactory = __importStar(require("../highlighter/highlighter_factory.js")); const locale_js_1 = require("../l10n/locale.js"); const Semantic = __importStar(require("../semantic_tree/semantic.js")); const SpeechGeneratorFactory = __importStar(require("../speech_generator/speech_generator_factory.js")); const SpeechGeneratorUtil = __importStar(require("../speech_generator/speech_generator_util.js")); const WalkerFactory = __importStar(require("../walker/walker_factory.js")); const WalkerUtil = __importStar(require("../walker/walker_util.js")); const rebuild_stree_js_1 = require("../walker/rebuild_stree.js"); const DomUtil = __importStar(require("./dom_util.js")); const engine_js_1 = require("./engine.js"); const EngineConst = __importStar(require("../common/engine_const.js")); const processor_js_1 = require("./processor.js"); const XpathUtil = __importStar(require("./xpath_util.js")); const semantic_skeleton_js_1 = require("../semantic_tree/semantic_skeleton.js"); const PROCESSORS = new Map(); function set(processor) { PROCESSORS.set(processor.name, processor); } function get(name) { const processor = PROCESSORS.get(name); if (!processor) { throw new engine_js_1.SREError('Unknown processor ' + name); } return processor; } function process(name, expr) { const processor = get(name); try { return processor.processor(expr); } catch (error) { if (error instanceof engine_js_1.SREError) { throw error; } throw new engine_js_1.SREError(`Processing error for expression\n ${expr}`); } } function print(name, data) { const processor = get(name); return engine_js_1.Engine.getInstance().options.pprint ? processor.pprint(data) : processor.print(data); } function output(name, expr) { const processor = get(name); try { const data = processor.processor(expr); return engine_js_1.Engine.getInstance().options.pprint ? processor.pprint(data) : processor.print(data); } catch (error) { if (error instanceof engine_js_1.SREError) { throw error; } throw new engine_js_1.SREError(`Processing error for expression\n ${expr}`); } } function keypress(name, expr) { const processor = get(name); const key = processor instanceof processor_js_1.KeyProcessor ? processor.key(expr) : expr; const data = processor.processor(key); return engine_js_1.Engine.getInstance().options.pprint ? processor.pprint(data) : processor.print(data); } set(new processor_js_1.Processor('semantic', { processor: function (expr) { const mml = DomUtil.parseInput(expr); return Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); }, postprocessor: function (xml, _expr) { const setting = engine_js_1.Engine.getInstance().options.speech; if (setting === EngineConst.Speech.NONE) { return xml; } const clone = DomUtil.cloneNode(xml); let speech = SpeechGeneratorUtil.computeMarkup(clone, true); if (setting === EngineConst.Speech.SHALLOW) { xml.setAttribute('speech', AuralRendering.finalize(speech)); return xml; } const nodesXml = XpathUtil.evalXPath('.//*[@id]', xml); const nodesClone = XpathUtil.evalXPath('.//*[@id]', clone); for (let i = 0, orig, node; (orig = nodesXml[i]), (node = nodesClone[i]); i++) { speech = SpeechGeneratorUtil.computeMarkup(node); orig.setAttribute('speech', AuralRendering.finalize(speech)); } return xml; }, pprint: function (tree) { return DomUtil.formatXml(tree.toString()); } })); set(new processor_js_1.Processor('speech', { processor: function (expr) { const mml = DomUtil.parseInput(expr); const xml = Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); const descrs = SpeechGeneratorUtil.computeSpeech(xml, true); return AuralRendering.finalize(AuralRendering.markup(descrs)); }, pprint: function (speech) { const str = speech.toString(); return AuralRendering.isXml() ? DomUtil.formatXml(str) : str; } })); set(new processor_js_1.Processor('json', { processor: function (expr) { const mml = DomUtil.parseInput(expr); const stree = Semantic.getTree(mml, engine_js_1.Engine.getInstance().options); return stree.toJson(); }, postprocessor: function (json, expr) { const setting = engine_js_1.Engine.getInstance().options.speech; if (setting === EngineConst.Speech.NONE) { return json; } const mml = DomUtil.parseInput(expr); const xml = Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); const speech = SpeechGeneratorUtil.computeMarkup(xml); if (setting === EngineConst.Speech.SHALLOW) { json.stree.speech = AuralRendering.finalize(speech); return json; } const addRec = (json) => { const node = XpathUtil.evalXPath(`.//*[@id=${json.id}]`, xml)[0]; const speech = SpeechGeneratorUtil.computeMarkup(node); json.speech = AuralRendering.finalize(speech); if (json.children) { json.children.forEach(addRec); } }; addRec(json.stree); return json; }, print: function (json) { return JSON.stringify(json); }, pprint: function (json) { return JSON.stringify(json, null, 2); } })); set(new processor_js_1.Processor('vis', { processor: function (expr) { const mml = DomUtil.parseInput(expr); const stree = Semantic.getTree(mml, engine_js_1.Engine.getInstance().options); const json = stree.toJson(); json.stree = rewriteJson(json.stree); return json; }, print: function (json) { return JSON.stringify(json); }, pprint: function (json) { return JSON.stringify(json, null, 2); } })); function rewriteJson(node) { if (!node.children) { return node; } if (node.children) { node.children.forEach((node) => node.child = true); } if (node.content) { node.content.forEach((node) => node.cont = true); } node.children = semantic_skeleton_js_1.SemanticSkeleton.combineContentChildren(node.type, node.role, node.content || [], node.children || []); node.children.forEach((node) => rewriteJson(node)); return node; } set(new processor_js_1.Processor('description', { processor: function (expr) { const mml = DomUtil.parseInput(expr); const xml = Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); const descrs = SpeechGeneratorUtil.computeSpeech(xml, true); return descrs; }, print: function (descrs) { return JSON.stringify(descrs); }, pprint: function (descrs) { return JSON.stringify(descrs, null, 2); } })); set(new processor_js_1.Processor('enriched', { processor: function (expr) { return Enrich.semanticMathmlSync(expr, engine_js_1.Engine.getInstance().options); }, postprocessor: function (enr, _expr) { const root = WalkerUtil.getSemanticRoot(enr); let generator; switch (engine_js_1.Engine.getInstance().options.speech) { case EngineConst.Speech.NONE: break; case EngineConst.Speech.SHALLOW: generator = SpeechGeneratorFactory.generator('Adhoc'); generator.getSpeech(root, enr); break; case EngineConst.Speech.DEEP: generator = SpeechGeneratorFactory.generator('Tree'); generator.getSpeech(enr, enr); break; default: break; } return enr; }, pprint: function (tree) { return DomUtil.formatXml(tree.toString()); } })); set(new processor_js_1.Processor('rebuild', { processor: function (expr) { const rebuilt = new rebuild_stree_js_1.RebuildStree(DomUtil.parseInput(expr)); return rebuilt.stree.xml(); }, pprint: function (tree) { return DomUtil.formatXml(tree.toString()); } })); set(new processor_js_1.Processor('walker', { processor: function (expr) { const generator = SpeechGeneratorFactory.generator('Node'); processor_js_1.Processor.LocalState.speechGenerator = generator; generator.setOptions({ modality: engine_js_1.Engine.getInstance().options.modality, locale: engine_js_1.Engine.getInstance().options.locale, domain: engine_js_1.Engine.getInstance().options.domain, style: engine_js_1.Engine.getInstance().options.style }); processor_js_1.Processor.LocalState.highlighter = HighlighterFactory.highlighter({ color: 'black' }, { color: 'white' }, { renderer: 'NativeMML' }); const node = process('enriched', expr); const eml = print('enriched', node); processor_js_1.Processor.LocalState.walker = WalkerFactory.walker(engine_js_1.Engine.getInstance().options.walker, node, generator, processor_js_1.Processor.LocalState.highlighter, eml); return processor_js_1.Processor.LocalState.walker; }, print: function (_walker) { return processor_js_1.Processor.LocalState.walker.speech(); } })); set(new processor_js_1.KeyProcessor('move', { processor: function (direction) { if (!processor_js_1.Processor.LocalState.walker) { return null; } const move = processor_js_1.Processor.LocalState.walker.move(direction); return move === false ? AuralRendering.error(direction) : processor_js_1.Processor.LocalState.walker.speech(); } })); set(new processor_js_1.Processor('number', { processor: function (numb) { const num = parseInt(numb, 10); return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.numberToWords(num); } })); set(new processor_js_1.Processor('ordinal', { processor: function (numb) { const num = parseInt(numb, 10); return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.wordOrdinal(num); } })); set(new processor_js_1.Processor('numericOrdinal', { processor: function (numb) { const num = parseInt(numb, 10); return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.numericOrdinal(num); } })); set(new processor_js_1.Processor('vulgar', { processor: function (numb) { const [en, den] = numb.split('/').map((x) => parseInt(x, 10)); return isNaN(en) || isNaN(den) ? '' : process('speech', `<mfrac><mn>${en}</mn><mn>${den}</mn></mfrac>`); } })); set(new processor_js_1.Processor('latex', { processor: function (ltx) { if (engine_js_1.Engine.getInstance().options.modality !== 'braille' || engine_js_1.Engine.getInstance().options.locale !== 'euro') { console.info('LaTeX input currently only works for Euro Braille output.' + ' Please use the latex-to-speech package from npm for general' + ' LaTeX input to SRE.'); } return process('speech', `<math data-latex="${ltx}"></math>`); } })); set(new processor_js_1.Processor('rebuildStree', { processor: function (expr) { return new rebuild_stree_js_1.RebuildStree(DomUtil.parseInput(expr)); } })); set(new processor_js_1.Processor('speechStructure', { processor: function (expr) { const mml = DomUtil.parseInput(expr); let sxml; try { const rebuilt = new rebuild_stree_js_1.RebuildStree(mml); sxml = rebuilt.stree.xml(); } catch (_e) { sxml = Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); } SpeechGeneratorUtil.connectMactionSelections(mml, sxml); return SpeechGeneratorUtil.computeSpeechStructure(sxml); }, print: function (descrs) { return JSON.stringify(descrs); }, pprint: function (descrs) { return JSON.stringify(descrs, null, 2); } })); set(new processor_js_1.Processor('workerSpeechStructure', { processor: function (expr) { const mml = DomUtil.parseInput(expr); let sxml; try { const rebuilt = new rebuild_stree_js_1.RebuildStree(mml); sxml = rebuilt.stree.xml(); } catch (_e) { sxml = Semantic.xmlTree(mml, engine_js_1.Engine.getInstance().options); } engine_js_1.Engine.getInstance().options.automark = true; const json = {}; assembleSpeechStructure(json, mml, sxml); return json; }, print: function (descrs) { return JSON.stringify(descrs); }, pprint: function (descrs) { return JSON.stringify(descrs, null, 2); } })); function assembleSpeechStructure(json, mml, sxml, options = {}) { var _a; json.options = options; json.mactions = SpeechGeneratorUtil.connectMactionSelections(mml, sxml); if (options.enableSpeech === false) { return; } json.speech = SpeechGeneratorUtil.computeSpeechStructure(sxml); const root = (_a = sxml.childNodes[0]) === null || _a === void 0 ? void 0 : _a.getAttribute('id'); const links = DomUtil.querySelectorAllByAttr(sxml, 'href').length; if (links) { const text = `${links} ${links === 1 ? 'link' : 'links'}`; json.speech[root]['postfix-none'] = json.speech[root]['postfix-none'] ? json.speech[root]['postfix-none'] + `, ${text}` : text; json.speech[root]['postfix-ssml'] = json.speech[root]['postfix-ssml'] ? json.speech[root]['postfix-ssml'] + ` <break time="250ms"/> ${text}` : text; } json.label = json.speech[root]['speech-none'] + (json.speech[root]['postfix-none'] ? `, ${json.speech[root]['postfix-none']}` : ''); json.ssml = json.speech[root]['speech-ssml'] + (json.speech[root]['postfix-ssml'] ? ` <prosody pitch="+30%" rate="+20%"> ${json.speech[root]['postfix-ssml']} </prosody>` : ''); json.translations = Object.assign({}, locale_js_1.LOCALE.MESSAGES.navigate); } //# sourceMappingURL=processor_factory.js.map