Home

Awesome

Speech Rule Engine

Dependencies NPM version NPM monthly downloads NPM total downloads jsdelivr rank example workflow


Breaking Change: Please move to v3.0.2 or later. More info here.


NodeJS version of the ChromeVox speech rule engine. Forked from ChromeVox release 1.31.0

Speech rule engine (SRE) can translate XML expressions into speech strings according to rules that can be specified in a syntax using Xpath expressions. It was originally designed for translation of MathML and MathJax DOM elements for the ChromeVox screen reader. Besides the rules originally designed for the use in ChromeVox, it also has an implemententation of the full set of Mathspeak and Clearspeak rules, localisation into a number of languages and Braille output currently in Nemeth.

SRE contains a library for semantic interpretation to re-represents any mathematical expression in its own internal semantic format, overcoming the poor design of presentation MathML by fully disassembling and reconstructing an expression. For a better understanding of the representation have a look at its visualiser. The semantic trees can be used in their own XML format directly or used to enrich the input MathML expressions with semantic information and speech strings.

There are three ways of using SRE:

  1. Node Module: Download via npm or yarn. This is the easiest way to use the speech rule engine via its API and is the preferred option if you just want to include it in your project.

  2. Standalone Tool: Download via github and build. This is useful if you want to use the speech rule engine in batch mode or interactivley to add your own code. Or simply run it with npx, for example to get all SRE options anywhere without local installation run:

    npx speech-rule-engine -h
  1. Browser Library: This gives you the option of loading SRE in a browser and use its full functionality on your webesites.

Node Module

Install as a node module using npm:

 npm install speech-rule-engine

Or add it with yarn:

 yarn add speech-rule-engine

Then import into a running node or a source file using require:

 require('speech-rule-engine');

API

Current API functions are divided into three categories.

Methods that take a string containing a MathML expression:

MethodReturn Value
toSpeech(mathml)Speech string for the MathML.
toSemantic(mathml)XML representation of the semantic tree for the MathML.
toJson(mathml)The semantic tree in JSON.
toDescription(mathml)The array of auditory description objects of the MathML expression.
toEnriched(mathml)The semantically enriched MathML expression.

Note that in asynchronous operation mode for these methods to work correctly, it is necessary to ensure that the Engine is ready for processing. In other words, you need to wait for the setup promise to resolve. See documentation of engineReady and setupEngine below.

Methods that take an input filename and optionally an output filename:

Note that the file methods only work in Node!

These methods load the given file, process its content and return the result. In asynchronous mode they return a promise that resolves to the result. If the output filename is given the result will also be written to this file. Note, that this will overwrite the existing file.

MethodReturn Value
file.toSpeech(input, output)Speech string for the MathML.
file.toSemantic(input, output)XML representation of the semantic tree for the MathML.
file.toJson(input, output)The semantic tree in JSON.
file.toDescription(input, output)The array of auditory description objects of the MathML expression.
file.toEnriched(input, output)The semantically enriched MathML expression.

Methods for computing textual representations of numbers

These methods take a non-negative integer (either as string or number) as input an return the number as text in the currently active locale. For the vulgar method a vulgar fraction can be provided as a string of two slash separated numbers, e.g., "1/2".

MethodReturn Value
number(input)The number as text.
ordinal(input)The word ordinal.
numericOrdinal(input)The numeric ordinal.
vulgar(input)Word representation of a vulgar fraction.

Methods for querying and controlling the engine behaviour:

MethodReturn Value
versionReturns SRE's version number.
engineReady()Returns a promise that resolves as soon as the engine is ready for processing (i.e., all necessary rule files have been loaded and the engine is done updating). This is important in asynchronous settings.
setupEngine(options)Takes an options feature vector to parameterise the Speech Rule Engine. Returns a promise that resolves as soon as the engine is ready for processing.
engineSetup()Returns the current setup of the engine as an options feature vector.

Methods for navigating math expressions:

For the following methods SRE maintains an internal state, hence they are only useful when running in browser or in a Node REPL. Therefore, they are not exposed via the command line interface.

MethodReturn Value
walk(input)Speech string for the MathML.
move(keycode)Speech string after the move. Keycodes are numerical strings representing cursor keys, space, enter, etc.

For more information on keybindings for the walker see here this dedicated page.

Options

There are a number of options that allow you to parameterise the Speech Rule Engine. They can be set with the setupEngine(options) method, which takes an options feature vector (an object of option/value pairs) to parameterise the engine. The engine's setup can be queried with the engineSetup() method that returns feature vector representing its current setup. Some options are quite internal to SRE and are therefore not exposed via the command line interface.

Options to control speech output

OptionValue
domainDomain or subject area of speech rules (e.g., mathspeak, clearspeak).
styleStyle or preference setting of speech rules (e.g., brief).
In case of clearspeak, multiple preferences can be chosen using : as separator.
localeLanguage locale in 639-1.
subisoMore fine grained specification of locale. E.g., for French fr, be, or ch
markupSet output markup for speech: none, ssml, sable, voicexml, acss, ssml_step
modalitySet the modality SRE returns. E.g., speech, braille, prefix, summary

Observe that not every domain (i.e., speech rule set) implements every style. Similarly, not every speech rule set is implemneted in every locale. For a more detailed overview of locale, domain, style combinations, use the --opt switch on the command line interface.

Options for enriched MathML output

Enriched MathML output is markup that embeds the internal semantic structure SRE uses into a modified represnentation of the original MathML. To get an idea of the semantic tree, take a look at its visualisation.

OptionValue
speechDepth to which generated speech is stored in attributes during semantic enrichment. Values are none, shallow, deep. Default is none.
pprintBoolean flag to switch on pretty printing of output. This works on any XML style output. Default is true.
structureIf set, includes a structure attribute in the enriched MathML that summarises the structure of the semantic tree in form of an sexpression.

Options for internal control of the engine

These other options give more fine grained control of SRE. They can be useful during development and when integrating SRE into a larger project. They are given in decreasing order of interestingness.

OptionValue
jsonURL where to pull the json speech rule files from.
xpathURL where to pull an xpath library from. This is important for environments not supporting xpath, e.g., IE or Edge.
rateBase value for speech rate in ssml_step markup
strictBoolean flag indicating if only a directly matching rule should be used. I.e., no default rules are used in case a rule is not available for a particular domain, style, etc. Default is false.
modeThe running mode for SRE: sync, async, http
By default SRE in node is in async, in browser in http, and on CLI in sync mode.
customProvide a custom method for locale loading. See below for more informaton.

Custom Loading Method

SRE loads its locales and rule sets via loading methods specific for the particular environment and mode. I.e., it loads json files from the file system in node or via XML HTTP requests in the browser. These methods can be customised via passing a new method to the engine via the feature vector. A loader method takes the locale string as input and return a promise that resolves to the string containing the JSON structure of the locale file once loading is successfully completed. In other words it should be of type

(locale: string) => Promise<string>

In node the method can be directly set by passing it to the setupEngine method via the feature vector. As an example the following method loads locales from a local folder at /tmp/mymaps.

sre.setupEngine({
  custom: loc => {
    let file = `/tmp/mymaps/${loc}.json`;
    return new Promise((res, rej) => {
      try {
        res(fs.readFileSync(file));
        console.log(`Loading of locale ${loc} succeeded`);
      } catch (_) {
        console.log(`Loading of locale ${loc} failed`);
        rej('');
      }
    });
  }
});

Standalone Tool

Install the library using npm:

 npm install speech-rule-engine

Or add it with yarn:

 yarn add speech-rule-engine

Run on command line

SRE can be run on the command line by providing a set of processing options and either a list of input files or a inputting an XML expression manually.

./node_modules/.bin/sre [options] infile1 infile2 infile3 ...

For example running

./node_modules/.bin/sre -j -p PATH_TO_SRE_RESOURCES/samples/sample1.xml PATH_TO_SRE_RESOURCES/samples/sample2.xml

will return the semantic tree in JSON as well as the speech translation for the expressions in the two sample files. (Note, that -p is the default option if no processing options are given).

If you have npx installed simply use this to run it from within the speech-rule-engine folder with

npx sre

This works equivalently with all options and file input.

SRE also enables direct input from command line using stdin. For example, running

npx sre -j -p

will wait for a complete XML expression to be input for translation. Similarly, shell piping is allowed:

npx sre -j -p < PATH_TO_SRE_RESOURCES/samples/sample1.xml

Note, that when providing the -o outfile option output is saved into the given file. However, when processing from file only the very last output is reliably saved, while when processing via pipes or command line input all output is saved.

Command Line Options

The following is a list of command line options for the speech rule engine.

ShortLongMeaning
-o--output [name]Output file [name].
If not given output is printed to stdout.
-d--domain [name]Domain or subject area [name].
This refers to a particular subject type of speech rules or subject area rules are defined for (e.g., mathspeak, clearspeak).
If no domain parameter is provided, default is used.
-t--style [name]Speech style [name].
Selects a particular speech style (e.g., brief).
If no style parameter is provided, style default is used.
-c--localeLanguage locale in ISO 639-1.
-k--markup [name]Generate speech output with markup tags. Currently supported SSML, VoiceXML, Sable, ACSS (as sexpressions for Emacsspeak)
-p--speechGenerate speech output (default).
-a--auditGenerate auditory descriptions (JSON format).
-j--jsonGenerate JSON of semantic tree.
-x--xmlGenerate XML of semantic tree.
-P--pprintWhen given output is pretty printed if possible.
-m--mathmlGenerate enriched MathML.
-g--generate [depth]Include generated speech in enriched MathML. Supported values: none, shallow, deep (default: none)
-w--structureInclude structure attribute in enriched MathML.
-N--numberTranslate number to words.
-O--ordinalTranslate number to word ordinal.
-S--numericTranslate number to numeric ordinal.
-F--vulgarTranslate vulgar fraction to words. Provide vulgar fraction as slash seperated numbers.
-C--subisoSubcategory of the locale given with -c.
-v--verboseVerbose mode. Print additional information, useful for debugging.
-l--log [name]Log file [name]. Verbose output is redirected to this file.
If not given verbose output is printed to stdout.
-h--helpEnumerates all command line options.
--optEnumerates all available options for locale, modality, domain and style.
-V--versionOutputs the version number

Building from Source

Clone from github and install dependencies either by running:

 npm install

Or install them manually. SRE depends on the following libraries to run:

 commander
 xmldom-sre
 wicked-good-xpath

In addition SRE depends on a number of libraries for development, in particular TypeScript and webpack as well as a number of plugins and libraries to ensure source code hygiene. These are too numerous to list here and are best viewed in the devDependencies section of the package.json file.

Running npm install will build the single JavaScript modules, webpack the bundle file in lib/sre.js as well as assemble the locale files in lib/mathmaps. For more details on the build process as well as how to use different bundlers see the developers documentation below.

Run interactively

You can work with SRE interactively in node or use it as a batch processor, by loading JavaScript modules directly. For the generation of speech make sure to set the SRE_JSON_PATH environment variable to the folder where your locale files reside. For example, set

export SRE_JSON_PATH=./lib/mathmaps

before in the shell before running node in the speech-rule-engine directory. You can then load the individual modules simply with node's require:

let sre = require('./js/index.js');

will give you the full API in the sre variable. On the other hand,

semantic = require('./js/semantic_tree/semantic.js');

will let you work with the semantic tree module only.

Browser Library

SRE can be used as a browser ready library giving you the option of loading it in a browser and use its full functionality on your webesites. Since SRE version 4, the same bundle file works both in node and in a browser. Simply include the file sre.js in your website in a script tag

<script src="[URL]/sre.js"></script>

The API will now be available in the SRE namespace.

Configuration

In addition to programmatically configuring SRE using the setupEngine method, you can also include a configuration element in a website, that can take the same options as setupEngine.

For example the configuration element

<script type="text/x-sre-config">
{
"json": "https://cdn.jsdelivr.net/gh/zorkow/speech-rule-engine@develop/mathmaps/",
"xpath": "https://cdn.jsdelivr.net/gh/google/wicked-good-xpath@master/dist/wgxpath.install.js",
"domain": "mathspeak",
"style": "sbrief"
}
</script>

will cause SRE to load JSON files from rawgit and for IE or Edge it will also load Google's wicked good xpath library. In addition the speech rules are set to mathspeak in super brief style.

Make sure the configuration element comes before the script tag loading SRE in your website!

Custom Loading Methods

Providing a custom loading method for locale loading in browser mode is very similar to its use in node. However, note that since we now want to define a function, it can not simply be given in the JSON configuration element in the x-sre-config script tag. Instead we need to define the special SREfeature variable in the header of the file. Again make sure this script tag comes before the script tag loading SRE in your website!

Here is an example of a custom function to load locales from localhost:

<script>
var SREfeature = {
"custom": function(loc) {
    let file = 'http://localhost/sre/lib/mathmaps/' + loc + '.json';
    let httpRequest = new XMLHttpRequest();
    return new Promise((res, rej) => {
      httpRequest.onreadystatechange = function() {
        if (httpRequest.readyState === 4) {
          console.log('Using my custom loader');
          let status = httpRequest.status;
          if (status === 0 || (status >= 200 && status < 400)) {
            res(httpRequest.responseText);
          } else {
            rej(status);
          }
        }
      };
      httpRequest.open('GET', file, true);
      httpRequest.send();
    });
  }
}
</script>

Developers Documentation

Since v4 SRE is distributed with the transpiled .js files via the npm package. These can be directly included into your respective projects. To control the location of the locale mappings, set the SRE_JSON_PATH environment variable to the folder where your locale files reside. For example, set

export SRE_JSON_PATH=./lib/mathmaps

For more controlled integration or development fork or clone the repository from github.

Building

By default the build process consists of three steps:

  1. Creating Locale files in 'lib/mathmaps'
  2. Transpiling typescript from sources in 'ts/' to 'js/'
  3. Webpacking the bundle in 'lib/sre.js'

Locales are created from the sources in mathmaps by combining the topically split .json files into a single, minimized .json file, one for each language. Note, that for ease of development JSON minimization is done via an intermediate step to generate .min files, which is handles in the Makefile and ensures that only newly altered files have to be minimized.

While the entire build is best cleaned with make clean, this does not clean the .min files. These should be cleaned with make clean_min.

Alternative Builds

MathJax Library

This is only relevant for MathJax distributions version 2.7.X. As of version 3.0 MathJax uses sre directly via its npm release. The MathJax specific build can be created using the mjConfig goal for webpack

npx webpack

that generates a build specific for MathJax in mathjax_sre.js. SRE can then be configured locally on webpages as described above.

Other Entry Points

For particular projects it might be useful and sufficient to create bespoke bundles of SRE submodules. Depending on the bundler

Examples of entry points that provide separate API functionality to SRE submodules are

ModuleJavascript entry pointTypescript entry pointComments
semanticjs/semantic_tree/semantic.jsts/semantic_tree/semantic.tsAPI for semantic tree generation
enrichjs/enrich_mathml/enrich.jsts/enrich_mathml/enrich.tsAPI for semantic enrichment of MathML expressions.
mathjaxjs/common/mathjax.jsts/common/mathjax.tsAPI for MathJax version 2.7.X

Using Bundlers

By default SRE works with webpack. But you can use a number of other bundlers to build. Note, that for all bundlers the JSON locale files need to be build as usual. Depending on the version of SRE you are using some of the alternative bundlers might already be in the devDependencies.

WebPack

The default webpack of SRE generates the sre.js library that can be used both in node and the browser. Other goals are mjConfig that is defined in webpack.config.js or alternative entry points as discussed in more detail in the Alternative Builds section.

Rollupjs

Creates bundles similar to webpack, that can be used pretty much as replacement. Rollup bundles are build from the Javascript modules in js, so make sure to transpile first with npx tsc.

Build

Install the required packages:

npm install --no-save rollup
npm install --no-save @rollup/plugin-commonjs
npm install --no-save @rollup/plugin-node-resolve
npm install --no-save rollup-plugin-terser

Add a rollup.config.js file of the form:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from "rollup-plugin-terser";
import pkg from './package.json';

export default [
  {
    input: 'js/index.js',
    output: {
      name: 'SRE',
      file: pkg.browser,
      format: 'umd'
    },
    plugins: [
      resolve(), 
      commonjs(),
      terser()
    ]
  }
];

The resulting file in ./lib/sre.js works as usual for both browser and node.

Note, that in the Browser version there is currently an issue with Unicode Braille Spaces that are being garbled.

Esbuild

Creates small builds very fast, but has some backward compatibility issues, in that it can work with ES6 modules only.

Build

Install the required packages:

npm install --no-save esbuild

Build using the following command line:

npx esbuild ./ts/index.ts --bundle --outfile=lib/sre.js --format=esm --minify

Node

To run in node you need ES6 modules enabled.

npx install --no-save esm

Then start node with node -r esm. If you want to use the CLI interface, adapt the ./bin/sre script as follows:

#!/usr/bin/env -S node -r esm 
let sre = require('../lib/sre.js');
(new sre.cli()).commandLine();

Browser

Import the SRE library as ES6 module into the browser, e.g.,

<script type="module">
  import * as SRE from 'http://localhost/sre/speech-rule-engine/lib/sre.js'
  ...
</script>

Parcel

SRE currently does not support bundling with parcel.

Coding Style

SRE is implemented using coding format enforced by prettier and eslint. In addition it requires full documentation using JSDOC. When creating a pull request, please make sure that your code compiles and is fully linted.

Code Formatting

We use prettier for formatting code. Run

npm format

to see which files contain format violations. Use

npm format-fix

to automatically fix those format violations.

Code Hygiene

We use eslint for enforcing code style and documentation. Run

npm lint

to see a list of linting errors and warnings. Use

npm lint-fix

to automatically fix those violations as much as possible.

Documentation

Full JSDOC documentation is required and enforced via the eslint jsdoc plugin. To generate documentation from the JSDOC, simply run

npm run docs

This will generate documentation using typedoc for the source code in the directory docs/.

Node Package

The speech rule engine is published as a node package in fully compiled form, together with the JSON libraries for translating atomic expressions. All relevant files are in the lib subdirectory.

To publish the node package run

npm publish

For manually going through the build steps see the prepublish script in package.json.

Removed or Deprecated Functionality

The following is an overview of functionality and options that were available at some point in SRE. Depending on the version you are using they might still work, do nothing or throw an error. Even if they still work they are strongly discouraged to use.

Removed or Deprecated Engine Setup Options

The following options are either deprecated or have been removed. Having them in the feature vector for setupEngine should not throw an exception but will have no effect.

OptionValueReleaseComments
cacheBoolean flag to switch expression caching during speech generation. Default is true.Removed in v3.2.0Expression caching has been removed and the option has no longer any effect.
rulesA list of rulesets to use by SRE. This allows to artificially restrict available speech rules, which can be useful for testing and during rule development. Always expects a list, even if only one rule set is supplied!Deprecated in v4.0.0Note that setting rule sets is no longer useful with the new rule indexing structures. It is only retained for testing purposes.
walkerA walker to use for interactive exploration: None, Syntax, Semantic, TableDeprecated since v4.0.0Defaults to Table walker. Other walkers are no longer maintained!
semanticsBoolean flag to switch OFF semantic interpretation.Removed in v3.0Non-semantic rule sets have been removed since v3.0.

Removed API functions

MethodReturn ValueReleaseComments
pprintXML(string)Returns pretty printed version of a serialised XML string.Removed v3.0Use the pprint option instead.`

Removed Command Line Options

ShortLongMeaningReleaseComments
-i--input [name]Input file [name].Deprecated since v3.0. Removed in v4.0!Use standard input file handling or stdio piping instead
-s--semanticsSwitch OFF semantics interpretation.Removed in v3.0There is no longer support for non-semantic rule sets.

Breaking Change

Due to a breaking change in the commander library old versions of SRE might break when newly installed from npm. SRE relies on commander for running its command line interface.

Therefore, please move to SRE v3.0.2 or later.

If you want to run older versions of SRE, you need to manually downgrade the commander package to v5.1.0 by running

npm install commander@5.1.0

Note, that the command line option --options has now been renamed to --opt.