Skip to main content

Local CLI for extracting subtitles and aligned timestamps from audio and video.

Project description

echoalign-asr-mlx

easr is a local CLI for extracting subtitles and aligned timestamps from audio/video files.

It currently targets macOS + Apple Silicon and uses an MLX-based provider (Qwen3-ASR + Qwen3-ForcedAligner) behind a stable CLI interface.

Current Status

The project is implemented and runnable.

Current capabilities:

  • local file and directory processing
  • audio/video normalization to mono 16 kHz WAV
  • sentence-level and token-level export views
  • subtitle export to srt and vtt
  • rich JSON export (segments, tokens, provider metadata)
  • windowed transcription/alignment pipeline with diagnostics

Environment Requirements

  • OS: macOS on Apple Silicon
  • Python: >=3.14,<3.15
  • package installer: pip or uv pip
  • build tooling: uv (recommended)
  • system dependencies on PATH:
    • ffmpeg
    • ffprobe
  • network access on first run (model download from Hugging Face)

Default provider models:

Installation

  1. Install ffmpeg and ffprobe with your package manager.
  2. Install package dependencies with MLX extra.
python3.14 -m pip install ".[mlx]"

Alternative (uv-managed environment in project root):

uv sync --extra mlx
  1. Verify CLI is available.
easr --help

If you are using uv sync in the project checkout without installing into an active shell environment, run through uv:

uv run --python 3.14 --extra mlx easr --help

Python Package Distribution

Build source + wheel artifacts:

uv build

Install wheel in a target environment:

python3.14 -m pip install dist/echoalign_asr_mlx-0.1.0-py3-none-any.whl

For full transcription runtime, install with MLX extra:

python3.14 -m pip install ".[mlx]"

After publishing to an index (for example PyPI), end users can install with:

python3.14 -m pip install "echoalign-asr-mlx[mlx]"

GitHub Release to PyPI

This repository includes a publish workflow at:

  • .github/workflows/publish-pypi.yml

Release flow:

  1. Configure a Trusted Publisher in PyPI for this project:
    • project: echoalign-asr-mlx
    • owner/repo: your GitHub repository
    • workflow: publish-pypi.yml
    • environment: pypi
  2. Bump version in pyproject.toml.
  3. Create and publish a GitHub Release.
  4. GitHub Actions runs tests, builds distributions, and publishes to PyPI.

The workflow also supports manual trigger with workflow_dispatch.

Quick Start

The examples below use the installed easr command directly. If you are running from a project checkout with uv sync, prefix commands with:

uv run --python 3.14 --extra mlx easr ...

Single file

easr ./demo.mp4 --verbose

No input path (defaults to current directory)

easr

Directory (non-recursive by default)

easr ./media

Directory (recursive)

easr ./media --recursive --verbose

Glob pattern input

easr "./media/**/*.mp4" --recursive --verbose

CLI Reference

Help output:

usage: easr [-h] [--recursive] [--output-dir OUTPUT_DIR]
           [--granularity {sentence,token}] [--verbose]
           [inputs ...]

Arguments and flags:

  • inputs: file, directory, or glob pattern; defaults to current directory if omitted
  • --recursive: recurse when scanning directory inputs
  • --output-dir: override default output root
  • --granularity {sentence,token}:
    • sentence: subtitle entries come from segment boundaries
    • token: subtitle/JSON items are generated from tokens
  • --verbose: print detailed per-step timing and export <name>.metrics.json

Shell Completion (fish)

Generate fish completion script:

easr completion fish

Install fish completion script:

easr completion install fish

Install target path:

  • ~/.config/fish/completions/easr.fish
  • existing file is overwritten on install

Supported Input Formats

Audio:

  • wav
  • mp3
  • m4a
  • flac
  • aac

Video:

  • mp4
  • mov
  • m4v
  • mkv
  • webm

Output Files and Layout

For each input media file, the CLI writes:

  • <name>.srt
  • <name>.vtt
  • <name>.json
  • <name>.metrics.json (only when --verbose is enabled)

Default output directory name: outputs

Layout rules:

  • input is a directory/current directory:
    • output root defaults to <input_root>/outputs
  • input is a single file:
    • output root defaults to <file_parent>/outputs
  • recursive batch keeps relative directory structure
  • --output-dir overrides output root

Example:

/project/media/
  a.mp4
  nested/b.wav

/project/media/outputs/
  a.srt
  a.vtt
  a.json
  nested/b.srt
  nested/b.vtt
  nested/b.json

JSON Contract (Practical)

json output includes:

  • top-level transcription document:
    • source_path
    • provider_name
    • detected_language
    • segments
    • source_media
  • export view:
    • granularity
    • items

source_media currently includes:

  • prepared_audio_path
  • provider_metadata:
    • processing_strategy
    • window_count
    • duration_sec
    • quality_pass_count
    • failed_window_count
    • window_diagnostics

Real E2E Example (Current Repo)

Command used in this repository:

uv run --python 3.14 --extra mlx easr tests/e2e/test1.mov --verbose

Observed output files:

  • tests/e2e/outputs/test1.srt
  • tests/e2e/outputs/test1.vtt
  • tests/e2e/outputs/test1.json

Observed sample stats from test1.json:

  • window_count: 3
  • failed_window_count: 0
  • segments: ~49 (depends on current alignment behavior/model output)

Sample subtitle excerpt:

00:00:09,600 --> 00:00:17,640
But despite all the buzz and hype, one of the things that's still underestimated by many people is their power as a developer too.

Common Commands

Run unit tests

PYTHONPATH=src uv run --python 3.14 python -m unittest discover -s tests -p 'test_*.py'

Run a single focused test

PYTHONPATH=src uv run --python 3.14 python -m unittest tests.test_authority

Dry-check CLI parsing/help

uv run --python 3.14 easr --help

Token-level subtitle export

uv run --python 3.14 --extra mlx easr ./demo.mp4 --granularity token --verbose

Export verbose metrics JSON for optimization

uv run --python 3.14 --extra mlx easr ./demo.mp4 --verbose

Runtime Flow (What Happens Internally)

For each media file:

  1. CLI discovers supported inputs (file/dir/glob).
  2. Environment preflight validates:
    • ffmpeg and ffprobe availability
    • MLX/Metal basic runtime check
    • progress starts rendering in terminal (single-line by default)
  3. Media is normalized to mono 16 kHz WAV.
  4. Provider runs windowed ASR + alignment.
  5. Results are exported to srt, vtt, and json.
  6. When --verbose is enabled, <name>.metrics.json is also exported.

Exit Codes and Runtime Behavior

  • 0: all discovered files processed successfully
  • 1: no supported input found, preflight failed, or at least one file failed in batch

Batch behavior:

  • files are processed one-by-one
  • failures are reported per file to stderr
  • other files continue processing

Troubleshooting

[easr] environment check failed: Missing required media dependency...

Cause: ffmpeg and/or ffprobe not found on PATH.

Fix:

  • install both binaries
  • ensure they are visible in the shell used to run easr

[easr] environment check failed: MLX/Metal preflight failed...

Cause: MLX runtime could not initialize Metal backend (or crashed during preflight).

Fix:

  • verify Apple Silicon + supported macOS runtime
  • re-check Python/venv and mlx dependency installation
  • retry from a clean shell/session

First run is slow

Cause: model download and cache warm-up.

Fix:

  • expected on first run
  • later runs should be faster after cache is populated

Notes and Scope

  • translation is out of scope in current phase
  • speaker diarization is not implemented
  • subtitle segmentation quality depends on model + alignment behavior
  • provider abstraction is in place for future backend extension

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

echoalign_asr_mlx-0.2.0.tar.gz (101.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

echoalign_asr_mlx-0.2.0-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file echoalign_asr_mlx-0.2.0.tar.gz.

File metadata

  • Download URL: echoalign_asr_mlx-0.2.0.tar.gz
  • Upload date:
  • Size: 101.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for echoalign_asr_mlx-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ca8c201c732aa5e9b08d1aa6411dce624f93dc065c3ab36a7e8b567f2b6c7aaf
MD5 6bef78669ce1550daa106344d08c6793
BLAKE2b-256 86c0d94b08774788197113caacc3a30c3ca023cdbfe4c153099f0bf921b0bb06

See more details on using hashes here.

Provenance

The following attestation bundles were made for echoalign_asr_mlx-0.2.0.tar.gz:

Publisher: publish-pypi.yml on morehardy/ASR

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file echoalign_asr_mlx-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for echoalign_asr_mlx-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1cb123798fff48e46805ee43540ccf4d0a6d9f1d3e0f30cc233c25fe7679b19a
MD5 553b5375893e4e7ca2b0f833b7ea9ae9
BLAKE2b-256 06026cdc77e2760c380746736d6269f8dff75e7528d7919f73c8498a492895e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for echoalign_asr_mlx-0.2.0-py3-none-any.whl:

Publisher: publish-pypi.yml on morehardy/ASR

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page