File size: 7,333 Bytes
51e84d2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | # Architecture
Speech-Text Data Aligners is a library-first forced-alignment framework. The core
contract accepts WAV audio plus a known, authoritative transcript and returns
backend-neutral timed words. The CLI is only a composition and presentation layer.
The mandatory design rules are defined in the
[modular architecture contract](MODULAR_ARCHITECTURE_CONTRACT.md) and the
[aligner engineering contract](ALIGNER_ENGINEERING_CONTRACT.md).
## Layers and Dependency Direction
```text
CLI --------------------> Application --------------------> Core
| ^
+----------> Data -------------+
+----------> Benchmarking -----+
+----------> Runtime ----------+
CLI -- lazy composition --> Concrete Backends
| |
+------------> Core
+------------> Runtime
```
In compact form:
```text
CLI -> Application -> Core
-> Data
-> Benchmarking
-> Runtime
Concrete Backends -> Core / Runtime
```
The enforced consequences are:
- Core does not import application, data, benchmarking, CLI, or concrete backends.
- Data and benchmarking do not depend on concrete backends.
- Application services receive an `AlignmentBackend` protocol instance; they do not
branch on NeMo, MFA, or WhisperX names.
- Concrete backend packages do not import one another.
- The registry stores lazy dotted factories so unavailable optional runtimes do not
break backend-neutral imports or sibling backends.
- The CLI delegates annotation and benchmarking to reusable Python services.
## Current Package Tree
```text
src/speech_text_data_aligners/
|-- __init__.py public backend-neutral facade
|-- application/
| |-- annotate.py annotation orchestration and publication policy
| `-- benchmark.py identical-request benchmark orchestration
|-- backends/
| |-- registry.py immutable lazy backend composition
| |-- nemo/
| | |-- backend.py neutral adapter
| | |-- config.py typed configuration
| | |-- manifest.py reference JSONL and output-manifest parsing
| | |-- runner.py isolated NFA execution
| | `-- ctm.py word CTM parsing and mapping
| |-- mfa/
| | |-- backend.py neutral adapter
| | |-- config.py typed configuration
| | |-- corpus.py temporary WAV/LAB corpus
| | |-- runner.py isolated MFA execution
| | `-- textgrid.py word-tier parsing and mapping
| `-- whisperx/
| |-- backend.py neutral adapter
| |-- config.py typed configuration
| |-- segments.py full-WAV authoritative segments
| |-- provider.py isolated-worker transport
| |-- worker.py lazy heavyweight native runtime
| `-- parser.py native word-dictionary parsing and mapping
|-- benchmarking/
| |-- metrics.py sparse-gold and pairwise metrics
| `-- reports.py JSON/CSV/Markdown report rendering
|-- cli/
| |-- main.py command dispatch
| |-- annotate.py annotation argument adapter
| `-- benchmark.py benchmark argument adapter
|-- core/
| |-- models.py immutable neutral values and provenance
| |-- protocols.py injected backend contracts
| |-- errors.py project exception taxonomy
| |-- normalization.py lexical plans and monotonic reconciliation
| |-- validation.py result and publication-path invariants
| `-- extraction.py six first/last output fields
|-- data/
| |-- audio.py WAV resolution and lightweight probing
| `-- metadata.py preserving, atomic CSV I/O
`-- runtime/
|-- process.py shell-free injected subprocess boundary
|-- artifacts.py temporary and retained artifact lifecycle
`-- receipts.py hashes and run provenance
```
Package-marker `__init__.py` files not shown above are deliberately empty. The root
`__init__.py` is the tested public facade.
## Backend Isolation and Native Containment
```text
PARENT PROCESS
Python caller or CLI
|
v
backend-neutral application API
|
v
AlignmentBackend protocol
|
v
concrete adapter (NeMo | MFA | WhisperX)
|
| injected process/provider boundary
v
+------------------------------------------------------+
| ISOLATED NATIVE RUNTIME |
| NeMo NFA process | MFA process | WhisperX worker |
| Heavy optional dependencies and model lifecycle |
+------------------------------------------------------+
|
| native files / native dictionaries
v
adapter-local builder, parser, and reconciliation
|
| only neutral records cross this point
v
AlignmentResult | AlignmentFailure | diagnostics | provenance
```
NeMo manifests, output manifests, and CTM rows remain inside
`backends.nemo`. MFA corpus labels and TextGrid objects remain inside
`backends.mfa`. WhisperX segment payloads and native result dictionaries remain
inside `backends.whisperx`. NeMo CTM, MFA TextGrid, and WhisperX native dictionaries
never escape their adapters; callers receive only backend-neutral models.
The parent process does not import heavyweight NeMo, MFA, WhisperX, Torch, or
Torchaudio packages. NeMo and MFA run through the shared shell-free process boundary.
WhisperX runs in a dedicated worker that imports its heavy stack only after invocation.
## Transcript-to-Result Data Flow
```text
authoritative transcript
|
v
backend-specific reference representation
|
v
native timed words
|
v
shared monotonic reconciliation
|
v
shared validation
|
v
AlignmentResult
```
The authoritative `en_transcript` remains unchanged throughout. A backend may
normalize or expand text only through a reversible plan that retains ownership of
original lexical words. Shared reconciliation requires complete monotonic coverage,
and shared validation rejects non-finite, negative, reversed, overlapping, incomplete,
or out-of-audio timestamps. It never clamps, interpolates, or invents a timestamp.
## Reuse and Composition
The root facade exposes reusable annotation and benchmark services. Applications may
inject any object satisfying `AlignmentBackend`, including a lightweight test or
custom backend. The default registry is a convenience for the CLI, not a dependency of
the application layer.
Benchmarking consumes the same neutral results as annotation. Native parsing,
transcript mapping, CSV I/O, metric calculation, report rendering, and process
execution each have one owning layer, so adding another adapter does not require
changes to established backend-neutral behavior.
Architecture is enforced by deterministic AST tests and Import Linter contracts. The
accepted audit and complete dependency evidence are recorded in the
[Stage 5 final acceptance report](STAGE_5_FINAL_ACCEPTANCE_REPORT.md).
|