speech-rule-engine
Version:
A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.
342 lines • 13.7 kB
JavaScript
;
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.computeSpeech = computeSpeech;
exports.computeMarkup = computeMarkup;
exports.recomputeMarkup = recomputeMarkup;
exports.addSpeech = addSpeech;
exports.addModality = addModality;
exports.addPrefix = addPrefix;
exports.retrievePrefix = retrievePrefix;
exports.computePrefix = computePrefix;
exports.connectMactions = connectMactions;
exports.connectMactionSelections = connectMactionSelections;
exports.connectAllMactions = connectAllMactions;
exports.retrieveSummary = retrieveSummary;
exports.computeSummary = computeSummary;
exports.computePostfix = computePostfix;
exports.completeModalities = completeModalities;
exports.computeSpeechStructure = computeSpeechStructure;
exports.computeBrailleStructure = computeBrailleStructure;
exports.nextRules = nextRules;
exports.nextStyle = nextStyle;
exports.toStyles = toStyles;
exports.fromStyles = fromStyles;
const auditory_description_js_1 = require("../audio/auditory_description.js");
const AuralRendering = __importStar(require("../audio/aural_rendering.js"));
const DomUtil = __importStar(require("../common/dom_util.js"));
const XpathUtil = __importStar(require("../common/xpath_util.js"));
const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
const speech_rule_engine_js_1 = require("../rule_engine/speech_rule_engine.js");
const semantic_meaning_js_1 = require("../semantic_tree/semantic_meaning.js");
const semantic_tree_js_1 = require("../semantic_tree/semantic_tree.js");
const WalkerUtil = __importStar(require("../walker/walker_util.js"));
const EngineConst = __importStar(require("../common/engine_const.js"));
const clearspeak_preferences_js_1 = require("../speech_rules/clearspeak_preferences.js");
const clearspeak_preference_string_js_1 = require("../speech_rules/clearspeak_preference_string.js");
function computeSpeech(xml, clear = false) {
const result = speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(xml, clear);
return result;
}
function recomputeSpeech(semantic) {
const tree = semantic_tree_js_1.SemanticTree.fromNode(semantic);
return computeSpeech(tree.xml());
}
function computeMarkup(tree, clear = false) {
const descrs = computeSpeech(tree, clear);
return AuralRendering.markup(descrs);
}
function recomputeMarkup(semantic) {
const descrs = recomputeSpeech(semantic);
return AuralRendering.markup(descrs);
}
function addSpeech(mml, semantic, snode) {
const sxml = DomUtil.querySelectorAllByAttrValue(snode, 'id', semantic.id.toString())[0];
const speech = sxml
? AuralRendering.markup(computeSpeech(sxml))
: recomputeMarkup(semantic);
mml.setAttribute(enrich_attr_js_1.Attribute.SPEECH, speech);
}
function addModality(mml, semantic, modality) {
const markup = recomputeMarkup(semantic);
mml.setAttribute(modality, markup);
}
function addPrefix(mml, semantic) {
const speech = retrievePrefix(semantic);
if (speech) {
mml.setAttribute(enrich_attr_js_1.Attribute.PREFIX, speech);
}
}
function retrievePrefix(semantic) {
const node = computePrefixNode(semantic);
const descrs = computePrefix(node);
return AuralRendering.markup(descrs);
}
function computePrefix(node) {
return node
? speech_rule_engine_js_1.SpeechRuleEngine.getInstance().runInSetting({
modality: 'prefix',
strict: true,
speech: true
}, function () {
return speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(node);
})
: [];
}
function computePrefixNode(semantic) {
const tree = semantic_tree_js_1.SemanticTree.fromRoot(semantic);
const nodes = XpathUtil.evalXPath('.//*[@id="' + semantic.id + '"]', tree.xml());
let node = nodes[0];
if (nodes.length > 1) {
node = nodeAtPosition(semantic, nodes) || node;
}
return node;
}
function nodeAtPosition(semantic, nodes) {
const node = nodes[0];
if (!semantic.parent) {
return node;
}
const path = [];
while (semantic) {
path.push(semantic.id);
semantic = semantic.parent;
}
const pathEquals = function (xml, path) {
while (path.length &&
path.shift().toString() === xml.getAttribute('id') &&
xml.parentNode &&
xml.parentNode.parentNode) {
xml = xml.parentNode.parentNode;
}
return !path.length;
};
for (let i = 0, xml; (xml = nodes[i]); i++) {
if (pathEquals(xml, path.slice())) {
return xml;
}
}
return node;
}
function connectMactions(node, mml, stree) {
const mactions = DomUtil.querySelectorAll(mml, 'maction');
for (let i = 0, maction; (maction = mactions[i]); i++) {
const aid = maction.getAttribute('id');
const span = DomUtil.querySelectorAllByAttrValue(node, 'id', aid)[0];
if (!span) {
continue;
}
const lchild = maction.childNodes[1];
const mid = lchild.getAttribute(enrich_attr_js_1.Attribute.ID);
let cspan = WalkerUtil.getBySemanticId(node, mid);
if (cspan && cspan.getAttribute(enrich_attr_js_1.Attribute.TYPE) !== 'dummy') {
continue;
}
cspan = span.childNodes[0];
if (cspan.getAttribute('sre-highlighter-added')) {
continue;
}
const pid = lchild.getAttribute(enrich_attr_js_1.Attribute.PARENT);
if (pid) {
cspan.setAttribute(enrich_attr_js_1.Attribute.PARENT, pid);
}
cspan.setAttribute(enrich_attr_js_1.Attribute.TYPE, 'dummy');
cspan.setAttribute(enrich_attr_js_1.Attribute.ID, mid);
cspan.setAttribute('role', 'treeitem');
cspan.setAttribute('aria-level', lchild.getAttribute('aria-level'));
const cst = DomUtil.querySelectorAllByAttrValue(stree, 'id', mid)[0];
cst.setAttribute('alternative', mid);
}
}
var NeededAttributes;
(function (NeededAttributes) {
NeededAttributes["ID"] = "data-semantic-id";
NeededAttributes["PARENT"] = "data-semantic-parent";
NeededAttributes["LEVEL"] = "aria-level";
NeededAttributes["POS"] = "aria-posinset";
NeededAttributes["ROLE"] = "role";
})(NeededAttributes || (NeededAttributes = {}));
function getNeededAttributes(stree) {
const result = {};
for (const [, attr] of Object.entries(NeededAttributes)) {
result[attr] = stree.getAttribute(attr);
}
return result;
}
function connectMactionSelections(mml, stree) {
const mactions = DomUtil.querySelectorAll(mml, 'maction');
const results = {};
for (let i = 0, maction; (maction = mactions[i]); i++) {
const selection = parseInt(maction.getAttribute('selection'));
const children = Array.from(maction.childNodes);
const semantic = children.filter((child) => child.hasAttribute(NeededAttributes.ID))[0];
const selected = children[selection - 1];
if (!semantic || semantic === selected) {
continue;
}
const mid = semantic.getAttribute(enrich_attr_js_1.Attribute.ID);
const cst = DomUtil.querySelectorAllByAttrValue(stree, 'id', mid)[0];
cst.setAttribute('alternative', mid);
results[maction.getAttribute('id')] = getNeededAttributes(semantic);
}
return results;
}
function connectAllMactions(mml, stree) {
const mactions = DomUtil.querySelectorAll(mml, 'maction');
for (let i = 0, maction; (maction = mactions[i]); i++) {
const lchild = maction.childNodes[1];
const mid = lchild.getAttribute(enrich_attr_js_1.Attribute.ID);
const cst = DomUtil.querySelectorAllByAttrValue(stree, 'id', mid)[0];
cst.setAttribute('alternative', mid);
}
}
function retrieveSummary(node, options = {}) {
const descrs = computeSummary(node, options);
return AuralRendering.markup(descrs);
}
function computeSummary(node, options = {}) {
const preOption = options.locale ? { locale: options.locale } : {};
return node
? speech_rule_engine_js_1.SpeechRuleEngine.getInstance().runInSetting(Object.assign(preOption, {
modality: 'summary',
strict: false,
speech: true
}), function () {
return speech_rule_engine_js_1.SpeechRuleEngine.getInstance().evaluateNode(node);
})
: [];
}
function computePostfix(node) {
const postfix = [];
if (node.getAttribute('role') === semantic_meaning_js_1.SemanticRole.MGLYPH) {
postfix.push(new auditory_description_js_1.AuditoryDescription({ text: 'image', personality: {} }));
}
if (node.hasAttribute('href')) {
postfix.push(new auditory_description_js_1.AuditoryDescription({ text: 'link', personality: {} }));
}
speech_rule_engine_js_1.SpeechRuleEngine.getInstance().speechStructure.addNode(node, postfix, 'postfix');
return postfix;
}
function completeModalities(structure) {
structure.completeModality('speech', computeSpeech);
structure.completeModality('prefix', computePrefix);
structure.completeModality('postfix', computePostfix);
structure.completeModality('summary', computeSummary);
}
function computeSpeechStructure(sxml) {
computeSpeech(sxml, true);
const structure = speech_rule_engine_js_1.SpeechRuleEngine.getInstance().speechStructure;
completeModalities(structure);
return structure.json(['none', 'ssml']);
}
function computeBrailleStructure(sxml) {
computeSpeech(sxml, true);
const structure = speech_rule_engine_js_1.SpeechRuleEngine.getInstance().speechStructure;
structure.completeModality('braille', computeSpeech);
return structure.json(['none']);
}
function nextRules(options, styles = EngineConst.DOMAIN_TO_STYLES) {
var _a;
if (options.modality !== 'speech') {
return options;
}
const prefs = clearspeak_preferences_js_1.ClearspeakPreferences.getLocalePreferences();
if (!prefs[options.locale]) {
return options;
}
options.domain = options.domain === 'mathspeak' ? 'clearspeak' : 'mathspeak';
options.style = (_a = styles[options.domain]) !== null && _a !== void 0 ? _a : options.style;
return options;
}
function nextStyle(node, options) {
const { modality: modality, domain: domain, style: style, locale: locale } = options;
if (modality !== 'speech') {
return style;
}
if (domain === 'mathspeak') {
const styles = ['default', 'brief', 'sbrief'];
const index = styles.indexOf(style);
if (index === -1) {
return style;
}
return index >= styles.length - 1 ? styles[0] : styles[index + 1];
}
if (domain === 'clearspeak') {
const prefs = clearspeak_preferences_js_1.ClearspeakPreferences.getLocalePreferences();
const loc = prefs[locale];
if (!loc) {
return 'default';
}
const smart = clearspeak_preferences_js_1.ClearspeakPreferences.relevantPreferences(node);
const current = (0, clearspeak_preference_string_js_1.findPreference)(style, smart);
const options = loc[smart].map(function (x) {
return x.split('_')[1];
});
const index = options.indexOf(current);
if (index === -1) {
return style;
}
const next = index >= options.length - 1 ? options[0] : options[index + 1];
const result = (0, clearspeak_preference_string_js_1.addPreference)(style, smart, next);
return result;
}
return style;
}
function toStyles(options) {
var _a;
const { domain, style, domain2style } = options;
const styles = {};
if (!domain2style) {
Object.assign(styles, EngineConst.DOMAIN_TO_STYLES);
styles[domain] = style;
return styles;
}
const split = domain2style.split(',');
for (const pair of split) {
const [first, second] = pair.split(/:(.*)/);
styles[first] = second
? second
: ((_a = EngineConst.DOMAIN_TO_STYLES[first]) !== null && _a !== void 0 ? _a : 'default');
}
return styles;
}
function fromStyles(styles) {
const strs = [];
for (const [domain, style] of Object.entries(styles)) {
strs.push(`${domain}:${style}`);
}
return strs.join(',');
}
//# sourceMappingURL=speech_generator_util.js.map