processor_factory.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.process = process;
  4. exports.output = output;
  5. exports.keypress = keypress;
  6. const AuralRendering = require("../audio/aural_rendering.js");
  7. const Enrich = require("../enrich_mathml/enrich.js");
  8. const HighlighterFactory = require("../highlighter/highlighter_factory.js");
  9. const locale_js_1 = require("../l10n/locale.js");
  10. const Semantic = require("../semantic_tree/semantic.js");
  11. const SpeechGeneratorFactory = require("../speech_generator/speech_generator_factory.js");
  12. const SpeechGeneratorUtil = require("../speech_generator/speech_generator_util.js");
  13. const WalkerFactory = require("../walker/walker_factory.js");
  14. const WalkerUtil = require("../walker/walker_util.js");
  15. const rebuild_stree_js_1 = require("../walker/rebuild_stree.js");
  16. const DomUtil = require("./dom_util.js");
  17. const engine_js_1 = require("./engine.js");
  18. const EngineConst = require("../common/engine_const.js");
  19. const processor_js_1 = require("./processor.js");
  20. const XpathUtil = require("./xpath_util.js");
  21. const PROCESSORS = new Map();
  22. function set(processor) {
  23. PROCESSORS.set(processor.name, processor);
  24. }
  25. function get(name) {
  26. const processor = PROCESSORS.get(name);
  27. if (!processor) {
  28. throw new engine_js_1.SREError('Unknown processor ' + name);
  29. }
  30. return processor;
  31. }
  32. function process(name, expr) {
  33. const processor = get(name);
  34. try {
  35. return processor.processor(expr);
  36. }
  37. catch (_e) {
  38. throw new engine_js_1.SREError('Processing error for expression ' + expr);
  39. }
  40. }
  41. function print(name, data) {
  42. const processor = get(name);
  43. return engine_js_1.Engine.getInstance().pprint
  44. ? processor.pprint(data)
  45. : processor.print(data);
  46. }
  47. function output(name, expr) {
  48. const processor = get(name);
  49. try {
  50. const data = processor.processor(expr);
  51. return engine_js_1.Engine.getInstance().pprint
  52. ? processor.pprint(data)
  53. : processor.print(data);
  54. }
  55. catch (_e) {
  56. console.log(_e);
  57. throw new engine_js_1.SREError('Processing error for expression ' + expr);
  58. }
  59. }
  60. function keypress(name, expr) {
  61. const processor = get(name);
  62. const key = processor instanceof processor_js_1.KeyProcessor ? processor.key(expr) : expr;
  63. const data = processor.processor(key);
  64. return engine_js_1.Engine.getInstance().pprint
  65. ? processor.pprint(data)
  66. : processor.print(data);
  67. }
  68. set(new processor_js_1.Processor('semantic', {
  69. processor: function (expr) {
  70. const mml = DomUtil.parseInput(expr);
  71. return Semantic.xmlTree(mml);
  72. },
  73. postprocessor: function (xml, _expr) {
  74. const setting = engine_js_1.Engine.getInstance().speech;
  75. if (setting === EngineConst.Speech.NONE) {
  76. return xml;
  77. }
  78. const clone = DomUtil.cloneNode(xml);
  79. let speech = SpeechGeneratorUtil.computeMarkup(clone);
  80. if (setting === EngineConst.Speech.SHALLOW) {
  81. xml.setAttribute('speech', AuralRendering.finalize(speech));
  82. return xml;
  83. }
  84. const nodesXml = XpathUtil.evalXPath('.//*[@id]', xml);
  85. const nodesClone = XpathUtil.evalXPath('.//*[@id]', clone);
  86. for (let i = 0, orig, node; (orig = nodesXml[i]), (node = nodesClone[i]); i++) {
  87. speech = SpeechGeneratorUtil.computeMarkup(node);
  88. orig.setAttribute('speech', AuralRendering.finalize(speech));
  89. }
  90. return xml;
  91. },
  92. pprint: function (tree) {
  93. return DomUtil.formatXml(tree.toString());
  94. }
  95. }));
  96. set(new processor_js_1.Processor('speech', {
  97. processor: function (expr) {
  98. const mml = DomUtil.parseInput(expr);
  99. const xml = Semantic.xmlTree(mml);
  100. const descrs = SpeechGeneratorUtil.computeSpeech(xml);
  101. return AuralRendering.finalize(AuralRendering.markup(descrs));
  102. },
  103. pprint: function (speech) {
  104. const str = speech.toString();
  105. return AuralRendering.isXml() ? DomUtil.formatXml(str) : str;
  106. }
  107. }));
  108. set(new processor_js_1.Processor('json', {
  109. processor: function (expr) {
  110. const mml = DomUtil.parseInput(expr);
  111. const stree = Semantic.getTree(mml);
  112. return stree.toJson();
  113. },
  114. postprocessor: function (json, expr) {
  115. const setting = engine_js_1.Engine.getInstance().speech;
  116. if (setting === EngineConst.Speech.NONE) {
  117. return json;
  118. }
  119. const mml = DomUtil.parseInput(expr);
  120. const xml = Semantic.xmlTree(mml);
  121. const speech = SpeechGeneratorUtil.computeMarkup(xml);
  122. if (setting === EngineConst.Speech.SHALLOW) {
  123. json.stree.speech = AuralRendering.finalize(speech);
  124. return json;
  125. }
  126. const addRec = (json) => {
  127. const node = XpathUtil.evalXPath(`.//*[@id=${json.id}]`, xml)[0];
  128. const speech = SpeechGeneratorUtil.computeMarkup(node);
  129. json.speech = AuralRendering.finalize(speech);
  130. if (json.children) {
  131. json.children.forEach(addRec);
  132. }
  133. };
  134. addRec(json.stree);
  135. return json;
  136. },
  137. print: function (json) {
  138. return JSON.stringify(json);
  139. },
  140. pprint: function (json) {
  141. return JSON.stringify(json, null, 2);
  142. }
  143. }));
  144. set(new processor_js_1.Processor('description', {
  145. processor: function (expr) {
  146. const mml = DomUtil.parseInput(expr);
  147. const xml = Semantic.xmlTree(mml);
  148. const descrs = SpeechGeneratorUtil.computeSpeech(xml);
  149. return descrs;
  150. },
  151. print: function (descrs) {
  152. return JSON.stringify(descrs);
  153. },
  154. pprint: function (descrs) {
  155. return JSON.stringify(descrs, null, 2);
  156. }
  157. }));
  158. set(new processor_js_1.Processor('enriched', {
  159. processor: function (expr) {
  160. return Enrich.semanticMathmlSync(expr);
  161. },
  162. postprocessor: function (enr, _expr) {
  163. const root = WalkerUtil.getSemanticRoot(enr);
  164. let generator;
  165. switch (engine_js_1.Engine.getInstance().speech) {
  166. case EngineConst.Speech.NONE:
  167. break;
  168. case EngineConst.Speech.SHALLOW:
  169. generator = SpeechGeneratorFactory.generator('Adhoc');
  170. generator.getSpeech(root, enr);
  171. break;
  172. case EngineConst.Speech.DEEP:
  173. generator = SpeechGeneratorFactory.generator('Tree');
  174. generator.getSpeech(enr, enr);
  175. break;
  176. default:
  177. break;
  178. }
  179. return enr;
  180. },
  181. pprint: function (tree) {
  182. return DomUtil.formatXml(tree.toString());
  183. }
  184. }));
  185. set(new processor_js_1.Processor('rebuild', {
  186. processor: function (expr) {
  187. const rebuilt = new rebuild_stree_js_1.RebuildStree(DomUtil.parseInput(expr));
  188. return rebuilt.stree.xml();
  189. },
  190. pprint: function (tree) {
  191. return DomUtil.formatXml(tree.toString());
  192. }
  193. }));
  194. set(new processor_js_1.Processor('walker', {
  195. processor: function (expr) {
  196. const generator = SpeechGeneratorFactory.generator('Node');
  197. processor_js_1.Processor.LocalState.speechGenerator = generator;
  198. generator.setOptions({
  199. modality: engine_js_1.Engine.getInstance().modality,
  200. locale: engine_js_1.Engine.getInstance().locale,
  201. domain: engine_js_1.Engine.getInstance().domain,
  202. style: engine_js_1.Engine.getInstance().style
  203. });
  204. processor_js_1.Processor.LocalState.highlighter = HighlighterFactory.highlighter({ color: 'black' }, { color: 'white' }, { renderer: 'NativeMML' });
  205. const node = process('enriched', expr);
  206. const eml = print('enriched', node);
  207. processor_js_1.Processor.LocalState.walker = WalkerFactory.walker(engine_js_1.Engine.getInstance().walker, node, generator, processor_js_1.Processor.LocalState.highlighter, eml);
  208. return processor_js_1.Processor.LocalState.walker;
  209. },
  210. print: function (_walker) {
  211. return processor_js_1.Processor.LocalState.walker.speech();
  212. }
  213. }));
  214. set(new processor_js_1.KeyProcessor('move', {
  215. processor: function (direction) {
  216. if (!processor_js_1.Processor.LocalState.walker) {
  217. return null;
  218. }
  219. const move = processor_js_1.Processor.LocalState.walker.move(direction);
  220. return move === false
  221. ? AuralRendering.error(direction)
  222. : processor_js_1.Processor.LocalState.walker.speech();
  223. }
  224. }));
  225. set(new processor_js_1.Processor('number', {
  226. processor: function (numb) {
  227. const num = parseInt(numb, 10);
  228. return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.numberToWords(num);
  229. }
  230. }));
  231. set(new processor_js_1.Processor('ordinal', {
  232. processor: function (numb) {
  233. const num = parseInt(numb, 10);
  234. return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.wordOrdinal(num);
  235. }
  236. }));
  237. set(new processor_js_1.Processor('numericOrdinal', {
  238. processor: function (numb) {
  239. const num = parseInt(numb, 10);
  240. return isNaN(num) ? '' : locale_js_1.LOCALE.NUMBERS.numericOrdinal(num);
  241. }
  242. }));
  243. set(new processor_js_1.Processor('vulgar', {
  244. processor: function (numb) {
  245. const [en, den] = numb.split('/').map((x) => parseInt(x, 10));
  246. return isNaN(en) || isNaN(den)
  247. ? ''
  248. : process('speech', `<mfrac><mn>${en}</mn><mn>${den}</mn></mfrac>`);
  249. }
  250. }));
  251. set(new processor_js_1.Processor('latex', {
  252. processor: function (ltx) {
  253. if (engine_js_1.Engine.getInstance().modality !== 'braille' ||
  254. engine_js_1.Engine.getInstance().locale !== 'euro') {
  255. console.info('LaTeX input currently only works for Euro Braille output.' +
  256. ' Please use the latex-to-speech package from npm for general' +
  257. ' LaTeX input to SRE.');
  258. }
  259. return process('speech', `<math data-latex="${ltx}"></math>`);
  260. }
  261. }));