altasr 1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- altasr-1/PKG-INFO +428 -0
- altasr-1/PYPI_README.md +393 -0
- altasr-1/README.md +186 -0
- altasr-1/altasr/__init__.py +92 -0
- altasr-1/altasr/audio.py +208 -0
- altasr-1/altasr/benchmark.py +374 -0
- altasr-1/altasr/config.py +245 -0
- altasr-1/altasr/export.py +152 -0
- altasr-1/altasr/inference/__init__.py +44 -0
- altasr-1/altasr/inference/checkpoint.py +111 -0
- altasr-1/altasr/inference/decoding.py +304 -0
- altasr-1/altasr/inference/evaluate.py +194 -0
- altasr-1/altasr/inference/pool.py +159 -0
- altasr-1/altasr/inference/streaming.py +247 -0
- altasr-1/altasr/inference/transcribe.py +88 -0
- altasr-1/altasr/inference/transcriber.py +331 -0
- altasr-1/altasr/integrations/__init__.py +3 -0
- altasr-1/altasr/integrations/llm.py +231 -0
- altasr-1/altasr/lm.py +266 -0
- altasr-1/altasr/metrics.py +126 -0
- altasr-1/altasr/model/__init__.py +29 -0
- altasr-1/altasr/model/attention.py +104 -0
- altasr-1/altasr/model/block.py +66 -0
- altasr-1/altasr/model/convolution.py +59 -0
- altasr-1/altasr/model/ctc.py +104 -0
- altasr-1/altasr/model/encoder.py +109 -0
- altasr-1/altasr/model/feedforward.py +27 -0
- altasr-1/altasr/model/positional.py +75 -0
- altasr-1/altasr/model/subsampling.py +40 -0
- altasr-1/altasr/text.py +313 -0
- altasr-1/altasr/training/__init__.py +36 -0
- altasr-1/altasr/training/data.py +329 -0
- altasr-1/altasr/training/finetune.py +226 -0
- altasr-1/altasr/training/prepare.py +101 -0
- altasr-1/altasr/training/train.py +248 -0
- altasr-1/altasr/training/trainer.py +488 -0
- altasr-1/altasr/utils.py +154 -0
- altasr-1/altasr.egg-info/PKG-INFO +428 -0
- altasr-1/altasr.egg-info/SOURCES.txt +43 -0
- altasr-1/altasr.egg-info/dependency_links.txt +1 -0
- altasr-1/altasr.egg-info/entry_points.txt +9 -0
- altasr-1/altasr.egg-info/requires.txt +26 -0
- altasr-1/altasr.egg-info/top_level.txt +1 -0
- altasr-1/pyproject.toml +57 -0
- altasr-1/setup.cfg +4 -0
altasr-1/PKG-INFO
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: altasr
|
|
3
|
+
Version: 1
|
|
4
|
+
Summary: ALTASR: a scalable, streaming-ready Conformer-CTC speech recognition toolkit, built for Kinyarwanda and reusable for any language.
|
|
5
|
+
Author: YaliLabs / ALTA Project
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/yalilabs/altasr
|
|
8
|
+
Keywords: speech-recognition,asr,kinyarwanda,conformer,ctc,streaming,live-captioning,low-resource
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: torch>=2.3
|
|
15
|
+
Requires-Dist: torchaudio>=2.3
|
|
16
|
+
Requires-Dist: numpy>=1.24
|
|
17
|
+
Requires-Dist: soundfile>=0.12
|
|
18
|
+
Requires-Dist: av>=11.0
|
|
19
|
+
Requires-Dist: tqdm>=4.66
|
|
20
|
+
Provides-Extra: bpe
|
|
21
|
+
Requires-Dist: sentencepiece>=0.1.99; extra == "bpe"
|
|
22
|
+
Provides-Extra: onnx
|
|
23
|
+
Requires-Dist: onnx>=1.15; extra == "onnx"
|
|
24
|
+
Requires-Dist: onnxruntime>=1.17; extra == "onnx"
|
|
25
|
+
Provides-Extra: whisper
|
|
26
|
+
Requires-Dist: faster-whisper>=1.0; extra == "whisper"
|
|
27
|
+
Provides-Extra: mic
|
|
28
|
+
Requires-Dist: sounddevice>=0.4; extra == "mic"
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: sentencepiece>=0.1.99; extra == "all"
|
|
31
|
+
Requires-Dist: onnx>=1.15; extra == "all"
|
|
32
|
+
Requires-Dist: onnxruntime>=1.17; extra == "all"
|
|
33
|
+
Requires-Dist: faster-whisper>=1.0; extra == "all"
|
|
34
|
+
Requires-Dist: sounddevice>=0.4; extra == "all"
|
|
35
|
+
|
|
36
|
+
# ALTASR
|
|
37
|
+
|
|
38
|
+
**Scalable, streaming-ready speech recognition — built for Kinyarwanda, reusable for any language.**
|
|
39
|
+
|
|
40
|
+
ALTASR is a Conformer-CTC automatic speech recognition (ASR) toolkit by the
|
|
41
|
+
ALTA Project (YaliLabs). It covers the full lifecycle — data preparation,
|
|
42
|
+
training, fine-tuning, evaluation, benchmarking, streaming inference, and
|
|
43
|
+
edge deployment — behind a small, consistent API and a set of one-line CLIs.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install altasr
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
That single command installs everything needed for training and inference
|
|
50
|
+
(PyTorch, torchaudio, audio codecs). Optional features are extras:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install altasr[bpe] # subword (BPE) tokenizer
|
|
54
|
+
pip install altasr[onnx] # ONNX export for edge / CPU runtimes
|
|
55
|
+
pip install altasr[whisper] # Whisper baselines for benchmarking
|
|
56
|
+
pip install altasr[mic] # live microphone streaming
|
|
57
|
+
pip install altasr[all] # everything
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
**Full reference** (dataset format, every CLI parameter, multi-GPU,
|
|
63
|
+
web integration): [docs/USAGE.md](https://github.com/yalilabs/altasr/blob/main/docs/USAGE.md)
|
|
64
|
+
|
|
65
|
+
## Highlights
|
|
66
|
+
|
|
67
|
+
- **Modern Conformer-CTC encoder** with relative positional attention,
|
|
68
|
+
intermediate CTC regularization, and stochastic depth — accuracy keeps
|
|
69
|
+
improving as you scale data and model size.
|
|
70
|
+
- **True streaming**: chunked-attention models plus a `StreamingSession`
|
|
71
|
+
API and `altasr-stream` CLI for live captioning from files or microphone.
|
|
72
|
+
- **Punctuation-aware**: the tokenizer and normalization keep punctuation,
|
|
73
|
+
so transcripts come out readable (`ndashaka amazi, urakoze.`).
|
|
74
|
+
- **Smart on your domain, automatically**: training builds an n-gram LM
|
|
75
|
+
+ word lexicon from *your transcripts* and ships them in the checkpoint;
|
|
76
|
+
beam decoding uses them so corpus terms ("DGX", names, places) come out
|
|
77
|
+
right with **no hardcoded lists**. Hotwords remain for never-seen terms.
|
|
78
|
+
- **Your choice of decoder**: `decoder="auto"|"greedy"|"beam"` everywhere —
|
|
79
|
+
auto picks the best default (beam for single files, greedy for bulk and
|
|
80
|
+
streaming); explicit choices always win.
|
|
81
|
+
- **LLM & agent ready**: structured results (confidence + word
|
|
82
|
+
timestamps), an OpenAI tool schema so agents can call ASR as a tool,
|
|
83
|
+
and optional LLM post-correction through any OpenAI-compatible
|
|
84
|
+
endpoint (`SmartTranscriber` runs the whole pipeline).
|
|
85
|
+
- **Any language**: build a tokenizer (char or BPE) directly from *your*
|
|
86
|
+
dataset; nothing is Kinyarwanda-specific except the released checkpoints.
|
|
87
|
+
- **Robust to imperfect data**: speed perturbation, SpecAugment, and
|
|
88
|
+
capacity-scaled regularization are on by default; unreadable/corrupt
|
|
89
|
+
files are skipped with a warning instead of crashing a training run.
|
|
90
|
+
- **Efficient everywhere**: int8 dynamic quantization for CPU, ONNX export
|
|
91
|
+
for edge devices, bucketed batching and AMP for GPU training.
|
|
92
|
+
- **Fine-tuning pipeline**: adapt a trained checkpoint to a new dataset (or
|
|
93
|
+
a new language) in one command, with tokenizer extension and layer freezing.
|
|
94
|
+
- **Professional benchmarking**: compare your checkpoints against Whisper
|
|
95
|
+
and generate a Markdown/HTML report with WER, CER, error breakdowns and RTF.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Quickstart: transcribe an audio file
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from altasr import Transcriber
|
|
103
|
+
|
|
104
|
+
asr = Transcriber.from_pretrained("path/to/checkpoint")
|
|
105
|
+
text = asr.transcribe("recording.mp3")
|
|
106
|
+
print(text)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
With error handling for real applications:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from pathlib import Path
|
|
113
|
+
from altasr import Transcriber
|
|
114
|
+
|
|
115
|
+
def safe_transcribe(checkpoint: str, audio_path: str) -> str | None:
|
|
116
|
+
try:
|
|
117
|
+
asr = Transcriber.from_pretrained(checkpoint)
|
|
118
|
+
except FileNotFoundError:
|
|
119
|
+
print(f"Checkpoint not found: {checkpoint}")
|
|
120
|
+
return None
|
|
121
|
+
except ImportError as e:
|
|
122
|
+
print(f"Missing dependency: {e}") # e.g. torch not installed
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
if not Path(audio_path).exists():
|
|
126
|
+
print(f"Audio file not found: {audio_path}")
|
|
127
|
+
return None
|
|
128
|
+
try:
|
|
129
|
+
return asr.transcribe(audio_path)
|
|
130
|
+
except Exception as e: # unreadable / corrupt audio
|
|
131
|
+
print(f"Could not transcribe {audio_path}: {e}")
|
|
132
|
+
return None
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Command line:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
altasr-transcribe --checkpoint runs/my_model --audio recording.mp3
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Scenario: get domain terms right (hotwords) + structured output
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
text = asr.transcribe("meeting.mp3") # auto = beam + learned LM/lexicon
|
|
145
|
+
text = asr.transcribe("meeting.mp3", decoder="greedy") # fastest, explicit
|
|
146
|
+
text = asr.transcribe("meeting.mp3", # + hotwords for terms
|
|
147
|
+
hotwords=["NewClientName"]) # not in training data
|
|
148
|
+
|
|
149
|
+
res = asr.transcribe_detailed("meeting.mp3")
|
|
150
|
+
res.decoder # e.g. "beam+lm+lexfix" — shows what fired
|
|
151
|
+
res.text, res.confidence # "twaguze DGX nshya.", 0.94
|
|
152
|
+
res.words[0] # Word(word='twaguze', start=0.12, end=0.58, confidence=0.97)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
altasr-transcribe --checkpoint CKPT --audio meeting.mp3 --hotwords "DGX,H200" --detailed
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Scenario: LLM pipelines and agents
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from altasr import Transcriber, LLMCorrector, SmartTranscriber
|
|
163
|
+
|
|
164
|
+
asr = Transcriber.from_pretrained("runs/my_model/best")
|
|
165
|
+
smart = SmartTranscriber(
|
|
166
|
+
asr, hotwords=["DGX", "YaliLabs"], beam_size=8,
|
|
167
|
+
corrector=LLMCorrector(base_url="http://localhost:11434/v1",
|
|
168
|
+
model="llama3.1")) # any OpenAI-compatible API
|
|
169
|
+
result = smart.transcribe("meeting.mp3") # dict: text, asr_text,
|
|
170
|
+
# confidence, words, ...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Let an LLM agent call ASR as a tool (OpenAI function calling):
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from altasr import ASR_TOOL_SCHEMA, handle_tool_call
|
|
177
|
+
resp = client.chat.completions.create(model=..., messages=msgs,
|
|
178
|
+
tools=[ASR_TOOL_SCHEMA])
|
|
179
|
+
result = handle_tool_call(asr, resp.choices[0].message.tool_calls[0].function.arguments)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Full agent loop, design notes, and streaming-agent guidance:
|
|
183
|
+
[docs/USAGE.md](https://github.com/yalilabs/altasr/blob/main/docs/USAGE.md#8-agentic-integration-asr-as-an-llm-tool).
|
|
184
|
+
|
|
185
|
+
## Scenario: CPU / edge deployment
|
|
186
|
+
|
|
187
|
+
Quantize to int8 at load time (CPU only, ~4x smaller Linear layers, faster):
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
asr = Transcriber.from_pretrained("runs/my_model", device="cpu", quantize="int8")
|
|
191
|
+
print(asr.transcribe("recording.wav"))
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Or export to ONNX for onnxruntime / mobile:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
pip install altasr[onnx]
|
|
198
|
+
altasr-export runs/my_model --format onnx --out deploy/model.onnx
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The exporter writes `model.onnx`, a `model.json` metadata sidecar
|
|
202
|
+
(sample rate, mel settings, vocabulary), and copies `tokenizer.json` next to
|
|
203
|
+
it, so the deployment folder is self-contained.
|
|
204
|
+
|
|
205
|
+
## Scenario: live captioning (streaming)
|
|
206
|
+
|
|
207
|
+
Train or download a `streaming` preset checkpoint, then:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# From a file, paced in real time (add --fast to run as fast as possible)
|
|
211
|
+
altasr-stream --checkpoint runs/streaming_model --audio talk.wav
|
|
212
|
+
|
|
213
|
+
# From the microphone (pip install altasr[mic])
|
|
214
|
+
altasr-stream --checkpoint runs/streaming_model --mic --quantize int8
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
In Python:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from altasr import Transcriber
|
|
221
|
+
|
|
222
|
+
asr = Transcriber.from_pretrained("runs/streaming_model")
|
|
223
|
+
session = asr.stream(chunk_seconds=0.6)
|
|
224
|
+
|
|
225
|
+
for chunk in audio_chunks: # your capture loop: 1-D float32 @ 16 kHz
|
|
226
|
+
new_text = session.push(chunk)
|
|
227
|
+
if new_text:
|
|
228
|
+
print(new_text, end="", flush=True)
|
|
229
|
+
print(session.finish())
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Offline (non-streaming) checkpoints also work with `altasr-stream`, but a
|
|
233
|
+
`streaming`-preset model is trained with chunked attention and causal
|
|
234
|
+
convolutions, so its live accuracy is much closer to its offline accuracy.
|
|
235
|
+
|
|
236
|
+
## Scenario: train on your own dataset (any language)
|
|
237
|
+
|
|
238
|
+
Metadata is JSON/JSONL/CSV/TSV with an audio path and a transcript per row.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
altasr-train \
|
|
242
|
+
--preset medium \
|
|
243
|
+
--audio-root /data/my_corpus \
|
|
244
|
+
--train /data/my_corpus/train.json \
|
|
245
|
+
--val /data/my_corpus/dev.json \
|
|
246
|
+
--tokenizer bpe --bpe-vocab-size 1024 \
|
|
247
|
+
--out-dir runs/my_model
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
- The tokenizer (char by default, BPE with `--tokenizer bpe`) is built
|
|
251
|
+
**from your training transcripts**, so any language works out of the box.
|
|
252
|
+
- Punctuation is kept by default; pass `--no-punctuation` for bare text.
|
|
253
|
+
- Presets: `small` (~7M params), `medium` (~23M), `large` (~118M),
|
|
254
|
+
`streaming` (medium-sized, chunked attention for live use).
|
|
255
|
+
- Training auto-resumes from the last checkpoint in `--out-dir`.
|
|
256
|
+
|
|
257
|
+
**Dataset format** — metadata is any of: a JSON list of
|
|
258
|
+
`{"audio_path": ..., "text": ...}` objects, a JSON dict keyed by utterance
|
|
259
|
+
id, JSON-lines, or CSV with a header. Common field names are auto-detected
|
|
260
|
+
(`audio_path`/`path`/`file`/`audio` for audio; `text`/`sentence`/
|
|
261
|
+
`transcription`/`transcript` for the transcript; optional `duration`).
|
|
262
|
+
Audio can be wav/mp3/flac/ogg/m4a/… at any sample rate — ALTASR resamples
|
|
263
|
+
internally. Validate your dataset in seconds with `--dry-run`. Full details
|
|
264
|
+
and a worked formatting example: [docs/USAGE.md](https://github.com/yalilabs/altasr/blob/main/docs/USAGE.md#1-dataset-format).
|
|
265
|
+
|
|
266
|
+
**Multi-GPU** — same command, launched with `torchrun` (one process per
|
|
267
|
+
GPU; gradients are averaged automatically; checkpoints/logs come from GPU 0
|
|
268
|
+
only). On a 2-GPU machine (e.g. 2×H200):
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
torchrun --standalone --nproc_per_node=2 -m altasr.training.train \
|
|
272
|
+
--preset medium --audio-root /data/my_corpus \
|
|
273
|
+
--train /data/my_corpus/train.json --val /data/my_corpus/dev.json \
|
|
274
|
+
--out-dir runs/my_model_2gpu
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Works on any CUDA GPU generation PyTorch supports (Ampere, Hopper
|
|
278
|
+
H100/H200, Blackwell, ...): bf16 and TF32 are enabled by capability
|
|
279
|
+
detection, not hard-coded lists. `--batch-size` and `--num-workers` are
|
|
280
|
+
per GPU. See [docs/USAGE.md](https://github.com/yalilabs/altasr/blob/main/docs/USAGE.md#3-multi-gpu-training-2-gpus-h200-etc) for scaling guidance.
|
|
281
|
+
|
|
282
|
+
**Multi-GPU inference** works too — shard bulk transcription or
|
|
283
|
+
evaluation across GPUs:
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
from altasr import TranscriberPool
|
|
287
|
+
pool = TranscriberPool.from_pretrained("runs/my_model/best") # all GPUs
|
|
288
|
+
texts = pool.transcribe_batch(list_of_files) # ~N x faster on N GPUs
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
altasr-evaluate --checkpoint runs/my_model/best --device all-gpus \
|
|
293
|
+
--audio-root /data/test --metadata /data/test/test.json
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`TranscriberPool` is thread-safe (per-device scheduling), so it drops
|
|
297
|
+
straight into the web-server examples below in place of `Transcriber`.
|
|
298
|
+
|
|
299
|
+
For large corpora, precompute mel features once:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
altasr-prepare-data --audio-root /data/my_corpus \
|
|
303
|
+
--metadata /data/my_corpus/train.json --out-dir /data/mels
|
|
304
|
+
altasr-train ... --features mel --features-dir /data/mels
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Scenario: fine-tune an existing model on new data
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
altasr-finetune \
|
|
311
|
+
--checkpoint runs/my_model \
|
|
312
|
+
--audio-root /data/new_domain \
|
|
313
|
+
--train /data/new_domain/train.json \
|
|
314
|
+
--val /data/new_domain/dev.json \
|
|
315
|
+
--out-dir runs/my_model_medical \
|
|
316
|
+
--freeze-layers 8
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
- The tokenizer is **extended** with characters found in the new data
|
|
320
|
+
(old token ids stay stable; the CTC head is resized automatically).
|
|
321
|
+
Disable with `--no-extend-tokenizer`.
|
|
322
|
+
- `--freeze-layers N` freezes the feature extractor and the first N encoder
|
|
323
|
+
blocks — fast, stable adaptation on small datasets.
|
|
324
|
+
- Sensible defaults: `--lr 1e-4`, `--epochs 5`, short warmup.
|
|
325
|
+
|
|
326
|
+
## Scenario: evaluate and benchmark
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# Rich evaluation of one checkpoint
|
|
330
|
+
altasr-evaluate --checkpoint runs/my_model \
|
|
331
|
+
--audio-root /data/test --metadata /data/test/test.json --json eval.json
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Reported metrics: WER, CER, WER without punctuation, substitution /
|
|
335
|
+
deletion / insertion rates, and real-time factor (RTF).
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Professional comparison report (Markdown + optional HTML + JSON)
|
|
339
|
+
pip install altasr[whisper]
|
|
340
|
+
altasr-benchmark \
|
|
341
|
+
--checkpoint "ALTASR medium=runs/my_model" \
|
|
342
|
+
--checkpoint "ALTASR small=runs/small" \
|
|
343
|
+
--whisper small --whisper large-v3 \
|
|
344
|
+
--audio-root /data/test --metadata /data/test/test.json \
|
|
345
|
+
--out benchmark/report.md --html
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The report includes a methodology section, a results table (params, WER,
|
|
349
|
+
CER, error breakdown, RTF), per-system notes, and the hardest utterances —
|
|
350
|
+
ready to share with stakeholders.
|
|
351
|
+
|
|
352
|
+
## Scenario: serve ALTASR from a web app (FastAPI / Flask / Django)
|
|
353
|
+
|
|
354
|
+
Load the model **once at startup**, guard it with a lock, transcribe in a
|
|
355
|
+
worker thread. Minimal FastAPI service:
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
import asyncio, os, tempfile
|
|
359
|
+
from fastapi import FastAPI, File, HTTPException, UploadFile
|
|
360
|
+
from altasr import Transcriber
|
|
361
|
+
|
|
362
|
+
app = FastAPI()
|
|
363
|
+
asr = Transcriber.from_pretrained("runs/my_model/best")
|
|
364
|
+
lock = asyncio.Lock()
|
|
365
|
+
|
|
366
|
+
@app.post("/transcribe")
|
|
367
|
+
async def transcribe(file: UploadFile = File(...)):
|
|
368
|
+
suffix = os.path.splitext(file.filename or "a")[1] or ".wav"
|
|
369
|
+
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
|
|
370
|
+
tmp.write(await file.read()); path = tmp.name
|
|
371
|
+
try:
|
|
372
|
+
async with lock:
|
|
373
|
+
return {"text": await asyncio.to_thread(asr.transcribe, path)}
|
|
374
|
+
except Exception as exc:
|
|
375
|
+
raise HTTPException(422, f"could not transcribe: {exc}")
|
|
376
|
+
finally:
|
|
377
|
+
os.unlink(path)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
pip install fastapi uvicorn python-multipart
|
|
382
|
+
uvicorn app:app --port 8000
|
|
383
|
+
curl -F "file=@recording.mp3" http://localhost:8000/transcribe
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Complete examples — including a **WebSocket live-captioning endpoint**,
|
|
387
|
+
Flask, Django, and production sizing notes — are in
|
|
388
|
+
[docs/USAGE.md](https://github.com/yalilabs/altasr/blob/main/docs/USAGE.md#5-connecting-altasr-to-a-web-application).
|
|
389
|
+
|
|
390
|
+
## Checkpoint format
|
|
391
|
+
|
|
392
|
+
A checkpoint is a plain folder — easy to version, copy, and deploy:
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
runs/my_model/
|
|
396
|
+
├── config.json # full architecture + training config
|
|
397
|
+
├── tokenizer.json # vocabulary (char or BPE), normalization settings
|
|
398
|
+
└── model.pt # weights
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
`Transcriber.from_pretrained(folder)` is all an application needs.
|
|
402
|
+
|
|
403
|
+
## Requirements
|
|
404
|
+
|
|
405
|
+
- Python ≥ 3.9
|
|
406
|
+
- PyTorch ≥ 2.3 (installed automatically; for GPU wheels see pytorch.org)
|
|
407
|
+
- FFmpeg is **not** required — audio decoding uses soundfile / PyAV.
|
|
408
|
+
|
|
409
|
+
## Troubleshooting
|
|
410
|
+
|
|
411
|
+
| Symptom | Fix |
|
|
412
|
+
| --- | --- |
|
|
413
|
+
| `ImportError: ... requires PyTorch` | `pip install torch torchaudio` (or reinstall `altasr`) |
|
|
414
|
+
| `BPETokenizer requires sentencepiece` | `pip install altasr[bpe]` |
|
|
415
|
+
| `--mic` fails to start | `pip install altasr[mic]`; check OS microphone permissions |
|
|
416
|
+
| Whisper baseline skipped in benchmark | `pip install altasr[whisper]` |
|
|
417
|
+
| CUDA out of memory during training | `--grad-checkpoint` (large models); lower `--max-batch-seconds`; then lower `--batch-size` + raise `--grad-accum` |
|
|
418
|
+
| Slow CPU inference | `quantize="int8"`, or export to ONNX |
|
|
419
|
+
| CLI clears my terminal / logs | set `ALTASR_NO_CLEAR=1` (clearing is skipped automatically when output is piped) |
|
|
420
|
+
| A term like "DGX" comes out wrong | if it's in your training data: use beam decoding (the default) — the learned LM/lexicon handles it; if never seen: `--hotwords "DGX"`; for many terms, fine-tune |
|
|
421
|
+
| Only one of my GPUs is used | training: launch with `torchrun --standalone --nproc_per_node=<N> -m altasr.training.train ...`; inference: `--device all-gpus` or `TranscriberPool` |
|
|
422
|
+
| `Could not load libtorchcodec` / `libavutil.so` errors | `pip install av soundfile` (ALTASR's own decoders); no system FFmpeg needed — since v0.2.2 such files are skipped, not fatal |
|
|
423
|
+
| `[data] SKIPPING unreadable item` warnings | normal for a few bad files in web corpora; 10+ consecutive = wrong `--audio-root`/`--features-dir` |
|
|
424
|
+
|
|
425
|
+
## License
|
|
426
|
+
|
|
427
|
+
Apache-2.0 — © YaliLabs / ALTA Project.
|
|
428
|
+
Source, issues and documentation: <https://github.com/yalilabs/altasr>
|