123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.SpeechRuleEngine = void 0;
- const auditory_description_js_1 = require("../audio/auditory_description.js");
- const span_js_1 = require("../audio/span.js");
- const debugger_js_1 = require("../common/debugger.js");
- const DomUtil = require("../common/dom_util.js");
- const engine_js_1 = require("../common/engine.js");
- const EngineConst = require("../common/engine_const.js");
- const xpath_util_js_1 = require("../common/xpath_util.js");
- const SpeechRules = require("../speech_rules/speech_rules.js");
- const SpeechRuleStores = require("../speech_rules/speech_rule_stores.js");
- const braille_store_js_1 = require("./braille_store.js");
- const dynamic_cstr_js_1 = require("./dynamic_cstr.js");
- const grammar_js_1 = require("./grammar.js");
- const math_store_js_1 = require("./math_store.js");
- const speech_rule_js_1 = require("./speech_rule.js");
- const trie_js_1 = require("../indexing/trie.js");
- class SpeechRuleEngine {
- static getInstance() {
- SpeechRuleEngine.instance =
- SpeechRuleEngine.instance || new SpeechRuleEngine();
- return SpeechRuleEngine.instance;
- }
- static debugSpeechRule(rule, node) {
- const prec = rule.precondition;
- const queryResult = rule.context.applyQuery(node, prec.query);
- debugger_js_1.Debugger.getInstance().output(prec.query, queryResult ? queryResult.toString() : queryResult);
- prec.constraints.forEach((cstr) => debugger_js_1.Debugger.getInstance().output(cstr, rule.context.applyConstraint(node, cstr)));
- }
- static debugNamedSpeechRule(name, node) {
- const rules = SpeechRuleEngine.getInstance().trie.collectRules();
- const allRules = rules.filter((rule) => rule.name == name);
- for (let i = 0, rule; (rule = allRules[i]); i++) {
- debugger_js_1.Debugger.getInstance().output('Rule', name, 'DynamicCstr:', rule.dynamicCstr.toString(), 'number', i);
- SpeechRuleEngine.debugSpeechRule(rule, node);
- }
- }
- evaluateNode(node) {
- (0, xpath_util_js_1.updateEvaluator)(node);
- const timeIn = new Date().getTime();
- let result = [];
- try {
- result = this.evaluateNode_(node);
- }
- catch (err) {
- console.log(err);
- console.error('Something went wrong computing speech.');
- debugger_js_1.Debugger.getInstance().output(err);
- }
- const timeOut = new Date().getTime();
- debugger_js_1.Debugger.getInstance().output('Time:', timeOut - timeIn);
- return result;
- }
- toString() {
- const allRules = this.trie.collectRules();
- return allRules.map((rule) => rule.toString()).join('\n');
- }
- runInSetting(settings, callback) {
- const engine = engine_js_1.Engine.getInstance();
- const save = {};
- for (const [key, val] of Object.entries(settings)) {
- save[key] = engine[key];
- engine[key] = val;
- }
- engine.setDynamicCstr();
- const result = callback();
- for (const [key, val] of Object.entries(save)) {
- engine[key] = val;
- }
- engine.setDynamicCstr();
- return result;
- }
- static addStore(set) {
- const store = storeFactory(set);
- if (store.kind !== 'abstract') {
- store
- .getSpeechRules()
- .forEach((x) => SpeechRuleEngine.getInstance().trie.addRule(x));
- }
- SpeechRuleEngine.getInstance().addEvaluator(store);
- }
- processGrammar(context, node, grammar) {
- const assignment = {};
- for (const [key, val] of Object.entries(grammar)) {
- assignment[key] =
- typeof val === 'string' ? context.constructString(node, val) : val;
- }
- grammar_js_1.Grammar.getInstance().pushState(assignment);
- }
- addEvaluator(store) {
- const fun = store.evaluateDefault.bind(store);
- const loc = this.evaluators_[store.locale];
- if (loc) {
- loc[store.modality] = fun;
- return;
- }
- const mod = {};
- mod[store.modality] = fun;
- this.evaluators_[store.locale] = mod;
- }
- getEvaluator(locale, modality) {
- const loc = this.evaluators_[locale] ||
- this.evaluators_[dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.LOCALE]];
- return loc[modality] || loc[dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.MODALITY]];
- }
- enumerate(opt_info) {
- return this.trie.enumerate(opt_info);
- }
- constructor() {
- this.trie = null;
- this.evaluators_ = {};
- this.trie = new trie_js_1.Trie();
- }
- evaluateNode_(node) {
- if (!node) {
- return [];
- }
- this.updateConstraint_();
- let result = this.evaluateTree_(node);
- result = processAnnotations(result);
- return result;
- }
- evaluateTree_(node) {
- const engine = engine_js_1.Engine.getInstance();
- let result;
- debugger_js_1.Debugger.getInstance().output(engine.mode !== EngineConst.Mode.HTTP ? node.toString() : node);
- grammar_js_1.Grammar.getInstance().setAttribute(node);
- const rule = this.lookupRule(node, engine.dynamicCstr);
- if (!rule) {
- if (engine.strict) {
- return [];
- }
- result = this.getEvaluator(engine.locale, engine.modality)(node);
- if (node.attributes) {
- this.addPersonality_(result, {}, false, node);
- }
- return result;
- }
- debugger_js_1.Debugger.getInstance().generateOutput(() => [
- 'Apply Rule:',
- rule.name,
- rule.dynamicCstr.toString(),
- engine.mode === EngineConst.Mode.HTTP
- ? DomUtil.serializeXml(node)
- : node.toString()
- ]);
- grammar_js_1.Grammar.getInstance().processSingles();
- const context = rule.context;
- const components = rule.action.components;
- result = [];
- for (let i = 0, component; (component = components[i]); i++) {
- let descrs = [];
- const content = component.content || '';
- const attributes = component.attributes || {};
- let multi = false;
- if (component.grammar) {
- this.processGrammar(context, node, component.grammar);
- }
- let saveEngine = null;
- if (attributes.engine) {
- saveEngine = engine_js_1.Engine.getInstance().dynamicCstr.getComponents();
- const features = Object.assign({}, saveEngine, grammar_js_1.Grammar.parseInput(attributes.engine));
- engine_js_1.Engine.getInstance().setDynamicCstr(features);
- this.updateConstraint_();
- }
- switch (component.type) {
- case speech_rule_js_1.ActionType.NODE:
- {
- const selected = context.applyQuery(node, content);
- if (selected) {
- descrs = this.evaluateTree_(selected);
- }
- }
- break;
- case speech_rule_js_1.ActionType.MULTI:
- {
- multi = true;
- const selects = context.applySelector(node, content);
- if (selects.length > 0) {
- descrs = this.evaluateNodeList_(context, selects, attributes['sepFunc'], context.constructString(node, attributes['separator']), attributes['ctxtFunc'], context.constructString(node, attributes['context']));
- }
- }
- break;
- case speech_rule_js_1.ActionType.TEXT:
- {
- const xpath = attributes['span'];
- let attrs = {};
- if (xpath) {
- const nodes = (0, xpath_util_js_1.evalXPath)(xpath, node);
- attrs = nodes.length
- ? span_js_1.Span.getAttributes(nodes[0])
- : { kind: xpath };
- }
- const str = context.constructSpan(node, content, attrs);
- descrs = str.map(function (span) {
- return auditory_description_js_1.AuditoryDescription.create({ text: span.speech, attributes: span.attributes }, { adjust: true });
- });
- }
- break;
- case speech_rule_js_1.ActionType.PERSONALITY:
- default:
- descrs = [auditory_description_js_1.AuditoryDescription.create({ text: content })];
- }
- if (descrs[0] && !multi) {
- if (attributes['context']) {
- descrs[0]['context'] =
- context.constructString(node, attributes['context']) +
- (descrs[0]['context'] || '');
- }
- if (attributes['annotation']) {
- descrs[0]['annotation'] = attributes['annotation'];
- }
- }
- this.addLayout(descrs, attributes, multi);
- if (component.grammar) {
- grammar_js_1.Grammar.getInstance().popState();
- }
- result = result.concat(this.addPersonality_(descrs, attributes, multi, node));
- if (saveEngine) {
- engine_js_1.Engine.getInstance().setDynamicCstr(saveEngine);
- this.updateConstraint_();
- }
- }
- grammar_js_1.Grammar.getInstance().popState();
- return result;
- }
- evaluateNodeList_(context, nodes, sepFunc, sepStr, ctxtFunc, ctxtStr) {
- if (!nodes.length) {
- return [];
- }
- const sep = sepStr || '';
- const cont = ctxtStr || '';
- const cFunc = context.contextFunctions.lookup(ctxtFunc);
- const ctxtClosure = cFunc
- ? cFunc(nodes, cont)
- : function () {
- return cont;
- };
- const sFunc = context.contextFunctions.lookup(sepFunc);
- const sepClosure = sFunc
- ? sFunc(nodes, sep)
- : function () {
- return [
- auditory_description_js_1.AuditoryDescription.create({ text: sep }, { translate: true })
- ];
- };
- let result = [];
- for (let i = 0, node; (node = nodes[i]); i++) {
- const descrs = this.evaluateTree_(node);
- if (descrs.length > 0) {
- descrs[0]['context'] = ctxtClosure() + (descrs[0]['context'] || '');
- result = result.concat(descrs);
- if (i < nodes.length - 1) {
- const text = sepClosure();
- result = result.concat(text);
- }
- }
- }
- return result;
- }
- addLayout(descrs, props, _multi) {
- const layout = props.layout;
- if (!layout) {
- return;
- }
- if (layout.match(/^begin/)) {
- descrs.unshift(new auditory_description_js_1.AuditoryDescription({ text: '', layout: layout }));
- return;
- }
- if (layout.match(/^end/)) {
- descrs.push(new auditory_description_js_1.AuditoryDescription({ text: '', layout: layout }));
- return;
- }
- descrs.unshift(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `begin${layout}` }));
- descrs.push(new auditory_description_js_1.AuditoryDescription({ text: '', layout: `end${layout}` }));
- }
- addPersonality_(descrs, props, multi, node) {
- const personality = {};
- let pause = null;
- for (const key of EngineConst.personalityPropList) {
- const value = props[key];
- if (typeof value === 'undefined') {
- continue;
- }
- const numeral = parseFloat(value);
- const realValue = isNaN(numeral)
- ? value.charAt(0) === '"'
- ? value.slice(1, -1)
- : value
- : numeral;
- if (key === EngineConst.personalityProps.PAUSE) {
- pause = realValue;
- }
- else {
- personality[key] = realValue;
- }
- }
- for (let i = 0, descr; (descr = descrs[i]); i++) {
- this.addRelativePersonality_(descr, personality);
- this.addExternalAttributes_(descr, node);
- }
- if (multi && descrs.length) {
- delete descrs[descrs.length - 1].personality[EngineConst.personalityProps.JOIN];
- }
- if (pause && descrs.length) {
- const last = descrs[descrs.length - 1];
- if (last.text || Object.keys(last.personality).length) {
- descrs.push(auditory_description_js_1.AuditoryDescription.create({
- text: '',
- personality: { pause: pause }
- }));
- }
- else {
- last.personality[EngineConst.personalityProps.PAUSE] = pause;
- }
- }
- return descrs;
- }
- addExternalAttributes_(descr, node) {
- if (descr.attributes['id'] === undefined) {
- descr.attributes['id'] = node.getAttribute('id');
- }
- if (node.hasAttributes()) {
- const attrs = node.attributes;
- for (let i = attrs.length - 1; i >= 0; i--) {
- const key = attrs[i].name;
- if (!descr.attributes[key] && key.match(/^ext/)) {
- descr.attributes[key] = attrs[i].value;
- }
- }
- }
- }
- addRelativePersonality_(descr, personality) {
- if (!descr['personality']) {
- descr['personality'] = personality;
- return descr;
- }
- const descrPersonality = descr['personality'];
- for (const [key, val] of Object.entries(personality)) {
- if (descrPersonality[key] &&
- typeof descrPersonality[key] == 'number' &&
- typeof val == 'number') {
- descrPersonality[key] = (descrPersonality[key] + val).toString();
- }
- else if (!descrPersonality[key]) {
- descrPersonality[key] = val;
- }
- }
- return descr;
- }
- updateConstraint_() {
- const dynamic = engine_js_1.Engine.getInstance().dynamicCstr;
- const strict = engine_js_1.Engine.getInstance().strict;
- const trie = this.trie;
- const props = {};
- let locale = dynamic.getValue(dynamic_cstr_js_1.Axis.LOCALE);
- let modality = dynamic.getValue(dynamic_cstr_js_1.Axis.MODALITY);
- let domain = dynamic.getValue(dynamic_cstr_js_1.Axis.DOMAIN);
- if (!trie.hasSubtrie([locale, modality, domain])) {
- domain = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.DOMAIN];
- if (!trie.hasSubtrie([locale, modality, domain])) {
- modality = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.MODALITY];
- if (!trie.hasSubtrie([locale, modality, domain])) {
- locale = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.LOCALE];
- }
- }
- }
- props[dynamic_cstr_js_1.Axis.LOCALE] = [locale];
- props[dynamic_cstr_js_1.Axis.MODALITY] = [
- modality !== 'summary'
- ? modality
- : dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.MODALITY]
- ];
- props[dynamic_cstr_js_1.Axis.DOMAIN] = [
- modality !== 'speech' ? dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[dynamic_cstr_js_1.Axis.DOMAIN] : domain
- ];
- const order = dynamic.getOrder();
- for (let i = 0, axis; (axis = order[i]); i++) {
- if (!props[axis]) {
- const value = dynamic.getValue(axis);
- const valueSet = this.makeSet_(value, dynamic.preference);
- const def = dynamic_cstr_js_1.DynamicCstr.DEFAULT_VALUES[axis];
- if (!strict && value !== def) {
- valueSet.push(def);
- }
- props[axis] = valueSet;
- }
- }
- dynamic.updateProperties(props);
- }
- makeSet_(value, preferences) {
- if (!preferences || !Object.keys(preferences).length) {
- return [value];
- }
- return value.split(':');
- }
- lookupRule(node, dynamic) {
- if (!node ||
- (node.nodeType !== DomUtil.NodeType.ELEMENT_NODE &&
- node.nodeType !== DomUtil.NodeType.TEXT_NODE)) {
- return null;
- }
- const matchingRules = this.lookupRules(node, dynamic);
- return matchingRules.length > 0
- ? this.pickMostConstraint_(dynamic, matchingRules)
- : null;
- }
- lookupRules(node, dynamic) {
- return this.trie.lookupRules(node, dynamic.allProperties());
- }
- pickMostConstraint_(_dynamic, rules) {
- const comparator = engine_js_1.Engine.getInstance().comparator;
- rules.sort(function (r1, r2) {
- return (comparator.compare(r1.dynamicCstr, r2.dynamicCstr) ||
- r2.precondition.priority - r1.precondition.priority ||
- r2.precondition.constraints.length -
- r1.precondition.constraints.length ||
- r2.precondition.rank - r1.precondition.rank);
- });
- debugger_js_1.Debugger.getInstance().generateOutput((() => {
- return rules.map((x) => x.name + '(' + x.dynamicCstr.toString() + ')');
- }).bind(this));
- return rules[0];
- }
- }
- exports.SpeechRuleEngine = SpeechRuleEngine;
- const stores = new Map();
- function getStore(locale, modality) {
- if (modality === 'braille' && locale === 'euro') {
- return new braille_store_js_1.EuroStore();
- }
- if (modality === 'braille') {
- return new braille_store_js_1.BrailleStore();
- }
- return new math_store_js_1.MathStore();
- }
- function storeFactory(set) {
- const name = `${set.locale}.${set.modality}.${set.domain}`;
- if (set.kind === 'actions') {
- const store = stores.get(name);
- store.parse(set);
- return store;
- }
- SpeechRuleStores.init();
- if (set && !set.functions) {
- set.functions = SpeechRules.getStore(set.locale, set.modality, set.domain);
- }
- const store = getStore(set.locale, set.modality);
- stores.set(name, store);
- if (set.inherits) {
- store.inherits = stores.get(`${set.inherits}.${set.modality}.${set.domain}`);
- }
- store.parse(set);
- store.initialize();
- return store;
- }
- engine_js_1.Engine.nodeEvaluator = SpeechRuleEngine.getInstance().evaluateNode.bind(SpeechRuleEngine.getInstance());
- const punctuationMarks = ['⠆', '⠒', '⠲', '⠦', '⠴', '⠄'];
- function processAnnotations(descrs) {
- const alist = new auditory_description_js_1.AuditoryList(descrs);
- for (const item of alist.annotations) {
- const descr = item.data;
- if (descr.annotation === 'punctuation') {
- const prev = alist.prevText(item);
- if (!prev)
- continue;
- const last = prev.data;
- if (last.annotation !== 'punctuation' &&
- last.text !== '⠀' &&
- descr.text.length === 1 &&
- punctuationMarks.indexOf(descr.text) !== -1) {
- descr.text = '⠸' + descr.text;
- }
- }
- }
- return alist.toList();
- }
|