Skip to content

AndyFerns/Accessible-Math-Reader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

β™Ώ Accessible Math Reader

A screen-reader-first mathematical accessibility toolkit for converting LaTeX, MathML, and plaintext/Unicode math into speech, Braille, and navigable ARIA structures.

MIT License Python 3.9+ Alpha WCAG 2.2 AA

Quick Start β€’ Features β€’ Installation β€’ Usage β€’ API Reference β€’ Contributing


πŸ“– Overview

Accessible Math Reader (AMR) is a Python package and web application that makes mathematical notation accessible to visually impaired users. It parses LaTeX, MathML, and plaintext/Unicode math expressions and converts them into:

  • Natural language speech with configurable verbosity (verbose, concise, superbrief)
  • Braille notation in both Nemeth (US standard) and UEB (international standard)
  • Audio files via Google Text-to-Speech (gTTS)
  • ARIA-annotated HTML for keyboard-navigable, screen-reader-friendly exploration

AMR can be used as a Python library, a CLI tool, or through a Flask-based web interface.


✨ Features

Category Highlights
πŸ“– Multi-Format Input Parse LaTeX, MathML, and plaintext/Unicode math expressions with auto-detection
πŸ”Š Speech Output Natural language descriptions with 3 verbosity levels and SSML support
β Ώ Braille Support Full Nemeth Braille Code and Unified English Braille (UEB) converters
β™Ώ ARIA Navigation Keyboard-accessible, step-by-step expression exploration with 3 navigation modes
πŸ“‹ Multi-Format Clipboard Copy formulas as LaTeX, accessible text, or Braille from the web UI
🎨 Accessible Web UI Dark/light themes, high-contrast mode, zoom controls, screen-reader optimized
πŸ”Œ Plugin System Extensible architecture for custom speech rules, Braille notations, and input formats
⌨️ CLI Tool Full-featured command-line interface with interactive and batch modes

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Accessible Math Reader                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  CLI     β”‚  Web UI  β”‚       Python API (MathReader)  β”‚   Plugins    β”‚
β”‚  (amr)   β”‚  (Flask) β”‚                               β”‚  (extensible)β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                        Core Pipeline                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Parser  │──▸│ Semantic AST │──▸│        Renderers           β”‚  β”‚
β”‚  β”‚  LaTeX   β”‚   β”‚ (SemanticNodeβ”‚   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  MathML  β”‚   β”‚  NodeType)   β”‚   β”‚  β”‚ Speech  β”‚  Braille   β”‚  β”‚  β”‚
β”‚  β”‚ Plaintextβ”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚ Engine  β”‚ Nemeth/UEB β”‚  β”‚  β”‚
β”‚                        β”‚           β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚                        β–Ό           β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚  β”‚  ARIA   β”‚  Simple    β”‚  β”‚  β”‚
β”‚                  β”‚ Navigator β”‚     β”‚  β”‚Renderer β”‚  Text      β”‚  β”‚  β”‚
β”‚                  β”‚ (keyboard β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚                  β”‚  explore) β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                        Configuration                               β”‚
β”‚        Config  Β·  SpeechConfig  Β·  BrailleConfig  Β·  A11yConfig   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

accessible-math-reader/
β”œβ”€β”€ accessible_math_reader/       # πŸ“¦ Installable Python package
β”‚   β”œβ”€β”€ __init__.py               #    Public API exports
β”‚   β”œβ”€β”€ reader.py                 #    MathReader β€” high-level unified interface
β”‚   β”œβ”€β”€ cli.py                    #    CLI entry point (`amr` command)
β”‚   β”œβ”€β”€ config.py                 #    Configuration management (env, file, API)
β”‚   β”œβ”€β”€ core/                     #    Core parsing & rendering engine
β”‚   β”‚   β”œβ”€β”€ parser.py             #      LaTeX / MathML / Plaintext β†’ Semantic AST
β”‚   β”‚   β”œβ”€β”€ semantic.py           #      SemanticNode, NodeType, MathNavigator
β”‚   β”‚   β”œβ”€β”€ renderer.py           #      Base rendering infrastructure
β”‚   β”‚   β”œβ”€β”€ aria_navigator.py     #      ARIA-enhanced keyboard navigation
β”‚   β”‚   β”œβ”€β”€ aria_renderer.py      #      Accessible HTML generation
β”‚   β”‚   └── accessibility_contract.py  #  Accessibility validation contracts
β”‚   β”œβ”€β”€ speech/                   #    Speech output subsystem
β”‚   β”‚   β”œβ”€β”€ engine.py             #      TTS engine abstraction (gTTS backend)
β”‚   β”‚   └── rules.py              #      Verbosity-based speech rules
β”‚   β”œβ”€β”€ braille/                  #    Braille conversion subsystem
β”‚   β”‚   β”œβ”€β”€ nemeth.py             #      Nemeth Braille Code converter
β”‚   β”‚   └── ueb.py                #      Unified English Braille converter
β”‚   └── plugins/                  #    Plugin system
β”‚       └── base.py               #      Abstract plugin base classes
β”œβ”€β”€ app.py                        # 🌐 Flask web application entry point
β”œβ”€β”€ src/                          #    Legacy web-app helper modules
β”‚   β”œβ”€β”€ latex_parser.py           #      Regex-based LaTeX parser (for Flask UI)
β”‚   β”œβ”€β”€ braille_converter.py      #      Simple character-level Braille mapper
β”‚   └── speech_converter.py       #      gTTS wrapper for web UI
β”œβ”€β”€ templates/
β”‚   └── index.html                # πŸ–₯️  Web UI template (dark/light, accessible)
β”œβ”€β”€ static/
β”‚   β”œβ”€β”€ css/style.css             #    Web UI styles
β”‚   └── js/
β”‚       β”œβ”€β”€ app.js                #    Frontend logic & keyboard shortcuts
β”‚       └── clipboard.js          #    Multi-format clipboard support
β”œβ”€β”€ docs/                         # πŸ“š Documentation
β”‚   β”œβ”€β”€ api.md                    #    Full Python API reference
β”‚   β”œβ”€β”€ input-formats.md          #    Supported LaTeX & MathML syntax
β”‚   β”œβ”€β”€ accessibility.md          #    Screen reader, Braille & ARIA guide
β”‚   β”œβ”€β”€ configuration.md          #    Configuration reference
β”‚   └── examples.md               #    Code samples & use cases
β”œβ”€β”€ output/                       #    Sample Braille output files (.brf)
β”œβ”€β”€ pyproject.toml                #    Package metadata & build config
β”œβ”€β”€ requirements.txt              #    Web-app-specific dependencies
└── LICENSE                       #    MIT License

πŸš€ Installation

As a Python Package (Recommended)

Install directly from the repository:

# Clone the repository
git clone https://github.com/AndyFerns/Accessible-Math-Reader.git
cd Accessible-Math-Reader

# Create and activate a virtual environment
python -m venv venv
# Windows
venv\Scripts\activate
# Linux / macOS
source venv/bin/activate

# Install the package in editable mode (with all extras)
pip install -e ".[dev,web]"

This installs AMR as a package and registers the amr CLI command.

Minimal Install (Library Only)

If you only need the Python API (no web UI, no dev tools):

pip install -e .

Core dependencies are just gtts and lxml.

From PyPI (coming soon)

pip install accessible-math-reader

πŸ“‹ Usage

AMR provides three interfaces: a Python API, a CLI tool, and a web UI.

1. Python API

from accessible_math_reader import MathReader

reader = MathReader()

# ── Speech ──────────────────────────────────────────
speech = reader.to_speech(r"\frac{a}{b}")
print(speech)
# β†’ "start fraction a over b end fraction"

# ── Braille (Nemeth) ────────────────────────────────
braille = reader.to_braille(r"\frac{a}{b}", notation="nemeth")
print(braille)
# β†’ "β Ήβ β Œβ ƒβ Ό"

# ── Braille (UEB) ──────────────────────────────────
ueb = reader.to_braille(r"\frac{a}{b}", notation="ueb")

# ── Audio file ──────────────────────────────────────
reader.to_audio(r"\frac{a}{b}", "output.mp3")

# ── SSML markup ─────────────────────────────────────
ssml = reader.to_ssml(r"\sqrt{x}")

# ── Semantic tree inspection ────────────────────────
structure = reader.get_structure(r"\frac{a+b}{c}")

# ── Plaintext / Unicode math ────────────────────────
speech = reader.to_speech("xΒ² + yΒ² = zΒ²")
speech = reader.to_speech("(a+b)/(c-d)")
speech = reader.to_speech("sqrt(x) + Ο€")

Changing Verbosity

from accessible_math_reader import MathReader, VerbosityLevel

reader = MathReader()

reader.set_verbosity(VerbosityLevel.VERBOSE)
reader.to_speech(r"\frac{a}{b}")   # "start fraction a over b end fraction"

reader.set_verbosity(VerbosityLevel.CONCISE)
reader.to_speech(r"\frac{a}{b}")   # "a over b"

reader.set_verbosity(VerbosityLevel.SUPERBRIEF)
reader.to_speech(r"\frac{a}{b}")   # "fraction a b"

Custom Configuration

from accessible_math_reader import MathReader, Config
from accessible_math_reader.config import SpeechConfig, BrailleConfig, SpeechStyle, BrailleNotation

config = Config(
    speech=SpeechConfig(style=SpeechStyle.CONCISE, language="en", rate=0.9),
    braille=BrailleConfig(notation=BrailleNotation.UEB),
)

reader = MathReader(config)

Step-by-Step Navigation

nav = reader.get_navigator(r"\frac{a+b}{c}")
nav.enter()       # Drill into the fraction
nav.next()        # Move to the next sibling
nav.exit()        # Go back up to the parent
path = nav.get_path()  # Breadcrumb trail from root

2. Command-Line Interface (amr)

After installing the package, the amr command is available system-wide.

# Speech output (default)
amr "\frac{a^2 + b^2}{c}"

# Plaintext / Unicode math
amr "xΒ² + yΒ² = zΒ²"
amr "(a+b)/(c-d)"
amr "sqrt(x) + Ο€"

# Braille output (Nemeth)
amr --braille "\frac{a}{b}"

# Braille output (UEB)
amr --braille --notation ueb "\sqrt{x}"

# Generate audio file
amr --audio output.mp3 "\frac{1}{2}"

# SSML output
amr --ssml "\frac{a}{b}"

# JSON output (speech + braille + structure)
amr --json "\frac{a}{b}"

# Show expression tree structure
amr --structure "\frac{a+b}{c}"

# Set verbosity
amr --verbosity concise "x^2 + y^2 = z^2"

# Read from file (one expression per line)
amr --input equations.txt

# Write output to file
amr --output results.txt "\frac{a}{b}"

# Interactive REPL mode
amr --interactive

Interactive Mode Commands

Command Action
:quit / :exit Exit interactive mode
:verbosity <level> Set verbosity (verbose, concise, superbrief)
:braille Switch to Braille output
:speech Switch to speech output
:help Show all commands

3. Web Interface

The web UI provides a visual, accessible interface built with Flask:

# Install web dependencies
pip install -e ".[web]"

# Start the development server
python app.py

# Open http://localhost:5000

Web UI Features:

  • LaTeX / MathML / plaintext/Unicode input with live conversion
  • Tabbed output: Formula preview, Speech text, Braille, Accessible ARIA view
  • Multi-format clipboard (copy as LaTeX, plain text, or Braille)
  • Dark / Light / High-Contrast themes
  • Full keyboard navigation (Ctrl+Enter to convert, Alt+1–4 to switch tabs)
  • Screen-reader optimized with ARIA live regions

βš™οΈ Configuration

AMR supports three configuration methods (highest priority first):

1. Environment Variables

# Linux / macOS
export AMR_SPEECH_STYLE=concise        # verbose | concise | superbrief
export AMR_BRAILLE_NOTATION=nemeth     # nemeth | ueb
export AMR_SPEECH_LANGUAGE=en          # Language code
export AMR_PLUGIN_DIRS=/path/to/plugins

# Windows PowerShell
$env:AMR_SPEECH_STYLE = "concise"
$env:AMR_BRAILLE_NOTATION = "ueb"

2. JSON Config File

{
  "speech": {
    "style": "verbose",
    "language": "en",
    "rate": 1.0,
    "announce_structure": true
  },
  "braille": {
    "notation": "nemeth",
    "include_indicators": true
  },
  "accessibility": {
    "step_by_step": true,
    "announce_errors": true,
    "highlight_current": true
  }
}
config = Config.from_file("amr-config.json")
reader = MathReader(config)

3. Python API

config = Config()
config.speech.style = SpeechStyle.CONCISE
config.save("my-config.json")

πŸ“– Full configuration reference: docs/configuration.md


πŸ”Œ Plugin System

AMR's plugin architecture supports four extension points:

Plugin Type Base Class Purpose
Speech Rules SpeechRulesPlugin Custom verbalization rules for math constructs
Braille Notation BrailleNotationPlugin Additional Braille systems (French, German, etc.)
Input Format InputFormatPlugin New input parsers (AsciiMath, MathJSON, etc.)
Localization BasePlugin Language/locale-specific adaptations
from accessible_math_reader.plugins.base import SpeechRulesPlugin, PluginInfo, PluginType

class MyCustomRules(SpeechRulesPlugin):
    @property
    def info(self):
        return PluginInfo(
            name="my-rules",
            version="1.0.0",
            description="Custom speech rules",
            author="Your Name",
            plugin_type=PluginType.SPEECH_RULES,
        )

    def get_speech_rules(self):
        return {"FRACTION": lambda node: "custom fraction rendering"}

πŸ“š Documentation

Document Description
API Reference Full Python API with code examples
Input Formats Supported LaTeX commands and MathML elements
Accessibility Guide Screen reader, Braille display, and ARIA features
Configuration All speech, Braille, and accessibility settings
Examples Common use cases, batch processing, and web integration

Generating Documentation Locally

This project uses MkDocs with the Material theme for documentation hosting:

# Install documentation dependencies
pip install mkdocs mkdocs-material mkdocstrings[python]

# Serve docs locally (live reload)
mkdocs serve

# Build static site
mkdocs build

See mkdocs.yml for the full configuration.


🎯 Accessibility Compliance

Standard Status
WCAG 2.2 AA βœ… Full compliance for web interface
WAI-ARIA 1.2 βœ… Proper roles, labels, live regions, roving tabindex
Screen Readers βœ… Tested with NVDA, JAWS, VoiceOver, Narrator
Keyboard Navigation βœ… Full keyboard access, visible focus indicators
Braille Displays βœ… Unicode Braille output compatible with refreshable displays

πŸ§‘β€πŸ’» Development

Prerequisites

  • Python 3.9+
  • pip

Setup

git clone https://github.com/AndyFerns/Accessible-Math-Reader.git
cd Accessible-Math-Reader

python -m venv venv
venv\Scripts\activate          # Windows
# source venv/bin/activate     # Linux / macOS

pip install -e ".[dev,web]"

Running Tests

# Run full test suite with coverage
pytest tests/ -v --cov=accessible_math_reader --cov-report=term-missing

# Run a specific test file
pytest tests/test_parser.py -v

Linting

# Run ruff linter
ruff check accessible_math_reader/

# Auto-fix lint issues
ruff check accessible_math_reader/ --fix

Running the Web Server

python app.py
# Open http://localhost:5000

🀝 Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/your-feature
  3. Install dev dependencies: pip install -e ".[dev]"
  4. Make your changes and add tests
  5. Run the linter: ruff check accessible_math_reader/
  6. Run the tests: pytest tests/ -v
  7. Commit with a descriptive message
  8. Push to your fork and open a Pull Request

Areas Where Help Is Needed

  • 🌍 Localization: Speech rules for other languages
  • β Ώ Braille: Additional Braille notation systems (French, German, etc.)
  • πŸ§ͺ Testing: More unit tests, especially for edge-case math expressions
  • β™Ώ User Testing: Feedback from blind and low-vision users
  • πŸ“ Documentation: Tutorials, guides, and examples

πŸ“¦ Releasing as a Package

Building the Distribution

# Install build tool
pip install build

# Build source distribution and wheel
python -m build

# Output will be in dist/
#   dist/accessible_math_reader-0.1.0.tar.gz
#   dist/accessible_math_reader-0.1.0-py3-none-any.whl

Publishing to PyPI

# Install twine
pip install twine

# Upload to TestPyPI (for testing)
twine upload --repository testpypi dist/*

# Upload to PyPI (production)
twine upload dist/*

Installing from the Built Package

# From the wheel file
pip install dist/accessible_math_reader-0.1.0-py3-none-any.whl

# From TestPyPI
pip install --index-url https://test.pypi.org/simple/ accessible-math-reader

# From PyPI (once published)
pip install accessible-math-reader

πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.


πŸ™ Acknowledgments

  • gTTS β€” Google Text-to-Speech engine
  • lxml β€” XML/MathML parsing
  • Flask β€” Web framework
  • WCAG β€” Accessibility guidelines
  • Nemeth Braille Code β€” Mathematical Braille standard
  • UEB β€” Unified English Braille

Built with β™Ώ accessibility as a first-class priority.

About

A screen-reader-first mathematical accessibility toolkit for converting LaTeX, MathML, and plaintext/Unicode math into speech, Braille, and navigable ARIA structures.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors