parakeet.ts 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +286 -0
- package/dist/alignment.d.ts +36 -0
- package/dist/alignment.d.ts.map +1 -0
- package/dist/alignment.js +202 -0
- package/dist/alignment.js.map +1 -0
- package/dist/audio.d.ts +59 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +324 -0
- package/dist/audio.js.map +1 -0
- package/dist/backend.d.ts +61 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +14 -0
- package/dist/backend.js.map +1 -0
- package/dist/decode.d.ts +38 -0
- package/dist/decode.d.ts.map +1 -0
- package/dist/decode.js +124 -0
- package/dist/decode.js.map +1 -0
- package/dist/hub.d.ts +18 -0
- package/dist/hub.d.ts.map +1 -0
- package/dist/hub.js +86 -0
- package/dist/hub.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +51 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +34 -0
- package/dist/load.js.map +1 -0
- package/dist/mlx/attention.d.ts +61 -0
- package/dist/mlx/attention.d.ts.map +1 -0
- package/dist/mlx/attention.js +330 -0
- package/dist/mlx/attention.js.map +1 -0
- package/dist/mlx/audio.d.ts +46 -0
- package/dist/mlx/audio.d.ts.map +1 -0
- package/dist/mlx/audio.js +309 -0
- package/dist/mlx/audio.js.map +1 -0
- package/dist/mlx/backend.d.ts +22 -0
- package/dist/mlx/backend.d.ts.map +1 -0
- package/dist/mlx/backend.js +67 -0
- package/dist/mlx/backend.js.map +1 -0
- package/dist/mlx/cache.d.ts +23 -0
- package/dist/mlx/cache.d.ts.map +1 -0
- package/dist/mlx/cache.js +98 -0
- package/dist/mlx/cache.js.map +1 -0
- package/dist/mlx/cli.d.ts +12 -0
- package/dist/mlx/cli.d.ts.map +1 -0
- package/dist/mlx/cli.js +145 -0
- package/dist/mlx/cli.js.map +1 -0
- package/dist/mlx/conformer.d.ts +81 -0
- package/dist/mlx/conformer.d.ts.map +1 -0
- package/dist/mlx/conformer.js +315 -0
- package/dist/mlx/conformer.js.map +1 -0
- package/dist/mlx/index.d.ts +6 -0
- package/dist/mlx/index.d.ts.map +1 -0
- package/dist/mlx/index.js +9 -0
- package/dist/mlx/index.js.map +1 -0
- package/dist/mlx/load.d.ts +27 -0
- package/dist/mlx/load.d.ts.map +1 -0
- package/dist/mlx/load.js +161 -0
- package/dist/mlx/load.js.map +1 -0
- package/dist/mlx/nn.d.ts +121 -0
- package/dist/mlx/nn.d.ts.map +1 -0
- package/dist/mlx/nn.js +511 -0
- package/dist/mlx/nn.js.map +1 -0
- package/dist/mlx/rnnt.d.ts +59 -0
- package/dist/mlx/rnnt.d.ts.map +1 -0
- package/dist/mlx/rnnt.js +233 -0
- package/dist/mlx/rnnt.js.map +1 -0
- package/dist/mlx/server.d.ts +34 -0
- package/dist/mlx/server.d.ts.map +1 -0
- package/dist/mlx/server.js +115 -0
- package/dist/mlx/server.js.map +1 -0
- package/dist/mlx/utils.d.ts +19 -0
- package/dist/mlx/utils.d.ts.map +1 -0
- package/dist/mlx/utils.js +103 -0
- package/dist/mlx/utils.js.map +1 -0
- package/dist/model.d.ts +112 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +196 -0
- package/dist/model.js.map +1 -0
- package/dist/onnx/backend.d.ts +55 -0
- package/dist/onnx/backend.d.ts.map +1 -0
- package/dist/onnx/backend.js +111 -0
- package/dist/onnx/backend.js.map +1 -0
- package/dist/onnx/index.d.ts +7 -0
- package/dist/onnx/index.d.ts.map +1 -0
- package/dist/onnx/index.js +6 -0
- package/dist/onnx/index.js.map +1 -0
- package/dist/onnx/parakeet.d.ts +44 -0
- package/dist/onnx/parakeet.d.ts.map +1 -0
- package/dist/onnx/parakeet.js +135 -0
- package/dist/onnx/parakeet.js.map +1 -0
- package/dist/tokenizer.d.ts +6 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +8 -0
- package/dist/tokenizer.js.map +1 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marcin Bunsch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# parakeet.ts
|
|
2
|
+
|
|
3
|
+
TypeScript runtime for Nvidia Parakeet ASR models. Runs on Apple Silicon via MLX, or Nvidia GPUs (Linux) via ONNX Runtime.
|
|
4
|
+
|
|
5
|
+
> **Not affiliated with NVIDIA.**
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 18.11+
|
|
10
|
+
- [ffmpeg](https://ffmpeg.org/) in `$PATH` (for audio file decoding)
|
|
11
|
+
- A backend, chosen automatically by [`load()`](#usage):
|
|
12
|
+
- **MLX** — Apple Silicon Mac (M1 or later). No extra install.
|
|
13
|
+
- **ONNX Runtime** — everywhere else (CUDA on Linux/Nvidia, CPU otherwise).
|
|
14
|
+
Install the optional `onnxruntime-node` package.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install parakeet.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Backends
|
|
23
|
+
|
|
24
|
+
The model, audio front-end, decode loop, and alignment are backend-agnostic, and
|
|
25
|
+
`load()` picks the right backend for the machine — you normally don't choose one.
|
|
26
|
+
For explicit control, import a backend's loader directly. Every path returns the
|
|
27
|
+
same `ParakeetModel`, so all the examples below work unchanged.
|
|
28
|
+
|
|
29
|
+
| Backend | Runs on | `load()` picks it | Explicit import |
|
|
30
|
+
|---------|---------|-------------------|-----------------|
|
|
31
|
+
| **MLX** | Apple Silicon (Metal) | on Apple Silicon | `parakeet.ts/mlx` — `fromPretrained`, `fromLocal` |
|
|
32
|
+
| **ONNX Runtime** | Nvidia GPU (CUDA, Linux) / CPU | everywhere else | `parakeet.ts/onnx` — `fromLocal` |
|
|
33
|
+
|
|
34
|
+
Each backend has its own default checkpoint (different asset formats, same
|
|
35
|
+
transcripts). The CLI and HTTP server use the MLX backend. See
|
|
36
|
+
[docs/cuda.md](docs/cuda.md) for the dual-backend design and benchmarks.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### SDK
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { load } from 'parakeet.ts';
|
|
44
|
+
|
|
45
|
+
const model = await load(); // detects the backend, downloads the model on first run
|
|
46
|
+
const result = await model.transcribe('recording.wav');
|
|
47
|
+
|
|
48
|
+
console.log(result.text);
|
|
49
|
+
// "Hello world"
|
|
50
|
+
|
|
51
|
+
console.log(result.sentences);
|
|
52
|
+
// [{ text: 'Hello world', start: 0, end: 1.2, duration: 1.2, tokens: [...] }]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`load()` is the canonical entry point. It selects the backend for the current
|
|
56
|
+
machine — **MLX** on Apple Silicon, **ONNX Runtime** everywhere else — and
|
|
57
|
+
downloads that backend's default checkpoint from HuggingFace Hub on first run,
|
|
58
|
+
caching under `~/.cache/huggingface/hub/`. Subsequent calls load from cache.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const model = await load({
|
|
62
|
+
// backend: 'auto' (default) | 'mlx' | 'onnx'
|
|
63
|
+
// model: HF repo id or local directory (default: the backend's checkpoint)
|
|
64
|
+
// cacheDir: override the HF cache root
|
|
65
|
+
// executionProvider: ONNX only — 'cuda' | 'cpu' | ...
|
|
66
|
+
// filterbank: 'interpolated' (default) | 'floor'
|
|
67
|
+
onProgress(file, downloaded, total) {
|
|
68
|
+
console.error(`${file}: ${Math.round((downloaded / total) * 100)}%`);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Ask which backend load() would choose here, without loading:
|
|
73
|
+
import { detectBackend } from 'parakeet.ts';
|
|
74
|
+
detectBackend(); // 'mlx' | 'onnx'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
To pin a backend or load from a local directory instead of auto-selecting, use
|
|
78
|
+
the per-backend loaders — see [Backends](#backends) and
|
|
79
|
+
[ONNX Runtime backend](#onnx-runtime-backend):
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { fromPretrained, fromLocal } from 'parakeet.ts/mlx';
|
|
83
|
+
|
|
84
|
+
const a = await fromPretrained('mlx-community/parakeet-tdt-0.6b-v3');
|
|
85
|
+
const b = fromLocal('/path/to/mlx-model-dir');
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### Streaming
|
|
89
|
+
|
|
90
|
+
For real-time or incremental transcription, use `StreamingParakeet` directly or the `consumePcmStream` helper:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { consumePcmStream } from 'parakeet.ts';
|
|
94
|
+
|
|
95
|
+
const stream = model.transcribeStream();
|
|
96
|
+
const result = await consumePcmStream(stream, pcmFrameIterable);
|
|
97
|
+
// pcmFrameIterable: AsyncIterable<Float32Array> — 16kHz mono f32le
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`consumePcmStream` returns only once the source is exhausted. To surface partial
|
|
101
|
+
transcripts as audio arrives, drive it manually and read the getters after each
|
|
102
|
+
chunk:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const stream = model.transcribeStream();
|
|
106
|
+
|
|
107
|
+
for await (const chunk of pcmFrameIterable) {
|
|
108
|
+
await stream.addAudio(chunk); // async
|
|
109
|
+
console.log(stream.result.text); // best current guess (finalized + draft)
|
|
110
|
+
console.log(stream.finalizedResult.text); // committed tokens only — never revised
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const final = stream.finish(); // commit the remaining draft
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Streaming is backend-agnostic — the same `StreamingParakeet` runs on MLX and ONNX.
|
|
117
|
+
|
|
118
|
+
#### Concurrency
|
|
119
|
+
|
|
120
|
+
Each model instance has an internal async mutex. Concurrent `await model.transcribe(...)` calls on the same instance are automatically serialized — no GPU-state corruption. For lower tail latency under bursty load, create a pool:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const pool = await Promise.all([load(), load()]);
|
|
124
|
+
let i = 0;
|
|
125
|
+
const next = () => pool[i++ % pool.length];
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### Output shape
|
|
129
|
+
|
|
130
|
+
All entry points return `AlignedResult`:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
type AlignedResult = {
|
|
134
|
+
text: string;
|
|
135
|
+
sentences: AlignedSentence[];
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
type AlignedSentence = {
|
|
139
|
+
text: string;
|
|
140
|
+
start: number; // seconds
|
|
141
|
+
end: number;
|
|
142
|
+
duration: number;
|
|
143
|
+
tokens: AlignedToken[];
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
type AlignedToken = {
|
|
147
|
+
id: number;
|
|
148
|
+
text: string;
|
|
149
|
+
start: number; // seconds
|
|
150
|
+
duration: number;
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### ONNX Runtime backend
|
|
155
|
+
|
|
156
|
+
On anything other than Apple Silicon, `load()` uses [ONNX Runtime](https://onnxruntime.ai/)
|
|
157
|
+
(CUDA execution provider on Linux/Nvidia, CPU elsewhere). It needs the optional
|
|
158
|
+
runtime:
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
npm install onnxruntime-node
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
With that installed, `await load()` downloads the default ONNX checkpoint
|
|
165
|
+
([`istupakov/parakeet-tdt-0.6b-v3-onnx`](https://huggingface.co/istupakov/parakeet-tdt-0.6b-v3-onnx))
|
|
166
|
+
and runs — no other setup. Pass the execution provider through if you want to
|
|
167
|
+
override it:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const model = await load({ executionProvider: 'cuda' }); // 'cuda' | 'cpu' | 'tensorrt' | 'coreml' | 'dml'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
To use your own exported graphs, load a local directory containing
|
|
174
|
+
`encoder-model.onnx` (plus its `encoder-model.onnx.data` sidecar — keep the
|
|
175
|
+
filename), `decoder_joint-model.onnx`, and `vocab.txt`:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { fromLocal } from 'parakeet.ts/onnx';
|
|
179
|
+
|
|
180
|
+
const model = await fromLocal('/path/to/onnx-model-dir', {
|
|
181
|
+
executionProvider: 'cuda', // default: 'cuda' on Linux/Windows x64, 'cpu' elsewhere
|
|
182
|
+
decoderExecutionProvider: 'cpu', // optional: run the small per-step decoder on CPU
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Either way `model` is the same `ParakeetModel`, so streaming, concurrency, and
|
|
187
|
+
the [output shape](#output-shape) behave identically. Only TDT and RNN-T
|
|
188
|
+
checkpoints are available as ONNX exports.
|
|
189
|
+
|
|
190
|
+
### CLI
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
# Transcribe a file (auto-downloads model on first run)
|
|
194
|
+
parakeet recording.wav
|
|
195
|
+
|
|
196
|
+
# JSON output with word-level timestamps
|
|
197
|
+
parakeet recording.wav --json
|
|
198
|
+
|
|
199
|
+
# Different model
|
|
200
|
+
parakeet recording.wav --model mlx-community/parakeet-tdt-0.6b-v3
|
|
201
|
+
|
|
202
|
+
# Stream raw f32le mono 16kHz PCM from stdin
|
|
203
|
+
ffmpeg -i recording.wav -f f32le -ar 16000 -ac 1 - | parakeet --stream
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Options:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
--model, -m <id> HuggingFace repo ID or local directory (default: mlx-community/parakeet-tdt-0.6b-v3)
|
|
210
|
+
--json, -j Output full AlignedResult JSON instead of plain text
|
|
211
|
+
--stream, -s Read raw f32le mono 16kHz PCM from stdin
|
|
212
|
+
--help, -h Show help
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Exit codes: `0` success, `1` file/IO error, `2` model error.
|
|
216
|
+
|
|
217
|
+
### HTTP server
|
|
218
|
+
|
|
219
|
+
The `parakeet.ts/mlx/server` entry point exports a [Hono](https://hono.dev/) route factory. Install the extra deps first:
|
|
220
|
+
|
|
221
|
+
```sh
|
|
222
|
+
npm install hono @hono/node-server
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { Hono } from 'hono';
|
|
227
|
+
import { serve } from '@hono/node-server';
|
|
228
|
+
import { fromPretrained } from 'parakeet.ts/mlx';
|
|
229
|
+
import { createParakeetRoutes } from 'parakeet.ts/mlx/server';
|
|
230
|
+
|
|
231
|
+
const model = await fromPretrained('mlx-community/parakeet-tdt-0.6b-v3');
|
|
232
|
+
|
|
233
|
+
const app = new Hono();
|
|
234
|
+
app.route('/asr', createParakeetRoutes({
|
|
235
|
+
model,
|
|
236
|
+
maxDurationSeconds: 300, // default
|
|
237
|
+
idleTimeoutMs: 30_000, // default
|
|
238
|
+
}));
|
|
239
|
+
|
|
240
|
+
serve({ fetch: app.fetch, port: 8080 });
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### `POST /asr/transcribe`
|
|
244
|
+
|
|
245
|
+
Send raw f32le mono 16kHz PCM audio as the request body.
|
|
246
|
+
|
|
247
|
+
**Request headers:**
|
|
248
|
+
```
|
|
249
|
+
Content-Type: audio/pcm; rate=16000; channels=1; format=f32le
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Response `200`:** `AlignedResult` JSON
|
|
253
|
+
|
|
254
|
+
**Error responses:**
|
|
255
|
+
```json
|
|
256
|
+
{ "error": "<code>", "message": "<human-readable>" }
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
| Status | Error code | Cause |
|
|
260
|
+
|--------|------------|-------|
|
|
261
|
+
| 408 | `idle_timeout` | No bytes for `idleTimeoutMs` ms |
|
|
262
|
+
| 413 | `payload_too_large` | Audio exceeds `maxDurationSeconds` |
|
|
263
|
+
| 415 | `unsupported_media_type` | Wrong Content-Type |
|
|
264
|
+
| 500 | `internal_error` | Unexpected error |
|
|
265
|
+
|
|
266
|
+
## Available models
|
|
267
|
+
|
|
268
|
+
| Model | HuggingFace ID | Notes |
|
|
269
|
+
|-------|---------------|-------|
|
|
270
|
+
| Parakeet TDT 0.6B v2 | `mlx-community/parakeet-tdt-0.6b-v2` | |
|
|
271
|
+
| Parakeet TDT 0.6B v3 | `mlx-community/parakeet-tdt-0.6b-v3` | **Default** |
|
|
272
|
+
| Parakeet RNNT 0.6B | `mlx-community/parakeet-rnnt-0.6b` | |
|
|
273
|
+
| Parakeet CTC 0.6B | `mlx-community/parakeet-ctc-0.6b` | |
|
|
274
|
+
| Parakeet TDT-CTC 0.6B | `mlx-community/parakeet-tdt-ctc-0.6b` | |
|
|
275
|
+
| Parakeet TDT 1.1B | `mlx-community/parakeet-tdt-1.1b` | |
|
|
276
|
+
|
|
277
|
+
`load()` downloads a default checkpoint per backend — `mlx-community/parakeet-tdt-0.6b-v3`
|
|
278
|
+
(MLX) or [`istupakov/parakeet-tdt-0.6b-v3-onnx`](https://huggingface.co/istupakov/parakeet-tdt-0.6b-v3-onnx)
|
|
279
|
+
(ONNX). The table lists the MLX (`mlx-community`) checkpoints; pass any of them as
|
|
280
|
+
`load({ model })` or to `fromPretrained`. ONNX exports live in their own repos —
|
|
281
|
+
`load({ backend: 'onnx' })` fetches the default automatically, or point
|
|
282
|
+
`fromLocal` at a local directory of graphs.
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface AlignedToken {
|
|
2
|
+
id: number;
|
|
3
|
+
text: string;
|
|
4
|
+
start: float;
|
|
5
|
+
duration: float;
|
|
6
|
+
confidence: float;
|
|
7
|
+
end: float;
|
|
8
|
+
}
|
|
9
|
+
type float = number;
|
|
10
|
+
export declare function makeAlignedToken(id: number, text: string, start: number, duration: number, confidence?: number): AlignedToken;
|
|
11
|
+
export interface AlignedSentence {
|
|
12
|
+
text: string;
|
|
13
|
+
tokens: AlignedToken[];
|
|
14
|
+
start: number;
|
|
15
|
+
end: number;
|
|
16
|
+
duration: number;
|
|
17
|
+
confidence: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function makeAlignedSentence(text: string, tokens: AlignedToken[]): AlignedSentence;
|
|
20
|
+
export interface AlignedResult {
|
|
21
|
+
text: string;
|
|
22
|
+
sentences: AlignedSentence[];
|
|
23
|
+
tokens: AlignedToken[];
|
|
24
|
+
}
|
|
25
|
+
export declare function makeAlignedResult(text: string, sentences: AlignedSentence[]): AlignedResult;
|
|
26
|
+
export interface SentenceConfig {
|
|
27
|
+
maxWords?: number;
|
|
28
|
+
silenceGap?: number;
|
|
29
|
+
maxDuration?: number;
|
|
30
|
+
}
|
|
31
|
+
export declare function tokensToSentences(tokens: AlignedToken[], config?: SentenceConfig): AlignedSentence[];
|
|
32
|
+
export declare function sentencesToResult(sentences: AlignedSentence[]): AlignedResult;
|
|
33
|
+
export declare function mergeLongestContiguous(a: AlignedToken[], b: AlignedToken[], overlapDuration: number): AlignedToken[];
|
|
34
|
+
export declare function mergeLongestCommonSubsequence(a: AlignedToken[], b: AlignedToken[], overlapDuration: number): AlignedToken[];
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=alignment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alignment.d.ts","sourceRoot":"","sources":["../src/alignment.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC;IAChB,UAAU,EAAE,KAAK,CAAC;IAClB,GAAG,EAAE,KAAK,CAAC;CACZ;AAGD,KAAK,KAAK,GAAG,MAAM,CAAC;AAEpB,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,MAAY,GACvB,YAAY,CAEd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EAAE,GACrB,eAAe,CASjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,eAAe,EAAE,GAC3B,aAAa,CAQf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,GAAE,cAAmB,GAC1B,eAAe,EAAE,CAgDnB;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,aAAa,CAG7E;AAED,wBAAgB,sBAAsB,CACpC,CAAC,EAAE,YAAY,EAAE,EACjB,CAAC,EAAE,YAAY,EAAE,EACjB,eAAe,EAAE,MAAM,GACtB,YAAY,EAAE,CA2EhB;AAED,wBAAgB,6BAA6B,CAC3C,CAAC,EAAE,YAAY,EAAE,EACjB,CAAC,EAAE,YAAY,EAAE,EACjB,eAAe,EAAE,MAAM,GACtB,YAAY,EAAE,CAsFhB"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
export function makeAlignedToken(id, text, start, duration, confidence = 1.0) {
|
|
2
|
+
return { id, text, start, duration, confidence, end: start + duration };
|
|
3
|
+
}
|
|
4
|
+
export function makeAlignedSentence(text, tokens) {
|
|
5
|
+
const sorted = [...tokens].sort((a, b) => a.start - b.start);
|
|
6
|
+
const start = sorted[0].start;
|
|
7
|
+
const end = sorted[sorted.length - 1].end;
|
|
8
|
+
const duration = end - start;
|
|
9
|
+
// Geometric mean of token confidences
|
|
10
|
+
const logSum = sorted.reduce((acc, t) => acc + Math.log(t.confidence + 1e-10), 0);
|
|
11
|
+
const confidence = Math.exp(logSum / sorted.length);
|
|
12
|
+
return { text, tokens: sorted, start, end, duration, confidence };
|
|
13
|
+
}
|
|
14
|
+
export function makeAlignedResult(text, sentences) {
|
|
15
|
+
return {
|
|
16
|
+
text: text.trim(),
|
|
17
|
+
sentences,
|
|
18
|
+
get tokens() {
|
|
19
|
+
return sentences.flatMap(s => s.tokens);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function tokensToSentences(tokens, config = {}) {
|
|
24
|
+
if (tokens.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
const sentences = [];
|
|
27
|
+
let current = [];
|
|
28
|
+
for (let idx = 0; idx < tokens.length; idx++) {
|
|
29
|
+
const token = tokens[idx];
|
|
30
|
+
current.push(token);
|
|
31
|
+
const isPunctuation = token.text.includes('!') ||
|
|
32
|
+
token.text.includes('?') ||
|
|
33
|
+
token.text.includes('。') ||
|
|
34
|
+
token.text.includes('?') ||
|
|
35
|
+
token.text.includes('!') ||
|
|
36
|
+
(token.text.includes('.') &&
|
|
37
|
+
(idx === tokens.length - 1 || tokens[idx + 1].text.includes(' ')));
|
|
38
|
+
const isWordLimit = config.maxWords !== undefined &&
|
|
39
|
+
idx !== tokens.length - 1 &&
|
|
40
|
+
current.filter(t => t.text.includes(' ')).length +
|
|
41
|
+
(tokens[idx + 1].text.includes(' ') ? 1 : 0) >
|
|
42
|
+
config.maxWords;
|
|
43
|
+
const isLongSilence = config.silenceGap !== undefined &&
|
|
44
|
+
idx !== tokens.length - 1 &&
|
|
45
|
+
tokens[idx + 1].start - token.end >= config.silenceGap;
|
|
46
|
+
const isOverDuration = config.maxDuration !== undefined &&
|
|
47
|
+
token.end - current[0].start >= config.maxDuration;
|
|
48
|
+
if (isPunctuation || isWordLimit || isLongSilence || isOverDuration) {
|
|
49
|
+
const text = current.map(t => t.text).join('');
|
|
50
|
+
sentences.push(makeAlignedSentence(text, current));
|
|
51
|
+
current = [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (current.length > 0) {
|
|
55
|
+
const text = current.map(t => t.text).join('');
|
|
56
|
+
sentences.push(makeAlignedSentence(text, current));
|
|
57
|
+
}
|
|
58
|
+
return sentences;
|
|
59
|
+
}
|
|
60
|
+
export function sentencesToResult(sentences) {
|
|
61
|
+
const text = sentences.map(s => s.text).join('');
|
|
62
|
+
return makeAlignedResult(text, sentences);
|
|
63
|
+
}
|
|
64
|
+
export function mergeLongestContiguous(a, b, overlapDuration) {
|
|
65
|
+
if (a.length === 0)
|
|
66
|
+
return b;
|
|
67
|
+
if (b.length === 0)
|
|
68
|
+
return a;
|
|
69
|
+
const aEndTime = a[a.length - 1].end;
|
|
70
|
+
const bStartTime = b[0].start;
|
|
71
|
+
if (aEndTime <= bStartTime)
|
|
72
|
+
return [...a, ...b];
|
|
73
|
+
const overlapA = a.filter(t => t.end > bStartTime - overlapDuration);
|
|
74
|
+
const overlapB = b.filter(t => t.start < aEndTime + overlapDuration);
|
|
75
|
+
const enoughPairs = Math.floor(overlapA.length / 2);
|
|
76
|
+
if (overlapA.length < 2 || overlapB.length < 2) {
|
|
77
|
+
const cutoffTime = (aEndTime + bStartTime) / 2;
|
|
78
|
+
return [
|
|
79
|
+
...a.filter(t => t.end <= cutoffTime),
|
|
80
|
+
...b.filter(t => t.start >= cutoffTime),
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
// Find longest contiguous matching subsequence
|
|
84
|
+
let bestContiguous = [];
|
|
85
|
+
for (let i = 0; i < overlapA.length; i++) {
|
|
86
|
+
for (let j = 0; j < overlapB.length; j++) {
|
|
87
|
+
if (overlapA[i].id === overlapB[j].id &&
|
|
88
|
+
Math.abs(overlapA[i].start - overlapB[j].start) < overlapDuration / 2) {
|
|
89
|
+
const current = [];
|
|
90
|
+
let k = i, l = j;
|
|
91
|
+
while (k < overlapA.length &&
|
|
92
|
+
l < overlapB.length &&
|
|
93
|
+
overlapA[k].id === overlapB[l].id &&
|
|
94
|
+
Math.abs(overlapA[k].start - overlapB[l].start) < overlapDuration / 2) {
|
|
95
|
+
current.push([k, l]);
|
|
96
|
+
k++;
|
|
97
|
+
l++;
|
|
98
|
+
}
|
|
99
|
+
if (current.length > bestContiguous.length) {
|
|
100
|
+
bestContiguous = current;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (bestContiguous.length >= enoughPairs) {
|
|
106
|
+
const aStartIdx = a.length - overlapA.length;
|
|
107
|
+
const lcsIndicesA = bestContiguous.map(p => aStartIdx + p[0]);
|
|
108
|
+
const lcsIndicesB = bestContiguous.map(p => p[1]);
|
|
109
|
+
const result = [];
|
|
110
|
+
result.push(...a.slice(0, lcsIndicesA[0]));
|
|
111
|
+
for (let i = 0; i < bestContiguous.length; i++) {
|
|
112
|
+
result.push(a[lcsIndicesA[i]]);
|
|
113
|
+
if (i < bestContiguous.length - 1) {
|
|
114
|
+
const nextA = lcsIndicesA[i + 1];
|
|
115
|
+
const nextB = lcsIndicesB[i + 1];
|
|
116
|
+
const gapA = a.slice(lcsIndicesA[i] + 1, nextA);
|
|
117
|
+
const gapB = b.slice(lcsIndicesB[i] + 1, nextB);
|
|
118
|
+
result.push(...(gapB.length > gapA.length ? gapB : gapA));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
result.push(...b.slice(lcsIndicesB[lcsIndicesB.length - 1] + 1));
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
throw new Error(`No pairs exceeding ${enoughPairs}`);
|
|
125
|
+
}
|
|
126
|
+
export function mergeLongestCommonSubsequence(a, b, overlapDuration) {
|
|
127
|
+
if (a.length === 0)
|
|
128
|
+
return b;
|
|
129
|
+
if (b.length === 0)
|
|
130
|
+
return a;
|
|
131
|
+
const aEndTime = a[a.length - 1].end;
|
|
132
|
+
const bStartTime = b[0].start;
|
|
133
|
+
if (aEndTime <= bStartTime)
|
|
134
|
+
return [...a, ...b];
|
|
135
|
+
const overlapA = a.filter(t => t.end > bStartTime - overlapDuration);
|
|
136
|
+
const overlapB = b.filter(t => t.start < aEndTime + overlapDuration);
|
|
137
|
+
if (overlapA.length < 2 || overlapB.length < 2) {
|
|
138
|
+
const cutoffTime = (aEndTime + bStartTime) / 2;
|
|
139
|
+
return [
|
|
140
|
+
...a.filter(t => t.end <= cutoffTime),
|
|
141
|
+
...b.filter(t => t.start >= cutoffTime),
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
// LCS dynamic programming
|
|
145
|
+
const m = overlapA.length;
|
|
146
|
+
const n = overlapB.length;
|
|
147
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
148
|
+
for (let i = 1; i <= m; i++) {
|
|
149
|
+
for (let j = 1; j <= n; j++) {
|
|
150
|
+
if (overlapA[i - 1].id === overlapB[j - 1].id &&
|
|
151
|
+
Math.abs(overlapA[i - 1].start - overlapB[j - 1].start) < overlapDuration / 2) {
|
|
152
|
+
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Backtrack
|
|
160
|
+
const lcsPairs = [];
|
|
161
|
+
let i = m, j = n;
|
|
162
|
+
while (i > 0 && j > 0) {
|
|
163
|
+
if (overlapA[i - 1].id === overlapB[j - 1].id &&
|
|
164
|
+
Math.abs(overlapA[i - 1].start - overlapB[j - 1].start) < overlapDuration / 2) {
|
|
165
|
+
lcsPairs.push([i - 1, j - 1]);
|
|
166
|
+
i--;
|
|
167
|
+
j--;
|
|
168
|
+
}
|
|
169
|
+
else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
170
|
+
i--;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
j--;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
lcsPairs.reverse();
|
|
177
|
+
if (lcsPairs.length === 0) {
|
|
178
|
+
const cutoffTime = (aEndTime + bStartTime) / 2;
|
|
179
|
+
return [
|
|
180
|
+
...a.filter(t => t.end <= cutoffTime),
|
|
181
|
+
...b.filter(t => t.start >= cutoffTime),
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
const aStartIdx = a.length - overlapA.length;
|
|
185
|
+
const lcsIndicesA = lcsPairs.map(p => aStartIdx + p[0]);
|
|
186
|
+
const lcsIndicesB = lcsPairs.map(p => p[1]);
|
|
187
|
+
const result = [];
|
|
188
|
+
result.push(...a.slice(0, lcsIndicesA[0]));
|
|
189
|
+
for (let k = 0; k < lcsPairs.length; k++) {
|
|
190
|
+
result.push(a[lcsIndicesA[k]]);
|
|
191
|
+
if (k < lcsPairs.length - 1) {
|
|
192
|
+
const nextA = lcsIndicesA[k + 1];
|
|
193
|
+
const nextB = lcsIndicesB[k + 1];
|
|
194
|
+
const gapA = a.slice(lcsIndicesA[k] + 1, nextA);
|
|
195
|
+
const gapB = b.slice(lcsIndicesB[k] + 1, nextB);
|
|
196
|
+
result.push(...(gapB.length > gapA.length ? gapB : gapA));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
result.push(...b.slice(lcsIndicesB[lcsIndicesB.length - 1] + 1));
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=alignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alignment.js","sourceRoot":"","sources":["../src/alignment.ts"],"names":[],"mappings":"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"}
|
package/dist/audio.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface PreprocessArgs {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
normalize: string;
|
|
4
|
+
windowSize: number;
|
|
5
|
+
windowStride: number;
|
|
6
|
+
window: string;
|
|
7
|
+
features: number;
|
|
8
|
+
nFft: number;
|
|
9
|
+
dither: number;
|
|
10
|
+
padTo: number;
|
|
11
|
+
padValue: number;
|
|
12
|
+
preemph: number | null;
|
|
13
|
+
magPower: number;
|
|
14
|
+
winLength: number;
|
|
15
|
+
hopLength: number;
|
|
16
|
+
/** [features, nFft/2+1], row-major */
|
|
17
|
+
filterbanks: Float32Array;
|
|
18
|
+
}
|
|
19
|
+
/** Log-mel output, laid out [nMels, numFrames] — the encoder's `audio_signal` order. */
|
|
20
|
+
export interface LogMel {
|
|
21
|
+
data: Float32Array;
|
|
22
|
+
nMels: number;
|
|
23
|
+
numFrames: number;
|
|
24
|
+
}
|
|
25
|
+
/** Decode any ffmpeg-readable file to mono float32 PCM in [-1, 1]. */
|
|
26
|
+
export declare function loadAudioRaw(filename: string, samplingRate: number): Float32Array;
|
|
27
|
+
export declare function getWindow(name: string, size: number): Float32Array;
|
|
28
|
+
/**
|
|
29
|
+
* Filterbank as parakeet-mlx builds it: mel points snapped to FFT bins with
|
|
30
|
+
* `floor`. NOTE: at 16 kHz / nFft 512 / 128 mels this collapses 13 rows to all
|
|
31
|
+
* zero — see docs/cuda.md. Kept as the default for bit-compatibility with the
|
|
32
|
+
* existing MLX path and the current test fixtures.
|
|
33
|
+
*/
|
|
34
|
+
export declare function computeMelFilterbanks(sr: number, nFft: number, nMels: number, fMin: number, fMax: number): Float32Array;
|
|
35
|
+
/**
|
|
36
|
+
* librosa/NeMo-style filterbank: triangles evaluated on continuous frequencies,
|
|
37
|
+
* so no rows collapse. Matches NVIDIA's reference preprocessor. Opt in via
|
|
38
|
+
* `makePreprocessArgs({ filterbank: 'interpolated' })`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function computeMelFilterbanksInterpolated(sr: number, nFft: number, nMels: number, fMin: number, fMax: number): Float32Array;
|
|
41
|
+
export declare function makePreprocessArgs(args: {
|
|
42
|
+
sampleRate: number;
|
|
43
|
+
normalize: string;
|
|
44
|
+
windowSize: number;
|
|
45
|
+
windowStride: number;
|
|
46
|
+
window: string;
|
|
47
|
+
features: number;
|
|
48
|
+
nFft: number;
|
|
49
|
+
dither: number;
|
|
50
|
+
padTo?: number;
|
|
51
|
+
padValue?: number;
|
|
52
|
+
preemph?: number | null;
|
|
53
|
+
magPower?: number;
|
|
54
|
+
/** 'floor' (default, parakeet-mlx compatible) or 'interpolated' (NeMo reference) */
|
|
55
|
+
filterbank?: 'floor' | 'interpolated';
|
|
56
|
+
}): PreprocessArgs;
|
|
57
|
+
/** Log-mel spectrogram from mono PCM. Output is [nMels, numFrames]. */
|
|
58
|
+
export declare function getLogMel(signalIn: Float32Array, args: PreprocessArgs): LogMel;
|
|
59
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IAEjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,EAAE,YAAY,CAAC;CAC3B;AAED,wFAAwF;AACxF,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,CAqBjF;AA6BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CASlE;AAsGD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAClE,YAAY,CA0Bd;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAClE,YAAY,CAyBd;AAMD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,UAAU,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;CACvC,GAAG,cAAc,CAkBjB;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CA0D9E"}
|