NeMo
English
audio
speech
forced-alignment
reference-text-alignment
speech-processing
mfa
whisperx
python
metric:mae
Eval Results (legacy)
Instructions to use vertox-ai/speech-text-data-aligners with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- NeMo
How to use vertox-ai/speech-text-data-aligners with NeMo:
# tag did not correspond to a valid NeMo domain.
- Notebooks
- Google Colab
- Kaggle
File size: 4,119 Bytes
51e84d2 fc1dcbc | 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 | # License: Apache-2.0 License
# Created by: Patrick Lumbantobing, VertoX-AI
# Copyright (c) 2026 VertoX-AI. All rights reserved.
#
# This work is licensed under the Apache-2.0 License.
# To view a copy of this license, visit
# https://www.apache.org/licenses/LICENSE-2.0
"""Resolve safe WAV paths and probe lightweight PCM metadata with the standard library."""
from __future__ import annotations
import math
import wave
from dataclasses import dataclass
from pathlib import Path, PurePath
from speech_text_data_aligners.core.errors import AudioError
from speech_text_data_aligners.core.models import AlignmentRequest, Attributes
@dataclass(frozen=True, slots=True)
class WavInfo:
"""Describe lightweight WAV header facts needed by neutral services.
Parameters
----------
path: Probed WAV path.
frames: Audio frame count.
sample_rate_hz: Frames per second.
channels: Channel count.
sample_width_bytes: Bytes per sample per channel.
duration_s: Exact frame-count/sample-rate duration in seconds.
"""
path: Path
frames: int
sample_rate_hz: int
channels: int
sample_width_bytes: int
duration_s: float
def resolve_audio_path(audio_dir: Path, audio_id: str) -> Path:
"""Resolve an audio identifier strictly as ``<audio_dir>/<audio_id>.wav``.
Parameters
----------
audio_dir: Directory containing source WAVs.
audio_id: Metadata identifier without path components or extension.
Returns
-------
Lexically resolved WAV path; existence is checked by :func:`probe_wav`.
Raises
------
AudioError: If the identifier is empty, absolute, traversal-like, or contains
path separators.
"""
candidate = PurePath(audio_id)
if (
not audio_id
or audio_id in {".", ".."}
or candidate.is_absolute()
or candidate.name != audio_id
or "/" in audio_id
or "\\" in audio_id
):
raise AudioError("audio_id must be a non-empty path-component-free identifier")
return audio_dir / f"{audio_id}.wav"
def probe_wav(path: Path) -> WavInfo:
"""Read a local WAV header and calculate a finite positive duration.
Parameters
----------
path: WAV file to inspect.
Returns
-------
Immutable standard-library WAV facts.
Raises
------
AudioError: If the path is missing, unreadable, corrupt, empty, or has invalid
header dimensions.
"""
try:
with wave.open(str(path), "rb") as wav:
frames = wav.getnframes()
sample_rate = wav.getframerate()
channels = wav.getnchannels()
sample_width = wav.getsampwidth()
except (OSError, EOFError, wave.Error) as error:
raise AudioError(f"cannot read WAV audio: {path}") from error
if frames <= 0 or sample_rate <= 0 or channels <= 0 or sample_width <= 0:
raise AudioError(f"WAV has invalid or empty header values: {path}")
duration = frames / sample_rate
if not math.isfinite(duration) or duration <= 0:
raise AudioError(f"WAV duration is invalid: {path}")
return WavInfo(path, frames, sample_rate, channels, sample_width, duration)
def make_alignment_request(
*,
request_id: str,
audio_path: Path,
transcript: str,
context: Attributes = (),
) -> AlignmentRequest:
"""Probe a WAV and form a complete backend-neutral alignment request.
Parameters
----------
request_id: Caller-defined stable unique identity.
audio_path: Existing readable WAV path.
transcript: Exact authoritative transcript.
context: Immutable JSON-safe caller identifiers.
Returns
-------
Alignment request populated with the probed WAV duration.
Raises
------
AudioError: If WAV probing fails.
"""
info = probe_wav(audio_path)
return AlignmentRequest(
request_id=request_id,
audio_path=audio_path,
transcript=transcript,
audio_duration_s=info.duration_s,
context=context,
)
|