ngx-transformers 0.3.0 → 0.3.1
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 +87 -7
- package/fesm2022/ngx-transformers.mjs +134 -35
- package/fesm2022/ngx-transformers.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ngx-transformers.d.ts +48 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Muzaffar Qosimov
|
|
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
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
[](https://github.com/qwertymuzaffar/ngx-transformers/actions/workflows/ci.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
Run Hugging Face [Transformers.js](https://github.com/huggingface/transformers.js) models in Angular - **on-device ML with a signals API**. Text classification, sentence embeddings, semantic search, and Whisper speech-to-text that execute entirely in the browser: no server, no API key, works offline once the model is cached.
|
|
7
|
+
Run Hugging Face [Transformers.js](https://github.com/huggingface/transformers.js) models in Angular - **on-device ML with a signals API**. Text classification, zero-shot classification, sentence embeddings, semantic search, translation, and Whisper speech-to-text that execute entirely in the browser: no server, no API key, works offline once the model is cached.
|
|
8
8
|
|
|
9
|
-
**[
|
|
9
|
+
**[Documentation](https://qwertymuzaffar.github.io/ngx-transformers/)** · [Demo app](https://qwertymuzaffar.github.io/ngx-transformers/demo/) · [Storybook](https://qwertymuzaffar.github.io/ngx-transformers/storybook/) - the demos load real models in your browser.
|
|
10
10
|
|
|
11
11
|
## Why
|
|
12
12
|
|
|
@@ -90,6 +90,49 @@ async toggle() {
|
|
|
90
90
|
|
|
91
91
|
> Note: the recognizer defaults to `dtype: 'q4'` - q8 Whisper decoders currently fail on the v4 WASM runtime ([transformers.js#1707](https://github.com/huggingface/transformers.js/issues/1707)). Multilingual checkpoints (e.g. `onnx-community/whisper-tiny`) accept `language` and `task: 'translate'` options.
|
|
92
92
|
|
|
93
|
+
## Zero-shot classification
|
|
94
|
+
|
|
95
|
+
Score labels you name against a text, no fine-tuning - an NLI model judges whether "This example is {label}." follows from the text:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { createZeroShotClassifier } from 'ngx-transformers';
|
|
99
|
+
|
|
100
|
+
readonly classifier = createZeroShotClassifier(); // mobilebert-uncased-mnli, ~26 MB q8
|
|
101
|
+
|
|
102
|
+
const scored = await this.classifier.classify(ticketText, ['billing', 'bug report', 'feature request']);
|
|
103
|
+
// [{ label: 'bug report', score: 0.91 }, { label: 'billing', score: 0.06 }, ...] - scores sum to 1
|
|
104
|
+
|
|
105
|
+
// several labels can apply at once - score each on its own:
|
|
106
|
+
const tags = await this.classifier.classify(text, ['food', 'repair', 'politics'], {
|
|
107
|
+
multiLabel: true,
|
|
108
|
+
hypothesisTemplate: 'This text is about {}.',
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`Xenova/distilbert-base-uncased-mnli` (~80 MB) is the more accurate drop-in: `createZeroShotClassifier({ model: '...' })`.
|
|
113
|
+
|
|
114
|
+
## Translation
|
|
115
|
+
|
|
116
|
+
Marian opus-mt checkpoints, one per language pair (~105 MB q8 each), resolved from the pair and loaded on demand:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { createTranslator } from 'ngx-transformers';
|
|
120
|
+
|
|
121
|
+
readonly translator = createTranslator({ from: 'en', to: 'ru' }); // Xenova/opus-mt-en-ru
|
|
122
|
+
|
|
123
|
+
const russian = await this.translator.translate('The model runs entirely in the browser.');
|
|
124
|
+
const german = await this.translator.translate('Good morning.', { to: 'de' }); // opus-mt-en-de, its own download
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The translator's `status` / `progress` signals follow the model used by the latest call, so one `<ngx-model-progress>` covers every pair; `handleFor({ to: 'de' })` returns the underlying `PipelineHandle` when you want one per pair. Override the checkpoint for a pair globally with `provideTransformers({ translationModels: { 'en-ru': 'my-org/en-ru-tiny' } })`.
|
|
128
|
+
|
|
129
|
+
Multilingual checkpoints (NLLB, M2M100) serve every pair from one model and take the codes per call:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
readonly translator = createTranslator({ model: 'Xenova/nllb-200-distilled-600M' });
|
|
133
|
+
await this.translator.translate(text, { from: 'eng_Latn', to: 'tgk_Cyrl' }); // src_lang / tgt_lang forwarded
|
|
134
|
+
```
|
|
135
|
+
|
|
93
136
|
## Any pipeline
|
|
94
137
|
|
|
95
138
|
`createPipeline()` exposes the full Transformers.js task surface with the same signal lifecycle:
|
|
@@ -115,7 +158,23 @@ bootstrapApplication(App, {
|
|
|
115
158
|
});
|
|
116
159
|
```
|
|
117
160
|
|
|
118
|
-
Per-pipeline `device`/`dtype`/`options` win over the global config.
|
|
161
|
+
Per-pipeline `device`/`dtype`/`options` win over the global config. `translationModels` maps a `"from-to"` pair to a checkpoint for `createTranslator()`.
|
|
162
|
+
|
|
163
|
+
Every handle gets its pipeline from the `PIPELINE_FACTORY` injection token. Provide your own to add options or logging, route work to a Web Worker, or stub models in tests. `createDefaultPipelineFactory()` is the default; it lazy-imports `@huggingface/transformers` on the first pipeline, so wrapping it keeps the initial bundle small:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { PIPELINE_FACTORY, createDefaultPipelineFactory, type PipelineFactory } from 'ngx-transformers';
|
|
167
|
+
|
|
168
|
+
const base = createDefaultPipelineFactory();
|
|
169
|
+
const logging: PipelineFactory = (task, model, options) => {
|
|
170
|
+
console.log('loading', task, model);
|
|
171
|
+
return base(task, model, options);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
bootstrapApplication(App, {
|
|
175
|
+
providers: [{ provide: PIPELINE_FACTORY, useValue: logging }],
|
|
176
|
+
});
|
|
177
|
+
```
|
|
119
178
|
|
|
120
179
|
## API
|
|
121
180
|
|
|
@@ -127,10 +186,13 @@ Per-pipeline `device`/`dtype`/`options` win over the global config.
|
|
|
127
186
|
| `createTextClassifier(options?)` | `TextClassifier` - sentiment/classification, `classify(text, topK?)` |
|
|
128
187
|
| `createTextEmbedder(options?)` | `TextEmbedder` - `embed()`, `similarity()`, `rank()` |
|
|
129
188
|
| `createSpeechRecognizer(options?)` | `SpeechRecognizer` - `transcribe(audio, options?)` with timestamps |
|
|
189
|
+
| `createZeroShotClassifier(options?)` | `ZeroShotClassifier` - `classify(text, labels, { multiLabel?, hypothesisTemplate? })` |
|
|
190
|
+
| `createTranslator(options?)` | `Translator` - `translate(text, { from?, to? })`, one model per pair, `handleFor(pair)` |
|
|
130
191
|
| `createMicRecorder(deps?)` | `MicRecorder` - mic capture with `recording`/`seconds`/`error` signals |
|
|
131
192
|
| `cosineSimilarity(a, b)` / `decodeAudio(blob)` | Standalone helpers |
|
|
193
|
+
| `PIPELINE_FACTORY` / `createDefaultPipelineFactory()` | Swap or wrap how pipelines are created |
|
|
132
194
|
|
|
133
|
-
All `create*` functions must run in an injection context (field initializer, constructor, or `runInInjectionContext`); handles are
|
|
195
|
+
All `create*` functions must run in an injection context (field initializer, constructor, or `runInInjectionContext`); handles are destroyed with the surrounding component (the model is released and later calls reject). Call `dispose()` yourself to free a model early and load it again later.
|
|
134
196
|
|
|
135
197
|
### PipelineHandle signals
|
|
136
198
|
|
|
@@ -152,6 +214,8 @@ Status line + download bar for any handle. Inputs: `status` (required), `progres
|
|
|
152
214
|
| `createTextClassifier` | [Xenova/distilbert-base-uncased-finetuned-sst-2-english](https://huggingface.co/Xenova/distilbert-base-uncased-finetuned-sst-2-english) | ~65 MB | Apache-2.0 |
|
|
153
215
|
| `createTextEmbedder` | [Xenova/all-MiniLM-L6-v2](https://huggingface.co/Xenova/all-MiniLM-L6-v2) | ~23 MB | Apache-2.0 |
|
|
154
216
|
| `createSpeechRecognizer` | [onnx-community/whisper-tiny.en](https://huggingface.co/onnx-community/whisper-tiny.en) | ~41 MB (q4) | Apache-2.0 |
|
|
217
|
+
| `createZeroShotClassifier` | [Xenova/mobilebert-uncased-mnli](https://huggingface.co/Xenova/mobilebert-uncased-mnli) | ~26 MB | unlisted on the Hub (base MobileBERT: Apache-2.0) |
|
|
218
|
+
| `createTranslator` | [Xenova/opus-mt-{from}-{to}](https://huggingface.co/models?search=Xenova/opus-mt) | ~105 MB per pair | varies per pair (Apache-2.0 or CC-BY-4.0) |
|
|
155
219
|
|
|
156
220
|
Swap any compatible checkpoint via `{ model: '...' }`. Check the license of the model you ship.
|
|
157
221
|
|
|
@@ -159,10 +223,26 @@ Swap any compatible checkpoint via `{ model: '...' }`. Check the license of the
|
|
|
159
223
|
|
|
160
224
|
Model loading is browser-only (WASM/WebGPU). Creating handles is safe on the server - nothing downloads until `load()`/`run()` - but call those only in browser code paths.
|
|
161
225
|
|
|
162
|
-
##
|
|
226
|
+
## Device selection
|
|
227
|
+
|
|
228
|
+
WebGPU is several times faster than WASM where it works, but `navigator.gpu` existing is not enough: `requestAdapter()` can still hand back nothing on a machine without a usable GPU. `hasWebGpu()` runs that probe once (cached) and `detectDevice()` turns the answer into a device name; both resolve to the WASM answer on the server.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
import { createTextClassifier, detectDevice } from 'ngx-transformers';
|
|
232
|
+
|
|
233
|
+
const device = await detectDevice(); // 'webgpu' | 'wasm'
|
|
234
|
+
const classifier = createTextClassifier({ device });
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Or let every handle decide for itself:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
bootstrapApplication(App, {
|
|
241
|
+
providers: [provideTransformers({ autoDevice: true, dtype: 'q8' })],
|
|
242
|
+
});
|
|
243
|
+
```
|
|
163
244
|
|
|
164
|
-
|
|
165
|
-
- WebGPU feature-detection helper
|
|
245
|
+
With `autoDevice`, a handle that sets no `device` (or `'auto'`) probes WebGPU on its first load and uses it when available, else WASM. An explicit `device` on the handle or in the global config still wins. `resetDeviceDetection()` clears the cached answer.
|
|
166
246
|
|
|
167
247
|
## License
|
|
168
248
|
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, makeEnvironmentProviders, signal, computed, inject, DestroyRef, input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const importTransformers = () => import('@huggingface/transformers');
|
|
5
|
+
/**
|
|
6
|
+
* The factory behind PIPELINE_FACTORY. It imports @huggingface/transformers
|
|
7
|
+
* lazily, on the first pipeline, so the library adds nothing to the initial
|
|
8
|
+
* bundle. Wrap it to add options or logging while keeping the lazy import:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const base = createDefaultPipelineFactory();
|
|
12
|
+
* const factory: PipelineFactory = (task, model, options) =>
|
|
13
|
+
* base(task, model, { ...options, revision: 'v2' });
|
|
14
|
+
* providers: [{ provide: PIPELINE_FACTORY, useValue: factory }]
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* `load` is the importer. Tests pass a stub module; apps that need to
|
|
18
|
+
* configure Transformers.js (`env.allowRemoteModels`, `env.localModelPath`)
|
|
19
|
+
* do it there, before returning the module.
|
|
20
|
+
*/
|
|
21
|
+
function createDefaultPipelineFactory(load = importTransformers) {
|
|
22
|
+
return async (task, model, options) => {
|
|
23
|
+
const { pipeline } = await load();
|
|
24
|
+
return (await pipeline(task, model, options));
|
|
25
|
+
};
|
|
26
|
+
}
|
|
9
27
|
const PIPELINE_FACTORY = new InjectionToken('ngx-transformers.pipeline-factory', {
|
|
10
28
|
providedIn: 'root',
|
|
11
|
-
factory: () =>
|
|
29
|
+
factory: () => createDefaultPipelineFactory(),
|
|
12
30
|
});
|
|
13
31
|
const NGX_TRANSFORMERS_CONFIG = new InjectionToken('ngx-transformers.config', {
|
|
14
32
|
providedIn: 'root',
|
|
@@ -58,6 +76,7 @@ async function probeWebGpu() {
|
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
78
|
|
|
79
|
+
const newSession = () => ({ pipe: null, loading: null, inFlight: 0 });
|
|
61
80
|
/**
|
|
62
81
|
* A lazily-loaded Transformers.js pipeline wrapped in signals.
|
|
63
82
|
*
|
|
@@ -82,8 +101,8 @@ class PipelineHandle {
|
|
|
82
101
|
...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
|
|
83
102
|
busy = computed(() => this.status() === 'busy' || this.status() === 'loading', /* @ts-ignore */
|
|
84
103
|
...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
session = newSession();
|
|
105
|
+
destroyed = false;
|
|
87
106
|
constructor(request, factory, config) {
|
|
88
107
|
this.request = request;
|
|
89
108
|
this.factory = factory;
|
|
@@ -91,10 +110,15 @@ class PipelineHandle {
|
|
|
91
110
|
}
|
|
92
111
|
/** Downloads and initializes the model. Idempotent; retries after error. */
|
|
93
112
|
load() {
|
|
94
|
-
if (this.
|
|
113
|
+
if (this.destroyed)
|
|
114
|
+
return Promise.reject(destroyedError());
|
|
115
|
+
const session = this.session;
|
|
116
|
+
if (session.pipe)
|
|
95
117
|
return Promise.resolve();
|
|
96
|
-
|
|
97
|
-
|
|
118
|
+
session.loading ??= this.doLoad(session).finally(() => {
|
|
119
|
+
session.loading = null;
|
|
120
|
+
});
|
|
121
|
+
return session.loading;
|
|
98
122
|
}
|
|
99
123
|
/** Runs the pipeline, loading the model first if needed. */
|
|
100
124
|
run(input, runOptions) {
|
|
@@ -107,44 +131,79 @@ class PipelineHandle {
|
|
|
107
131
|
*/
|
|
108
132
|
async runWith(input, ...extraArgs) {
|
|
109
133
|
await this.load();
|
|
134
|
+
const session = this.session;
|
|
135
|
+
const pipe = session.pipe;
|
|
136
|
+
if (!pipe) {
|
|
137
|
+
throw new Error('PipelineHandle: disposed before the model finished loading.');
|
|
138
|
+
}
|
|
139
|
+
session.inFlight++;
|
|
110
140
|
this.status.set('busy');
|
|
111
141
|
try {
|
|
112
|
-
const pipe = this.pipe;
|
|
113
142
|
return (await pipe(input, ...extraArgs));
|
|
114
143
|
}
|
|
115
144
|
finally {
|
|
116
|
-
//
|
|
117
|
-
|
|
145
|
+
// Back to ready once the last overlapping run finishes - a failed run
|
|
146
|
+
// leaves the model intact. A run that outlived dispose() settles its
|
|
147
|
+
// own, retired session and leaves the status alone.
|
|
148
|
+
session.inFlight--;
|
|
149
|
+
if (session.inFlight === 0 && this.session === session)
|
|
150
|
+
this.status.set('ready');
|
|
118
151
|
}
|
|
119
152
|
}
|
|
120
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Frees the model. A download still in flight is cancelled: its model is
|
|
155
|
+
* released on arrival and the handle stays idle. The handle can be loaded
|
|
156
|
+
* again afterwards; destroy() is the terminal variant.
|
|
157
|
+
*/
|
|
121
158
|
async dispose() {
|
|
122
|
-
const
|
|
123
|
-
this.
|
|
159
|
+
const session = this.session;
|
|
160
|
+
this.session = newSession();
|
|
124
161
|
this.status.set('idle');
|
|
125
162
|
this.progress.set(null);
|
|
126
|
-
await pipe?.dispose?.();
|
|
163
|
+
await session.pipe?.dispose?.();
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* dispose() for good: later load() and run() calls reject instead of
|
|
167
|
+
* downloading a model nobody would release. create*() registers this with
|
|
168
|
+
* the DestroyRef of the injection context, so a handle declared in a
|
|
169
|
+
* component ends with the component.
|
|
170
|
+
*/
|
|
171
|
+
destroy() {
|
|
172
|
+
this.destroyed = true;
|
|
173
|
+
return this.dispose();
|
|
127
174
|
}
|
|
128
|
-
async doLoad() {
|
|
175
|
+
async doLoad(session) {
|
|
129
176
|
this.status.set('loading');
|
|
130
177
|
this.error.set(null);
|
|
131
178
|
const options = {
|
|
132
179
|
...this.config.pipelineOptions,
|
|
133
180
|
...this.request.options,
|
|
134
|
-
progress_callback: (event) => this.onProgress(event),
|
|
181
|
+
progress_callback: (event) => this.onProgress(event, session),
|
|
135
182
|
};
|
|
136
183
|
const device = await this.resolveDevice();
|
|
184
|
+
// Disposed while probing the device: do not start the download at all.
|
|
185
|
+
if (this.session !== session)
|
|
186
|
+
return;
|
|
137
187
|
const dtype = this.request.dtype ?? this.config.dtype;
|
|
138
188
|
if (device && device !== 'auto')
|
|
139
189
|
options['device'] = device;
|
|
140
190
|
if (dtype)
|
|
141
191
|
options['dtype'] = dtype;
|
|
142
192
|
try {
|
|
143
|
-
|
|
193
|
+
const pipe = await this.factory(this.request.task, this.request.model, options);
|
|
194
|
+
if (this.session !== session) {
|
|
195
|
+
// Disposed while downloading: nobody wants this model any more.
|
|
196
|
+
await pipe.dispose?.();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
session.pipe = pipe;
|
|
144
200
|
this.progress.set(null);
|
|
145
201
|
this.status.set('ready');
|
|
146
202
|
}
|
|
147
203
|
catch (err) {
|
|
204
|
+
// A cancelled load is not an error - dispose() already reset the handle.
|
|
205
|
+
if (this.session !== session)
|
|
206
|
+
return;
|
|
148
207
|
this.error.set(err);
|
|
149
208
|
this.status.set('error');
|
|
150
209
|
throw err;
|
|
@@ -160,7 +219,10 @@ class PipelineHandle {
|
|
|
160
219
|
return configured;
|
|
161
220
|
return this.config.autoDevice ? detectDevice() : configured;
|
|
162
221
|
}
|
|
163
|
-
onProgress(event) {
|
|
222
|
+
onProgress(event, session) {
|
|
223
|
+
// Events from a load that dispose() cancelled must not resurrect the bar.
|
|
224
|
+
if (this.session !== session)
|
|
225
|
+
return;
|
|
164
226
|
if (event.status !== 'progress' || !event.file)
|
|
165
227
|
return;
|
|
166
228
|
this.progress.set({
|
|
@@ -171,14 +233,17 @@ class PipelineHandle {
|
|
|
171
233
|
});
|
|
172
234
|
}
|
|
173
235
|
}
|
|
236
|
+
function destroyedError() {
|
|
237
|
+
return new Error('PipelineHandle: destroyed with its component; create a new handle.');
|
|
238
|
+
}
|
|
174
239
|
/**
|
|
175
240
|
* Creates a PipelineHandle in an injection context (constructor, field
|
|
176
|
-
* initializer, or runInInjectionContext). The handle is
|
|
241
|
+
* initializer, or runInInjectionContext). The handle is destroyed with the
|
|
177
242
|
* surrounding component/injector.
|
|
178
243
|
*/
|
|
179
244
|
function createPipeline(request) {
|
|
180
245
|
const handle = new PipelineHandle(request, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
181
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void handle.
|
|
246
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void handle.destroy());
|
|
182
247
|
return handle;
|
|
183
248
|
}
|
|
184
249
|
|
|
@@ -200,7 +265,7 @@ class TextClassifier extends PipelineHandle {
|
|
|
200
265
|
/** Creates a TextClassifier in an injection context. */
|
|
201
266
|
function createTextClassifier(options = {}) {
|
|
202
267
|
const classifier = new TextClassifier({ task: 'text-classification', model: DEFAULT_TEXT_CLASSIFICATION_MODEL, ...options }, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
203
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.
|
|
268
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.destroy());
|
|
204
269
|
return classifier;
|
|
205
270
|
}
|
|
206
271
|
|
|
@@ -246,7 +311,11 @@ class TextEmbedder extends PipelineHandle {
|
|
|
246
311
|
return [];
|
|
247
312
|
const [queryVec, ...docVecs] = await this.embed([query, ...documents]);
|
|
248
313
|
return docVecs
|
|
249
|
-
.map((vec, index) => ({
|
|
314
|
+
.map((vec, index) => ({
|
|
315
|
+
text: documents[index],
|
|
316
|
+
score: cosineSimilarity(queryVec, vec),
|
|
317
|
+
index,
|
|
318
|
+
}))
|
|
250
319
|
.sort((a, b) => b.score - a.score);
|
|
251
320
|
}
|
|
252
321
|
}
|
|
@@ -264,7 +333,7 @@ function toRows(out) {
|
|
|
264
333
|
/** Creates a TextEmbedder in an injection context. */
|
|
265
334
|
function createTextEmbedder(options = {}) {
|
|
266
335
|
const embedder = new TextEmbedder({ task: 'feature-extraction', model: DEFAULT_EMBEDDING_MODEL, ...options }, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
267
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void embedder.
|
|
336
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void embedder.destroy());
|
|
268
337
|
return embedder;
|
|
269
338
|
}
|
|
270
339
|
|
|
@@ -343,7 +412,7 @@ class SpeechRecognizer extends PipelineHandle {
|
|
|
343
412
|
*/
|
|
344
413
|
function createSpeechRecognizer(options = {}) {
|
|
345
414
|
const recognizer = new SpeechRecognizer({ task: 'automatic-speech-recognition', model: DEFAULT_ASR_MODEL, dtype: 'q4', ...options }, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
346
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void recognizer.
|
|
415
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void recognizer.destroy());
|
|
347
416
|
return recognizer;
|
|
348
417
|
}
|
|
349
418
|
|
|
@@ -382,7 +451,7 @@ class ZeroShotClassifier extends PipelineHandle {
|
|
|
382
451
|
/** Creates a ZeroShotClassifier in an injection context. */
|
|
383
452
|
function createZeroShotClassifier(options = {}) {
|
|
384
453
|
const classifier = new ZeroShotClassifier({ task: 'zero-shot-classification', model: DEFAULT_ZERO_SHOT_MODEL, ...options }, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
385
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.
|
|
454
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.destroy());
|
|
386
455
|
return classifier;
|
|
387
456
|
}
|
|
388
457
|
|
|
@@ -418,6 +487,7 @@ class Translator {
|
|
|
418
487
|
active = signal(null, /* @ts-ignore */
|
|
419
488
|
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
420
489
|
handles = new Map();
|
|
490
|
+
destroyed = false;
|
|
421
491
|
status = computed(() => this.active()?.status() ?? 'idle', /* @ts-ignore */
|
|
422
492
|
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
423
493
|
progress = computed(() => this.active()?.progress() ?? null, /* @ts-ignore */
|
|
@@ -434,7 +504,7 @@ class Translator {
|
|
|
434
504
|
this.config = config;
|
|
435
505
|
}
|
|
436
506
|
/** Downloads the model for a pair ahead of the first translate() call. */
|
|
437
|
-
load(pair = {}) {
|
|
507
|
+
async load(pair = {}) {
|
|
438
508
|
return this.handleFor(pair).load();
|
|
439
509
|
}
|
|
440
510
|
/** Translates one text; the pair defaults to the one given at creation. */
|
|
@@ -460,15 +530,32 @@ class Translator {
|
|
|
460
530
|
* keep several pairs warm and want a progress line per model.
|
|
461
531
|
*/
|
|
462
532
|
handleFor(pair = {}) {
|
|
533
|
+
if (this.destroyed) {
|
|
534
|
+
throw new Error('Translator: destroyed with its component; create a new translator.');
|
|
535
|
+
}
|
|
463
536
|
const model = this.modelFor(pair);
|
|
464
537
|
let handle = this.handles.get(model);
|
|
465
538
|
if (!handle) {
|
|
466
|
-
handle = new PipelineHandle({
|
|
539
|
+
handle = new PipelineHandle({
|
|
540
|
+
task: 'translation',
|
|
541
|
+
model,
|
|
542
|
+
device: this.options.device,
|
|
543
|
+
dtype: this.options.dtype,
|
|
544
|
+
options: this.options.options,
|
|
545
|
+
}, this.factory, this.config);
|
|
467
546
|
this.handles.set(model, handle);
|
|
468
547
|
}
|
|
469
548
|
this.active.set(handle);
|
|
470
549
|
return handle;
|
|
471
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* dispose() for good: later calls reject instead of loading a model nobody
|
|
553
|
+
* would release. createTranslator() registers this with the DestroyRef.
|
|
554
|
+
*/
|
|
555
|
+
destroy() {
|
|
556
|
+
this.destroyed = true;
|
|
557
|
+
return this.dispose();
|
|
558
|
+
}
|
|
472
559
|
/** Frees every model. The translator can be used again afterwards. */
|
|
473
560
|
async dispose() {
|
|
474
561
|
const handles = [...this.handles.values()];
|
|
@@ -493,7 +580,7 @@ class Translator {
|
|
|
493
580
|
/** Creates a Translator in an injection context. */
|
|
494
581
|
function createTranslator(options = {}) {
|
|
495
582
|
const translator = new Translator(options, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
496
|
-
inject(DestroyRef, { optional: true })?.onDestroy(() => void translator.
|
|
583
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void translator.destroy());
|
|
497
584
|
return translator;
|
|
498
585
|
}
|
|
499
586
|
|
|
@@ -631,7 +718,13 @@ class ModelProgressComponent {
|
|
|
631
718
|
<span class="nt-label">{{ label() }}</span>
|
|
632
719
|
@if (status() === 'loading' && progress(); as p) {
|
|
633
720
|
<span class="nt-file">{{ p.file }}</span>
|
|
634
|
-
<div
|
|
721
|
+
<div
|
|
722
|
+
class="nt-track"
|
|
723
|
+
role="progressbar"
|
|
724
|
+
[attr.aria-valuenow]="p.progress"
|
|
725
|
+
aria-valuemin="0"
|
|
726
|
+
aria-valuemax="100"
|
|
727
|
+
>
|
|
635
728
|
<div class="nt-fill" [style.width.%]="p.progress"></div>
|
|
636
729
|
</div>
|
|
637
730
|
<span class="nt-pct">{{ p.progress }}%</span>
|
|
@@ -647,7 +740,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
647
740
|
<span class="nt-label">{{ label() }}</span>
|
|
648
741
|
@if (status() === 'loading' && progress(); as p) {
|
|
649
742
|
<span class="nt-file">{{ p.file }}</span>
|
|
650
|
-
<div
|
|
743
|
+
<div
|
|
744
|
+
class="nt-track"
|
|
745
|
+
role="progressbar"
|
|
746
|
+
[attr.aria-valuenow]="p.progress"
|
|
747
|
+
aria-valuemin="0"
|
|
748
|
+
aria-valuemax="100"
|
|
749
|
+
>
|
|
651
750
|
<div class="nt-fill" [style.width.%]="p.progress"></div>
|
|
652
751
|
</div>
|
|
653
752
|
<span class="nt-pct">{{ p.progress }}%</span>
|
|
@@ -664,5 +763,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
664
763
|
* Generated bundle index. Do not edit.
|
|
665
764
|
*/
|
|
666
765
|
|
|
667
|
-
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, DEFAULT_ZERO_SHOT_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, Translator, WHISPER_SAMPLE_RATE, ZeroShotClassifier, cosineSimilarity, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, createTranslator, createZeroShotClassifier, decodeAudio, defaultTranslationModel, detectDevice, hasWebGpu, provideTransformers, resetDeviceDetection, resolveTranslationModel };
|
|
766
|
+
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, DEFAULT_ZERO_SHOT_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, Translator, WHISPER_SAMPLE_RATE, ZeroShotClassifier, cosineSimilarity, createDefaultPipelineFactory, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, createTranslator, createZeroShotClassifier, decodeAudio, defaultTranslationModel, detectDevice, hasWebGpu, provideTransformers, resetDeviceDetection, resolveTranslationModel };
|
|
668
767
|
//# sourceMappingURL=ngx-transformers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngx-transformers.mjs","sources":["../../../projects/ngx-transformers/src/lib/transformers.providers.ts","../../../projects/ngx-transformers/src/lib/device-detection.ts","../../../projects/ngx-transformers/src/lib/pipeline.ts","../../../projects/ngx-transformers/src/lib/text-classifier.ts","../../../projects/ngx-transformers/src/lib/text-embedder.ts","../../../projects/ngx-transformers/src/lib/speech-recognizer.ts","../../../projects/ngx-transformers/src/lib/zero-shot-classifier.ts","../../../projects/ngx-transformers/src/lib/translator.ts","../../../projects/ngx-transformers/src/lib/mic-recorder.ts","../../../projects/ngx-transformers/src/lib/model-progress.component.ts","../../../projects/ngx-transformers/src/public-api.ts","../../../projects/ngx-transformers/src/ngx-transformers.ts"],"sourcesContent":["import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport type { NgxTransformersConfig } from './transformers.models';\n\n/**\n * The callable returned by Transformers.js pipeline(), reduced to the\n * surface this library relies on.\n */\nexport type PipelineLike = ((input: unknown, options?: Record<string, unknown>) => Promise<unknown>) & {\n dispose?: () => Promise<void>;\n};\n\n/**\n * Creates a pipeline for a task. The default implementation lazy-imports\n * @huggingface/transformers; tests and SSR shims can provide their own.\n */\nexport type PipelineFactory = (\n task: string,\n model: string | undefined,\n options: Record<string, unknown>,\n) => Promise<PipelineLike>;\n\nconst defaultPipelineFactory: PipelineFactory = async (task, model, options) => {\n const { pipeline } = await import('@huggingface/transformers');\n const pipe = await (pipeline as (t: string, m?: string, o?: object) => Promise<unknown>)(\n task,\n model,\n options,\n );\n return pipe as PipelineLike;\n};\n\nexport const PIPELINE_FACTORY = new InjectionToken<PipelineFactory>('ngx-transformers.pipeline-factory', {\n providedIn: 'root',\n factory: () => defaultPipelineFactory,\n});\n\nexport const NGX_TRANSFORMERS_CONFIG = new InjectionToken<NgxTransformersConfig>('ngx-transformers.config', {\n providedIn: 'root',\n factory: () => ({}),\n});\n\n/**\n * Sets workspace-wide defaults (device, dtype, extra pipeline options):\n *\n * ```ts\n * bootstrapApplication(App, {\n * providers: [provideTransformers({ device: 'webgpu', dtype: 'q8' })],\n * });\n * ```\n */\nexport function provideTransformers(config: NgxTransformersConfig): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: NGX_TRANSFORMERS_CONFIG, useValue: config }]);\n}\n","/** The slice of navigator.gpu we probe; the WebGPU lib types are not in every project's tsconfig. */\ninterface GpuLike {\n requestAdapter(): Promise<unknown | null>;\n}\n\nlet webGpuProbe: Promise<boolean> | null = null;\n\n/**\n * Whether models can run on WebGPU here: `navigator.gpu` exists AND\n * `requestAdapter()` hands back an adapter - it returns null on machines\n * without a usable GPU or with WebGPU disabled, even when the API exists.\n * Resolves false on the server. The probe runs once and is cached.\n */\nexport function hasWebGpu(): Promise<boolean> {\n webGpuProbe ??= probeWebGpu();\n return webGpuProbe;\n}\n\n/** `'webgpu'` when hasWebGpu() resolves true, else `'wasm'`. */\nexport async function detectDevice(): Promise<'webgpu' | 'wasm'> {\n return (await hasWebGpu()) ? 'webgpu' : 'wasm';\n}\n\n/** Forgets the cached probe so the next hasWebGpu() asks the browser again. */\nexport function resetDeviceDetection(): void {\n webGpuProbe = null;\n}\n\nasync function probeWebGpu(): Promise<boolean> {\n const gpu = (globalThis as { navigator?: { gpu?: GpuLike } }).navigator?.gpu;\n if (!gpu) return false;\n try {\n return (await gpu.requestAdapter()) !== null;\n } catch {\n return false;\n }\n}\n","import { DestroyRef, computed, inject, signal } from '@angular/core';\nimport { detectDevice } from './device-detection';\nimport type { ModelProgress, NgxTransformersConfig, PipelineRequest, PipelineStatus, TransformersDevice } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, type PipelineFactory, type PipelineLike } from './transformers.providers';\n\n/** Shape of Transformers.js progress_callback events (subset we consume). */\ninterface RawProgressEvent {\n status?: string;\n file?: string;\n progress?: number;\n loaded?: number;\n total?: number;\n}\n\n/**\n * A lazily-loaded Transformers.js pipeline wrapped in signals.\n *\n * The model is not downloaded until load() or the first run() call, so\n * creating handles is free. All state is exposed as signals and safe to\n * bind in zoneless apps.\n */\nexport class PipelineHandle<TIn = unknown, TOut = unknown> {\n /** idle -> loading -> ready <-> busy; error only on load failure. */\n readonly status = signal<PipelineStatus>('idle');\n /** Download progress for the file currently transferring, else null. */\n readonly progress = signal<ModelProgress | null>(null);\n readonly error = signal<unknown>(null);\n /** True once the model is usable (including while a run is in flight). */\n readonly ready = computed(() => this.status() === 'ready' || this.status() === 'busy');\n readonly busy = computed(() => this.status() === 'busy' || this.status() === 'loading');\n\n private pipe: PipelineLike | null = null;\n private loading: Promise<void> | null = null;\n\n constructor(\n private readonly request: PipelineRequest,\n private readonly factory: PipelineFactory,\n private readonly config: NgxTransformersConfig,\n ) {}\n\n /** Downloads and initializes the model. Idempotent; retries after error. */\n load(): Promise<void> {\n if (this.pipe) return Promise.resolve();\n this.loading ??= this.doLoad().finally(() => (this.loading = null));\n return this.loading;\n }\n\n /** Runs the pipeline, loading the model first if needed. */\n run(input: TIn, runOptions?: Record<string, unknown>): Promise<TOut> {\n return this.runWith(input, runOptions);\n }\n\n /**\n * Runs the pipeline with extra positional arguments after the input, for\n * tasks whose pipeline signature is not (input, options): zero-shot\n * classification takes (text, candidateLabels, options).\n */\n protected async runWith(input: TIn, ...extraArgs: unknown[]): Promise<TOut> {\n await this.load();\n this.status.set('busy');\n try {\n const pipe = this.pipe! as (...args: unknown[]) => Promise<unknown>;\n return (await pipe(input, ...extraArgs)) as TOut;\n } finally {\n // A failed run leaves the model intact - back to ready either way.\n this.status.set('ready');\n }\n }\n\n /** Frees the model. The handle can be loaded again afterwards. */\n async dispose(): Promise<void> {\n const pipe = this.pipe;\n this.pipe = null;\n this.status.set('idle');\n this.progress.set(null);\n await pipe?.dispose?.();\n }\n\n private async doLoad(): Promise<void> {\n this.status.set('loading');\n this.error.set(null);\n const options: Record<string, unknown> = {\n ...this.config.pipelineOptions,\n ...this.request.options,\n progress_callback: (event: RawProgressEvent) => this.onProgress(event),\n };\n const device = await this.resolveDevice();\n const dtype = this.request.dtype ?? this.config.dtype;\n if (device && device !== 'auto') options['device'] = device;\n if (dtype) options['dtype'] = dtype;\n\n try {\n this.pipe = await this.factory(this.request.task, this.request.model, options);\n this.progress.set(null);\n this.status.set('ready');\n } catch (err) {\n this.error.set(err);\n this.status.set('error');\n throw err;\n }\n }\n\n /**\n * An explicit request or global device wins; with `autoDevice` on, an\n * unset or 'auto' device is probed for WebGPU (once, cached) at load time.\n */\n private async resolveDevice(): Promise<TransformersDevice | undefined> {\n const configured = this.request.device ?? this.config.device;\n if (configured && configured !== 'auto') return configured;\n return this.config.autoDevice ? detectDevice() : configured;\n }\n\n private onProgress(event: RawProgressEvent): void {\n if (event.status !== 'progress' || !event.file) return;\n this.progress.set({\n file: event.file,\n progress: Math.round(event.progress ?? 0),\n loadedBytes: event.loaded ?? 0,\n totalBytes: event.total ?? 0,\n });\n }\n}\n\n/**\n * Creates a PipelineHandle in an injection context (constructor, field\n * initializer, or runInInjectionContext). The handle is disposed with the\n * surrounding component/injector.\n */\nexport function createPipeline<TIn = unknown, TOut = unknown>(request: PipelineRequest): PipelineHandle<TIn, TOut> {\n const handle = new PipelineHandle<TIn, TOut>(\n request,\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void handle.dispose());\n return handle;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { ClassificationResult, PipelineRequest } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\nexport const DEFAULT_TEXT_CLASSIFICATION_MODEL = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n\n/**\n * Text classification (sentiment by default). The default model is\n * DistilBERT SST-2 (~65 MB, q8) - swap `model` for any Transformers.js\n * compatible text-classification checkpoint.\n */\nexport class TextClassifier extends PipelineHandle<string, ClassificationResult[] | ClassificationResult[][]> {\n /** Classifies one text; resolves to labels sorted by score (top first). */\n async classify(text: string, topK = 1): Promise<ClassificationResult[]> {\n const out = await this.run(text, { top_k: topK });\n // Single input: transformers.js returns a flat array of {label, score}.\n const flat = (Array.isArray(out[0]) ? out[0] : out) as ClassificationResult[];\n return [...flat].sort((a, b) => b.score - a.score);\n }\n}\n\n/** Creates a TextClassifier in an injection context. */\nexport function createTextClassifier(options: Partial<Omit<PipelineRequest, 'task'>> = {}): TextClassifier {\n const classifier = new TextClassifier(\n { task: 'text-classification', model: DEFAULT_TEXT_CLASSIFICATION_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.dispose());\n return classifier;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { PipelineRequest, RankedResult } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\nexport const DEFAULT_EMBEDDING_MODEL = 'Xenova/all-MiniLM-L6-v2';\n\n/** Tensor-ish output of feature-extraction: enough shape to read rows. */\ninterface TensorLike {\n dims: number[];\n data: ArrayLike<number>;\n tolist?: () => number[][];\n}\n\n/** Cosine similarity of two vectors. For normalized vectors this is the dot product. */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n if (a.length !== b.length || a.length === 0) {\n throw new Error(`cosineSimilarity: incompatible lengths ${a.length} and ${b.length}`);\n }\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n\n/**\n * Sentence embeddings via feature-extraction (all-MiniLM-L6-v2 by default,\n * ~23 MB q8). Outputs mean-pooled, L2-normalized vectors ready for cosine\n * similarity / semantic search.\n */\nexport class TextEmbedder extends PipelineHandle<string | string[], TensorLike> {\n /** Embeds one or many texts; always resolves to one vector per text. */\n async embed(texts: string | string[]): Promise<number[][]> {\n const input = Array.isArray(texts) ? texts : [texts];\n if (input.length === 0) return [];\n const out = await this.run(input, { pooling: 'mean', normalize: true });\n return toRows(out);\n }\n\n /** Cosine similarity of two texts in [-1, 1]. */\n async similarity(a: string, b: string): Promise<number> {\n const [va, vb] = await this.embed([a, b]);\n return cosineSimilarity(va, vb);\n }\n\n /** Ranks documents against a query, most similar first. */\n async rank(query: string, documents: string[]): Promise<RankedResult[]> {\n if (documents.length === 0) return [];\n const [queryVec, ...docVecs] = await this.embed([query, ...documents]);\n return docVecs\n .map((vec, index) => ({ text: documents[index], score: cosineSimilarity(queryVec, vec), index }))\n .sort((a, b) => b.score - a.score);\n }\n}\n\nfunction toRows(out: TensorLike): number[][] {\n if (typeof out.tolist === 'function') return out.tolist();\n const [rows, cols] = out.dims.length === 2 ? out.dims : [1, out.dims[out.dims.length - 1]];\n const data = out.data;\n const result: number[][] = [];\n for (let r = 0; r < rows; r++) {\n result.push(Array.from({ length: cols }, (_, c) => data[r * cols + c]));\n }\n return result;\n}\n\n/** Creates a TextEmbedder in an injection context. */\nexport function createTextEmbedder(options: Partial<Omit<PipelineRequest, 'task'>> = {}): TextEmbedder {\n const embedder = new TextEmbedder(\n { task: 'feature-extraction', model: DEFAULT_EMBEDDING_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void embedder.dispose());\n return embedder;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { PipelineRequest, TranscribeOptions, Transcription, TranscriptionChunk } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\n// onnx-community, not the legacy Xenova export: the old ONNX decoder lacks\n// the quantization scales transformers.js v4's runtime requires.\nexport const DEFAULT_ASR_MODEL = 'onnx-community/whisper-tiny.en';\n\n/** Whisper expects 16 kHz mono float PCM. */\nexport const WHISPER_SAMPLE_RATE = 16000;\n\n/** Raw ASR pipeline output (subset we consume). */\ninterface RawTranscription {\n text?: string;\n chunks?: { text: string; timestamp?: [number | null, number | null] }[];\n}\n\n/**\n * Decodes an encoded audio file (wav/mp3/webm/ogg - anything the browser\n * can decode) to 16 kHz mono Float32Array, ready for Whisper. Browser-only:\n * uses AudioContext with a target sample rate, which resamples on decode.\n */\nexport async function decodeAudio(\n source: Blob | ArrayBuffer,\n targetSampleRate = WHISPER_SAMPLE_RATE,\n): Promise<Float32Array> {\n const AudioContextCtor = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n if (!AudioContextCtor) {\n throw new Error('decodeAudio requires a browser AudioContext (not available in this environment).');\n }\n const buffer = source instanceof Blob ? await source.arrayBuffer() : source;\n const ctx = new AudioContextCtor({ sampleRate: targetSampleRate });\n try {\n const decoded = await ctx.decodeAudioData(buffer);\n if (decoded.numberOfChannels === 1) return decoded.getChannelData(0);\n // Mix down to mono by averaging channels.\n const left = decoded.getChannelData(0);\n const right = decoded.getChannelData(1);\n const mono = new Float32Array(left.length);\n for (let i = 0; i < left.length; i++) mono[i] = (left[i] + right[i]) / 2;\n return mono;\n } finally {\n await ctx.close();\n }\n}\n\n/**\n * Speech-to-text via Whisper. The default checkpoint is whisper-tiny.en\n * (~41 MB q8, English-only); swap `model` for a multilingual or larger one\n * (e.g. Xenova/whisper-small).\n */\nexport class SpeechRecognizer extends PipelineHandle<string | Float32Array, RawTranscription | RawTranscription[]> {\n /**\n * Transcribes audio: a URL, a decoded 16 kHz Float32Array, or an encoded\n * Blob/ArrayBuffer (decoded via decodeAudio first - browser-only).\n */\n async transcribe(\n audio: string | Float32Array | Blob | ArrayBuffer,\n options: TranscribeOptions = {},\n ): Promise<Transcription> {\n const input =\n audio instanceof Blob || audio instanceof ArrayBuffer ? await decodeAudio(audio) : audio;\n\n const runOptions: Record<string, unknown> = {};\n if (options.returnTimestamps !== undefined) runOptions['return_timestamps'] = options.returnTimestamps;\n if (options.chunkLengthS !== undefined) runOptions['chunk_length_s'] = options.chunkLengthS;\n if (options.strideLengthS !== undefined) runOptions['stride_length_s'] = options.strideLengthS;\n if (options.language !== undefined) runOptions['language'] = options.language;\n if (options.task !== undefined) runOptions['task'] = options.task;\n\n const raw = await this.run(input, runOptions);\n const first = (Array.isArray(raw) ? raw[0] : raw) ?? {};\n const chunks: TranscriptionChunk[] | undefined = first.chunks?.map((c) => ({\n text: c.text,\n start: c.timestamp?.[0] ?? null,\n end: c.timestamp?.[1] ?? null,\n }));\n return { text: (first.text ?? '').trim(), ...(chunks ? { chunks } : {}) };\n }\n}\n\n/**\n * Creates a SpeechRecognizer in an injection context.\n *\n * dtype defaults to 'q4' (not the library-wide default): q8 Whisper\n * decoders fail session creation on the v4 WASM runtime\n * (huggingface/transformers.js#1707), while q4 loads and runs everywhere.\n */\nexport function createSpeechRecognizer(options: Partial<Omit<PipelineRequest, 'task'>> = {}): SpeechRecognizer {\n const recognizer = new SpeechRecognizer(\n { task: 'automatic-speech-recognition', model: DEFAULT_ASR_MODEL, dtype: 'q4', ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void recognizer.dispose());\n return recognizer;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { ClassificationResult, PipelineRequest, ZeroShotOptions } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\n// The Transformers.js docs example for this task and the smallest MNLI\n// checkpoint that behaves well on the WASM runtime (~26 MB q8).\nexport const DEFAULT_ZERO_SHOT_MODEL = 'Xenova/mobilebert-uncased-mnli';\n\n/** Raw zero-shot output: labels ordered by score, scores aligned by index. */\ninterface RawZeroShotResult {\n sequence: string;\n labels: string[];\n scores: number[];\n}\n\n/**\n * Zero-shot classification: score any labels you name against a text with\n * an NLI model, no fine-tuning. The default checkpoint is MobileBERT MNLI\n * (~26 MB q8); Xenova/distilbert-base-uncased-mnli (~80 MB) is the\n * higher-accuracy alternative.\n */\nexport class ZeroShotClassifier extends PipelineHandle<string, RawZeroShotResult | RawZeroShotResult[]> {\n /**\n * Scores each candidate label for one text; resolves sorted by score (top\n * first). Single-label mode (default) normalizes across labels so scores\n * sum to 1; `multiLabel` scores each label on its own.\n */\n async classify(text: string, labels: readonly string[], options: ZeroShotOptions = {}): Promise<ClassificationResult[]> {\n if (labels.length === 0) return [];\n const runOptions: Record<string, unknown> = {};\n if (options.multiLabel !== undefined) runOptions['multi_label'] = options.multiLabel;\n if (options.hypothesisTemplate !== undefined) runOptions['hypothesis_template'] = options.hypothesisTemplate;\n\n const raw = await this.runWith(text, [...labels], runOptions);\n const first = Array.isArray(raw) ? raw[0] : raw;\n const scoredLabels = first?.labels ?? [];\n const scores = first?.scores ?? [];\n return scoredLabels\n .map((label, index) => ({ label, score: scores[index] ?? 0 }))\n .sort((left, right) => right.score - left.score);\n }\n}\n\n/** Creates a ZeroShotClassifier in an injection context. */\nexport function createZeroShotClassifier(options: Partial<Omit<PipelineRequest, 'task'>> = {}): ZeroShotClassifier {\n const classifier = new ZeroShotClassifier(\n { task: 'zero-shot-classification', model: DEFAULT_ZERO_SHOT_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.dispose());\n return classifier;\n}\n","import { DestroyRef, computed, inject, signal } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { NgxTransformersConfig, TranslateOptions, TranslatorOptions } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, type PipelineFactory } from './transformers.providers';\n\n/**\n * Default checkpoint for a language pair: Helsinki-NLP's Marian opus-mt\n * models, one per direction, ~105 MB q8 each (e.g. Xenova/opus-mt-en-ru).\n */\nexport function defaultTranslationModel(from: string, to: string): string {\n return `Xenova/opus-mt-${from}-${to}`;\n}\n\n/** Checkpoint for a pair: provideTransformers({ translationModels }) first, then opus-mt. */\nexport function resolveTranslationModel(from: string, to: string, config: NgxTransformersConfig): string {\n return config.translationModels?.[`${from}-${to}`] ?? defaultTranslationModel(from, to);\n}\n\n/**\n * Multilingual families take the pair per call as src_lang / tgt_lang;\n * Marian opus-mt checkpoints translate one fixed direction and ignore them.\n */\nconst MULTILINGUAL_MODEL_PATTERN = /nllb|m2m[_-]?100|mbart|madlad/i;\n\n/** Raw translation pipeline output, one entry per input text. */\ninterface RawTranslation {\n translation_text?: string;\n}\n\nexport type TranslationHandle = PipelineHandle<string, RawTranslation | RawTranslation[]>;\n\n/**\n * Text translation. Pipelines are created lazily, one per checkpoint: with\n * the default opus-mt family every language pair is its own model, so a\n * Translator holds one handle per pair it has been asked for, while a\n * pinned multilingual `model` (NLLB, M2M100) serves every pair from one.\n *\n * The signals mirror the handle used by the most recent call, so a single\n * `<ngx-model-progress>` covers the translator.\n */\nexport class Translator {\n private readonly active = signal<TranslationHandle | null>(null);\n private readonly handles = new Map<string, TranslationHandle>();\n\n readonly status = computed(() => this.active()?.status() ?? 'idle');\n readonly progress = computed(() => this.active()?.progress() ?? null);\n readonly error = computed(() => this.active()?.error() ?? null);\n readonly ready = computed(() => this.active()?.ready() ?? false);\n readonly busy = computed(() => this.active()?.busy() ?? false);\n\n constructor(\n private readonly options: TranslatorOptions,\n private readonly factory: PipelineFactory,\n private readonly config: NgxTransformersConfig,\n ) {}\n\n /** Downloads the model for a pair ahead of the first translate() call. */\n load(pair: TranslateOptions = {}): Promise<void> {\n return this.handleFor(pair).load();\n }\n\n /** Translates one text; the pair defaults to the one given at creation. */\n async translate(text: string, pair: TranslateOptions = {}): Promise<string> {\n const handle = this.handleFor(pair);\n const raw = await handle.run(text, this.languageOptions(pair));\n const first = Array.isArray(raw) ? raw[0] : raw;\n return (first?.translation_text ?? '').trim();\n }\n\n /** Checkpoint for a pair: the pinned model, else the configured or default one. */\n modelFor(pair: TranslateOptions = {}): string {\n if (this.options.model) return this.options.model;\n const from = pair.from ?? this.options.from;\n const to = pair.to ?? this.options.to;\n if (!from || !to) {\n throw new Error(\n 'Translator: no language pair - pass { from, to } to createTranslator() or translate(), or pin a multilingual model.',\n );\n }\n return resolveTranslationModel(from, to, this.config);\n }\n\n /**\n * The handle serving a pair, created on first use. Exposed for apps that\n * keep several pairs warm and want a progress line per model.\n */\n handleFor(pair: TranslateOptions = {}): TranslationHandle {\n const model = this.modelFor(pair);\n let handle = this.handles.get(model);\n if (!handle) {\n handle = new PipelineHandle(\n { task: 'translation', model, device: this.options.device, dtype: this.options.dtype, options: this.options.options },\n this.factory,\n this.config,\n );\n this.handles.set(model, handle);\n }\n this.active.set(handle);\n return handle;\n }\n\n /** Frees every model. The translator can be used again afterwards. */\n async dispose(): Promise<void> {\n const handles = [...this.handles.values()];\n this.handles.clear();\n this.active.set(null);\n await Promise.all(handles.map((handle) => handle.dispose()));\n }\n\n /** src_lang / tgt_lang for multilingual checkpoints; opus-mt models get nothing. */\n private languageOptions(pair: TranslateOptions): Record<string, unknown> {\n const runOptions: Record<string, unknown> = {};\n if (!MULTILINGUAL_MODEL_PATTERN.test(this.modelFor(pair))) return runOptions;\n const from = pair.from ?? this.options.from;\n const to = pair.to ?? this.options.to;\n if (from !== undefined) runOptions['src_lang'] = from;\n if (to !== undefined) runOptions['tgt_lang'] = to;\n return runOptions;\n }\n}\n\n/** Creates a Translator in an injection context. */\nexport function createTranslator(options: TranslatorOptions = {}): Translator {\n const translator = new Translator(options, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));\n inject(DestroyRef, { optional: true })?.onDestroy(() => void translator.dispose());\n return translator;\n}\n","import { DestroyRef, inject, signal } from '@angular/core';\n\n/** Minimal recorder surface - lets tests (and exotic runtimes) inject fakes. */\nexport interface RecorderLike {\n start(): void;\n stop(): void;\n ondataavailable: ((event: { data: Blob }) => void) | null;\n onstop: (() => void) | null;\n mimeType?: string;\n}\n\nexport interface MicRecorderDeps {\n /** Defaults to navigator.mediaDevices.getUserMedia({ audio: true }). */\n getUserMedia?: () => Promise<MediaStream>;\n /** Defaults to new MediaRecorder(stream). */\n createRecorder?: (stream: MediaStream) => RecorderLike;\n}\n\n/**\n * Microphone capture with a signals API. start() asks for mic permission\n * and records; stop() resolves with the encoded audio Blob - pass it to\n * SpeechRecognizer.transcribe(). Browser-only.\n *\n * ```ts\n * readonly mic = createMicRecorder();\n * readonly whisper = createSpeechRecognizer();\n *\n * async toggle() {\n * if (this.mic.recording()) {\n * const audio = await this.mic.stop();\n * const { text } = await this.whisper.transcribe(audio);\n * } else {\n * await this.mic.start();\n * }\n * }\n * ```\n */\nexport class MicRecorder {\n readonly recording = signal(false);\n /** Elapsed recording time in whole seconds. */\n readonly seconds = signal(0);\n readonly error = signal<unknown>(null);\n\n private stream: MediaStream | null = null;\n private recorder: RecorderLike | null = null;\n private chunks: Blob[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(private readonly deps: MicRecorderDeps = {}) {}\n\n /** Requests the microphone and starts recording. No-op while recording. */\n async start(): Promise<void> {\n if (this.recording()) return;\n this.error.set(null);\n try {\n this.stream = await (this.deps.getUserMedia\n ? this.deps.getUserMedia()\n : navigator.mediaDevices.getUserMedia({ audio: true }));\n this.recorder = this.deps.createRecorder\n ? this.deps.createRecorder(this.stream)\n : (new MediaRecorder(this.stream) as unknown as RecorderLike);\n this.chunks = [];\n this.recorder.ondataavailable = (event) => {\n if (event.data.size > 0) this.chunks.push(event.data);\n };\n this.recorder.start();\n this.recording.set(true);\n this.seconds.set(0);\n this.timer = setInterval(() => this.seconds.set(this.seconds() + 1), 1000);\n } catch (err) {\n this.error.set(err);\n this.cleanup();\n throw err;\n }\n }\n\n /** Stops recording and resolves with the captured audio. */\n stop(): Promise<Blob> {\n const recorder = this.recorder;\n if (!recorder || !this.recording()) {\n return Promise.reject(new Error('MicRecorder.stop() called while not recording.'));\n }\n return new Promise<Blob>((resolve) => {\n recorder.onstop = () => {\n const blob = new Blob(this.chunks, { type: recorder.mimeType || 'audio/webm' });\n this.cleanup();\n resolve(blob);\n };\n recorder.stop();\n });\n }\n\n /** Stops tracks and timers without resolving audio (e.g. on destroy). */\n dispose(): void {\n this.cleanup();\n }\n\n private cleanup(): void {\n if (this.timer !== null) clearInterval(this.timer);\n this.timer = null;\n this.stream?.getTracks().forEach((track) => track.stop());\n this.stream = null;\n this.recorder = null;\n this.recording.set(false);\n }\n}\n\n/** Creates a MicRecorder in an injection context; disposed with the component. */\nexport function createMicRecorder(deps: MicRecorderDeps = {}): MicRecorder {\n const recorder = new MicRecorder(deps);\n inject(DestroyRef, { optional: true })?.onDestroy(() => recorder.dispose());\n return recorder;\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport type { ModelProgress, PipelineStatus } from './transformers.models';\n\n/**\n * Drop-in status line for a PipelineHandle: shows model download progress\n * while loading, then the ready/busy/error state. Themeable via CSS custom\n * properties (--nt-accent, --nt-ink, --nt-muted, --nt-track).\n *\n * ```html\n * <ngx-model-progress [status]=\"classifier.status()\" [progress]=\"classifier.progress()\" />\n * ```\n */\n@Component({\n selector: 'ngx-model-progress',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"nt-row\" [class.nt-error]=\"status() === 'error'\" role=\"status\">\n <span class=\"nt-dot\" [attr.data-status]=\"status()\"></span>\n <span class=\"nt-label\">{{ label() }}</span>\n @if (status() === 'loading' && progress(); as p) {\n <span class=\"nt-file\">{{ p.file }}</span>\n <div class=\"nt-track\" role=\"progressbar\" [attr.aria-valuenow]=\"p.progress\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"nt-fill\" [style.width.%]=\"p.progress\"></div>\n </div>\n <span class=\"nt-pct\">{{ p.progress }}%</span>\n }\n </div>\n `,\n styles: `\n :host {\n --nt-accent: #f59e0b;\n --nt-ink: #1e293b;\n --nt-muted: #64748b;\n --nt-track: #e2e8f0;\n display: block;\n font-size: 12.5px;\n color: var(--nt-ink);\n }\n .nt-row { display: flex; align-items: center; gap: 8px; }\n .nt-dot {\n width: 8px; height: 8px; border-radius: 50%; flex: none;\n background: var(--nt-muted);\n }\n .nt-dot[data-status='loading'] { background: var(--nt-accent); animation: nt-blink 1s ease-in-out infinite; }\n .nt-dot[data-status='ready'] { background: #22c55e; }\n .nt-dot[data-status='busy'] { background: #3b82f6; animation: nt-blink 0.7s ease-in-out infinite; }\n .nt-dot[data-status='error'] { background: #dc2626; }\n .nt-label { font-weight: 600; }\n .nt-file { color: var(--nt-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px; }\n .nt-track {\n flex: 1; min-width: 60px; height: 6px; border-radius: 3px;\n background: var(--nt-track); overflow: hidden;\n }\n .nt-fill { height: 100%; background: var(--nt-accent); border-radius: 3px; transition: width 120ms linear; }\n .nt-pct { font-variant-numeric: tabular-nums; color: var(--nt-muted); }\n .nt-error .nt-label { color: #dc2626; }\n @keyframes nt-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }\n @media (prefers-reduced-motion: reduce) {\n .nt-dot { animation: none; }\n .nt-fill { transition: none; }\n }\n `,\n})\nexport class ModelProgressComponent {\n status = input.required<PipelineStatus>();\n progress = input<ModelProgress | null>(null);\n /** Labels per status; override to localize. */\n labels = input<Partial<Record<PipelineStatus, string>>>({});\n\n readonly label = computed(() => {\n const defaults: Record<PipelineStatus, string> = {\n idle: 'Model not loaded',\n loading: 'Downloading model',\n ready: 'Model ready',\n busy: 'Running',\n error: 'Failed to load model',\n };\n return this.labels()[this.status()] ?? defaults[this.status()];\n });\n}\n","/*\n * Public API Surface of ngx-transformers\n */\n\nexport * from './lib/transformers.models';\nexport * from './lib/transformers.providers';\nexport * from './lib/pipeline';\nexport * from './lib/device-detection';\nexport * from './lib/text-classifier';\nexport * from './lib/text-embedder';\nexport * from './lib/speech-recognizer';\nexport * from './lib/zero-shot-classifier';\nexport * from './lib/translator';\nexport * from './lib/mic-recorder';\nexport * from './lib/model-progress.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngx-transformers.mjs","sources":["../../../projects/ngx-transformers/src/lib/transformers.providers.ts","../../../projects/ngx-transformers/src/lib/device-detection.ts","../../../projects/ngx-transformers/src/lib/pipeline.ts","../../../projects/ngx-transformers/src/lib/text-classifier.ts","../../../projects/ngx-transformers/src/lib/text-embedder.ts","../../../projects/ngx-transformers/src/lib/speech-recognizer.ts","../../../projects/ngx-transformers/src/lib/zero-shot-classifier.ts","../../../projects/ngx-transformers/src/lib/translator.ts","../../../projects/ngx-transformers/src/lib/mic-recorder.ts","../../../projects/ngx-transformers/src/lib/model-progress.component.ts","../../../projects/ngx-transformers/src/public-api.ts","../../../projects/ngx-transformers/src/ngx-transformers.ts"],"sourcesContent":["import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport type { NgxTransformersConfig } from './transformers.models';\n\n/**\n * The callable returned by Transformers.js pipeline(), reduced to the\n * surface this library relies on.\n */\nexport type PipelineLike = ((\n input: unknown,\n options?: Record<string, unknown>,\n) => Promise<unknown>) & {\n dispose?: () => Promise<void>;\n};\n\n/**\n * Creates a pipeline for a task. The default implementation lazy-imports\n * @huggingface/transformers; tests and SSR shims can provide their own.\n */\nexport type PipelineFactory = (\n task: string,\n model: string | undefined,\n options: Record<string, unknown>,\n) => Promise<PipelineLike>;\n\n/**\n * The slice of the @huggingface/transformers module the default factory\n * uses. The real module satisfies it, so an importer can configure\n * `env` and return the module as is.\n */\nexport interface TransformersModuleLike {\n // A method signature on purpose: it keeps the overloaded, generic\n // pipeline() of the real module assignable.\n pipeline(task: string, model?: string, options?: object): Promise<unknown>;\n}\n\nconst importTransformers = (): Promise<TransformersModuleLike> =>\n import('@huggingface/transformers');\n\n/**\n * The factory behind PIPELINE_FACTORY. It imports @huggingface/transformers\n * lazily, on the first pipeline, so the library adds nothing to the initial\n * bundle. Wrap it to add options or logging while keeping the lazy import:\n *\n * ```ts\n * const base = createDefaultPipelineFactory();\n * const factory: PipelineFactory = (task, model, options) =>\n * base(task, model, { ...options, revision: 'v2' });\n * providers: [{ provide: PIPELINE_FACTORY, useValue: factory }]\n * ```\n *\n * `load` is the importer. Tests pass a stub module; apps that need to\n * configure Transformers.js (`env.allowRemoteModels`, `env.localModelPath`)\n * do it there, before returning the module.\n */\nexport function createDefaultPipelineFactory(\n load: () => Promise<TransformersModuleLike> = importTransformers,\n): PipelineFactory {\n return async (task, model, options) => {\n const { pipeline } = await load();\n return (await pipeline(task, model, options)) as PipelineLike;\n };\n}\n\nexport const PIPELINE_FACTORY = new InjectionToken<PipelineFactory>(\n 'ngx-transformers.pipeline-factory',\n {\n providedIn: 'root',\n factory: () => createDefaultPipelineFactory(),\n },\n);\n\nexport const NGX_TRANSFORMERS_CONFIG = new InjectionToken<NgxTransformersConfig>(\n 'ngx-transformers.config',\n {\n providedIn: 'root',\n factory: () => ({}),\n },\n);\n\n/**\n * Sets workspace-wide defaults (device, dtype, extra pipeline options):\n *\n * ```ts\n * bootstrapApplication(App, {\n * providers: [provideTransformers({ device: 'webgpu', dtype: 'q8' })],\n * });\n * ```\n */\nexport function provideTransformers(config: NgxTransformersConfig): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: NGX_TRANSFORMERS_CONFIG, useValue: config }]);\n}\n","/** The slice of navigator.gpu we probe; the WebGPU lib types are not in every project's tsconfig. */\ninterface GpuLike {\n requestAdapter(): Promise<unknown | null>;\n}\n\nlet webGpuProbe: Promise<boolean> | null = null;\n\n/**\n * Whether models can run on WebGPU here: `navigator.gpu` exists AND\n * `requestAdapter()` hands back an adapter - it returns null on machines\n * without a usable GPU or with WebGPU disabled, even when the API exists.\n * Resolves false on the server. The probe runs once and is cached.\n */\nexport function hasWebGpu(): Promise<boolean> {\n webGpuProbe ??= probeWebGpu();\n return webGpuProbe;\n}\n\n/** `'webgpu'` when hasWebGpu() resolves true, else `'wasm'`. */\nexport async function detectDevice(): Promise<'webgpu' | 'wasm'> {\n return (await hasWebGpu()) ? 'webgpu' : 'wasm';\n}\n\n/** Forgets the cached probe so the next hasWebGpu() asks the browser again. */\nexport function resetDeviceDetection(): void {\n webGpuProbe = null;\n}\n\nasync function probeWebGpu(): Promise<boolean> {\n const gpu = (globalThis as { navigator?: { gpu?: GpuLike } }).navigator?.gpu;\n if (!gpu) return false;\n try {\n return (await gpu.requestAdapter()) !== null;\n } catch {\n return false;\n }\n}\n","import { DestroyRef, computed, inject, signal } from '@angular/core';\nimport { detectDevice } from './device-detection';\nimport type {\n ModelProgress,\n NgxTransformersConfig,\n PipelineRequest,\n PipelineStatus,\n TransformersDevice,\n} from './transformers.models';\nimport {\n NGX_TRANSFORMERS_CONFIG,\n PIPELINE_FACTORY,\n type PipelineFactory,\n type PipelineLike,\n} from './transformers.providers';\n\n/** Shape of Transformers.js progress_callback events (subset we consume). */\ninterface RawProgressEvent {\n status?: string;\n file?: string;\n progress?: number;\n loaded?: number;\n total?: number;\n}\n\n/** A pipeline callable with the positional extras some tasks take after the input. */\ntype Runnable = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * One load-to-dispose span of a handle. dispose() swaps in a fresh session,\n * so async work still holding the old one knows it was cancelled and keeps\n * its bookkeeping (in-flight runs, the loading promise) to itself.\n */\ninterface Session {\n pipe: PipelineLike | null;\n loading: Promise<void> | null;\n /** Runs executing against this session's pipe. */\n inFlight: number;\n}\n\nconst newSession = (): Session => ({ pipe: null, loading: null, inFlight: 0 });\n\n/**\n * A lazily-loaded Transformers.js pipeline wrapped in signals.\n *\n * The model is not downloaded until load() or the first run() call, so\n * creating handles is free. All state is exposed as signals and safe to\n * bind in zoneless apps.\n */\nexport class PipelineHandle<TIn = unknown, TOut = unknown> {\n /** idle -> loading -> ready <-> busy; error only on load failure. */\n readonly status = signal<PipelineStatus>('idle');\n /** Download progress for the file currently transferring, else null. */\n readonly progress = signal<ModelProgress | null>(null);\n readonly error = signal<unknown>(null);\n /** True once the model is usable (including while a run is in flight). */\n readonly ready = computed(() => this.status() === 'ready' || this.status() === 'busy');\n readonly busy = computed(() => this.status() === 'busy' || this.status() === 'loading');\n\n private session = newSession();\n private destroyed = false;\n\n constructor(\n private readonly request: PipelineRequest,\n private readonly factory: PipelineFactory,\n private readonly config: NgxTransformersConfig,\n ) {}\n\n /** Downloads and initializes the model. Idempotent; retries after error. */\n load(): Promise<void> {\n if (this.destroyed) return Promise.reject(destroyedError());\n const session = this.session;\n if (session.pipe) return Promise.resolve();\n session.loading ??= this.doLoad(session).finally(() => {\n session.loading = null;\n });\n return session.loading;\n }\n\n /** Runs the pipeline, loading the model first if needed. */\n run(input: TIn, runOptions?: Record<string, unknown>): Promise<TOut> {\n return this.runWith(input, runOptions);\n }\n\n /**\n * Runs the pipeline with extra positional arguments after the input, for\n * tasks whose pipeline signature is not (input, options): zero-shot\n * classification takes (text, candidateLabels, options).\n */\n protected async runWith(input: TIn, ...extraArgs: unknown[]): Promise<TOut> {\n await this.load();\n const session = this.session;\n const pipe = session.pipe;\n if (!pipe) {\n throw new Error('PipelineHandle: disposed before the model finished loading.');\n }\n session.inFlight++;\n this.status.set('busy');\n try {\n return (await (pipe as Runnable)(input, ...extraArgs)) as TOut;\n } finally {\n // Back to ready once the last overlapping run finishes - a failed run\n // leaves the model intact. A run that outlived dispose() settles its\n // own, retired session and leaves the status alone.\n session.inFlight--;\n if (session.inFlight === 0 && this.session === session) this.status.set('ready');\n }\n }\n\n /**\n * Frees the model. A download still in flight is cancelled: its model is\n * released on arrival and the handle stays idle. The handle can be loaded\n * again afterwards; destroy() is the terminal variant.\n */\n async dispose(): Promise<void> {\n const session = this.session;\n this.session = newSession();\n this.status.set('idle');\n this.progress.set(null);\n await session.pipe?.dispose?.();\n }\n\n /**\n * dispose() for good: later load() and run() calls reject instead of\n * downloading a model nobody would release. create*() registers this with\n * the DestroyRef of the injection context, so a handle declared in a\n * component ends with the component.\n */\n destroy(): Promise<void> {\n this.destroyed = true;\n return this.dispose();\n }\n\n private async doLoad(session: Session): Promise<void> {\n this.status.set('loading');\n this.error.set(null);\n const options: Record<string, unknown> = {\n ...this.config.pipelineOptions,\n ...this.request.options,\n progress_callback: (event: RawProgressEvent) => this.onProgress(event, session),\n };\n const device = await this.resolveDevice();\n // Disposed while probing the device: do not start the download at all.\n if (this.session !== session) return;\n const dtype = this.request.dtype ?? this.config.dtype;\n if (device && device !== 'auto') options['device'] = device;\n if (dtype) options['dtype'] = dtype;\n\n try {\n const pipe = await this.factory(this.request.task, this.request.model, options);\n if (this.session !== session) {\n // Disposed while downloading: nobody wants this model any more.\n await pipe.dispose?.();\n return;\n }\n session.pipe = pipe;\n this.progress.set(null);\n this.status.set('ready');\n } catch (err) {\n // A cancelled load is not an error - dispose() already reset the handle.\n if (this.session !== session) return;\n this.error.set(err);\n this.status.set('error');\n throw err;\n }\n }\n\n /**\n * An explicit request or global device wins; with `autoDevice` on, an\n * unset or 'auto' device is probed for WebGPU (once, cached) at load time.\n */\n private async resolveDevice(): Promise<TransformersDevice | undefined> {\n const configured = this.request.device ?? this.config.device;\n if (configured && configured !== 'auto') return configured;\n return this.config.autoDevice ? detectDevice() : configured;\n }\n\n private onProgress(event: RawProgressEvent, session: Session): void {\n // Events from a load that dispose() cancelled must not resurrect the bar.\n if (this.session !== session) return;\n if (event.status !== 'progress' || !event.file) return;\n this.progress.set({\n file: event.file,\n progress: Math.round(event.progress ?? 0),\n loadedBytes: event.loaded ?? 0,\n totalBytes: event.total ?? 0,\n });\n }\n}\n\nfunction destroyedError(): Error {\n return new Error('PipelineHandle: destroyed with its component; create a new handle.');\n}\n\n/**\n * Creates a PipelineHandle in an injection context (constructor, field\n * initializer, or runInInjectionContext). The handle is destroyed with the\n * surrounding component/injector.\n */\nexport function createPipeline<TIn = unknown, TOut = unknown>(\n request: PipelineRequest,\n): PipelineHandle<TIn, TOut> {\n const handle = new PipelineHandle<TIn, TOut>(\n request,\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void handle.destroy());\n return handle;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { ClassificationResult, PipelineRequest } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\nexport const DEFAULT_TEXT_CLASSIFICATION_MODEL =\n 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';\n\n/**\n * Text classification (sentiment by default). The default model is\n * DistilBERT SST-2 (~65 MB, q8) - swap `model` for any Transformers.js\n * compatible text-classification checkpoint.\n */\nexport class TextClassifier extends PipelineHandle<\n string,\n ClassificationResult[] | ClassificationResult[][]\n> {\n /** Classifies one text; resolves to labels sorted by score (top first). */\n async classify(text: string, topK = 1): Promise<ClassificationResult[]> {\n const out = await this.run(text, { top_k: topK });\n // Single input: transformers.js returns a flat array of {label, score}.\n const flat = (Array.isArray(out[0]) ? out[0] : out) as ClassificationResult[];\n return [...flat].sort((a, b) => b.score - a.score);\n }\n}\n\n/** Creates a TextClassifier in an injection context. */\nexport function createTextClassifier(\n options: Partial<Omit<PipelineRequest, 'task'>> = {},\n): TextClassifier {\n const classifier = new TextClassifier(\n { task: 'text-classification', model: DEFAULT_TEXT_CLASSIFICATION_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.destroy());\n return classifier;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { PipelineRequest, RankedResult } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\nexport const DEFAULT_EMBEDDING_MODEL = 'Xenova/all-MiniLM-L6-v2';\n\n/** Tensor-ish output of feature-extraction: enough shape to read rows. */\ninterface TensorLike {\n dims: number[];\n data: ArrayLike<number>;\n tolist?: () => number[][];\n}\n\n/** Cosine similarity of two vectors. For normalized vectors this is the dot product. */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n if (a.length !== b.length || a.length === 0) {\n throw new Error(`cosineSimilarity: incompatible lengths ${a.length} and ${b.length}`);\n }\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n\n/**\n * Sentence embeddings via feature-extraction (all-MiniLM-L6-v2 by default,\n * ~23 MB q8). Outputs mean-pooled, L2-normalized vectors ready for cosine\n * similarity / semantic search.\n */\nexport class TextEmbedder extends PipelineHandle<string | string[], TensorLike> {\n /** Embeds one or many texts; always resolves to one vector per text. */\n async embed(texts: string | string[]): Promise<number[][]> {\n const input = Array.isArray(texts) ? texts : [texts];\n if (input.length === 0) return [];\n const out = await this.run(input, { pooling: 'mean', normalize: true });\n return toRows(out);\n }\n\n /** Cosine similarity of two texts in [-1, 1]. */\n async similarity(a: string, b: string): Promise<number> {\n const [va, vb] = await this.embed([a, b]);\n return cosineSimilarity(va, vb);\n }\n\n /** Ranks documents against a query, most similar first. */\n async rank(query: string, documents: string[]): Promise<RankedResult[]> {\n if (documents.length === 0) return [];\n const [queryVec, ...docVecs] = await this.embed([query, ...documents]);\n return docVecs\n .map((vec, index) => ({\n text: documents[index],\n score: cosineSimilarity(queryVec, vec),\n index,\n }))\n .sort((a, b) => b.score - a.score);\n }\n}\n\nfunction toRows(out: TensorLike): number[][] {\n if (typeof out.tolist === 'function') return out.tolist();\n const [rows, cols] = out.dims.length === 2 ? out.dims : [1, out.dims[out.dims.length - 1]];\n const data = out.data;\n const result: number[][] = [];\n for (let r = 0; r < rows; r++) {\n result.push(Array.from({ length: cols }, (_, c) => data[r * cols + c]));\n }\n return result;\n}\n\n/** Creates a TextEmbedder in an injection context. */\nexport function createTextEmbedder(\n options: Partial<Omit<PipelineRequest, 'task'>> = {},\n): TextEmbedder {\n const embedder = new TextEmbedder(\n { task: 'feature-extraction', model: DEFAULT_EMBEDDING_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void embedder.destroy());\n return embedder;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type {\n PipelineRequest,\n TranscribeOptions,\n Transcription,\n TranscriptionChunk,\n} from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\n// onnx-community, not the legacy Xenova export: the old ONNX decoder lacks\n// the quantization scales transformers.js v4's runtime requires.\nexport const DEFAULT_ASR_MODEL = 'onnx-community/whisper-tiny.en';\n\n/** Whisper expects 16 kHz mono float PCM. */\nexport const WHISPER_SAMPLE_RATE = 16000;\n\n/** Raw ASR pipeline output (subset we consume). */\ninterface RawTranscription {\n text?: string;\n chunks?: { text: string; timestamp?: [number | null, number | null] }[];\n}\n\n/**\n * Decodes an encoded audio file (wav/mp3/webm/ogg - anything the browser\n * can decode) to 16 kHz mono Float32Array, ready for Whisper. Browser-only:\n * uses AudioContext with a target sample rate, which resamples on decode.\n */\nexport async function decodeAudio(\n source: Blob | ArrayBuffer,\n targetSampleRate = WHISPER_SAMPLE_RATE,\n): Promise<Float32Array> {\n const AudioContextCtor = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n if (!AudioContextCtor) {\n throw new Error(\n 'decodeAudio requires a browser AudioContext (not available in this environment).',\n );\n }\n const buffer = source instanceof Blob ? await source.arrayBuffer() : source;\n const ctx = new AudioContextCtor({ sampleRate: targetSampleRate });\n try {\n const decoded = await ctx.decodeAudioData(buffer);\n if (decoded.numberOfChannels === 1) return decoded.getChannelData(0);\n // Mix down to mono by averaging channels.\n const left = decoded.getChannelData(0);\n const right = decoded.getChannelData(1);\n const mono = new Float32Array(left.length);\n for (let i = 0; i < left.length; i++) mono[i] = (left[i] + right[i]) / 2;\n return mono;\n } finally {\n await ctx.close();\n }\n}\n\n/**\n * Speech-to-text via Whisper. The default checkpoint is whisper-tiny.en\n * (~41 MB q8, English-only); swap `model` for a multilingual or larger one\n * (e.g. Xenova/whisper-small).\n */\nexport class SpeechRecognizer extends PipelineHandle<\n string | Float32Array,\n RawTranscription | RawTranscription[]\n> {\n /**\n * Transcribes audio: a URL, a decoded 16 kHz Float32Array, or an encoded\n * Blob/ArrayBuffer (decoded via decodeAudio first - browser-only).\n */\n async transcribe(\n audio: string | Float32Array | Blob | ArrayBuffer,\n options: TranscribeOptions = {},\n ): Promise<Transcription> {\n const input =\n audio instanceof Blob || audio instanceof ArrayBuffer ? await decodeAudio(audio) : audio;\n\n const runOptions: Record<string, unknown> = {};\n if (options.returnTimestamps !== undefined)\n runOptions['return_timestamps'] = options.returnTimestamps;\n if (options.chunkLengthS !== undefined) runOptions['chunk_length_s'] = options.chunkLengthS;\n if (options.strideLengthS !== undefined) runOptions['stride_length_s'] = options.strideLengthS;\n if (options.language !== undefined) runOptions['language'] = options.language;\n if (options.task !== undefined) runOptions['task'] = options.task;\n\n const raw = await this.run(input, runOptions);\n const first = (Array.isArray(raw) ? raw[0] : raw) ?? {};\n const chunks: TranscriptionChunk[] | undefined = first.chunks?.map((c) => ({\n text: c.text,\n start: c.timestamp?.[0] ?? null,\n end: c.timestamp?.[1] ?? null,\n }));\n return { text: (first.text ?? '').trim(), ...(chunks ? { chunks } : {}) };\n }\n}\n\n/**\n * Creates a SpeechRecognizer in an injection context.\n *\n * dtype defaults to 'q4' (not the library-wide default): q8 Whisper\n * decoders fail session creation on the v4 WASM runtime\n * (huggingface/transformers.js#1707), while q4 loads and runs everywhere.\n */\nexport function createSpeechRecognizer(\n options: Partial<Omit<PipelineRequest, 'task'>> = {},\n): SpeechRecognizer {\n const recognizer = new SpeechRecognizer(\n { task: 'automatic-speech-recognition', model: DEFAULT_ASR_MODEL, dtype: 'q4', ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void recognizer.destroy());\n return recognizer;\n}\n","import { DestroyRef, inject } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type { ClassificationResult, PipelineRequest, ZeroShotOptions } from './transformers.models';\nimport { NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY } from './transformers.providers';\n\n// The Transformers.js docs example for this task and the smallest MNLI\n// checkpoint that behaves well on the WASM runtime (~26 MB q8).\nexport const DEFAULT_ZERO_SHOT_MODEL = 'Xenova/mobilebert-uncased-mnli';\n\n/** Raw zero-shot output: labels ordered by score, scores aligned by index. */\ninterface RawZeroShotResult {\n sequence: string;\n labels: string[];\n scores: number[];\n}\n\n/**\n * Zero-shot classification: score any labels you name against a text with\n * an NLI model, no fine-tuning. The default checkpoint is MobileBERT MNLI\n * (~26 MB q8); Xenova/distilbert-base-uncased-mnli (~80 MB) is the\n * higher-accuracy alternative.\n */\nexport class ZeroShotClassifier extends PipelineHandle<\n string,\n RawZeroShotResult | RawZeroShotResult[]\n> {\n /**\n * Scores each candidate label for one text; resolves sorted by score (top\n * first). Single-label mode (default) normalizes across labels so scores\n * sum to 1; `multiLabel` scores each label on its own.\n */\n async classify(\n text: string,\n labels: readonly string[],\n options: ZeroShotOptions = {},\n ): Promise<ClassificationResult[]> {\n if (labels.length === 0) return [];\n const runOptions: Record<string, unknown> = {};\n if (options.multiLabel !== undefined) runOptions['multi_label'] = options.multiLabel;\n if (options.hypothesisTemplate !== undefined)\n runOptions['hypothesis_template'] = options.hypothesisTemplate;\n\n const raw = await this.runWith(text, [...labels], runOptions);\n const first = Array.isArray(raw) ? raw[0] : raw;\n const scoredLabels = first?.labels ?? [];\n const scores = first?.scores ?? [];\n return scoredLabels\n .map((label, index) => ({ label, score: scores[index] ?? 0 }))\n .sort((left, right) => right.score - left.score);\n }\n}\n\n/** Creates a ZeroShotClassifier in an injection context. */\nexport function createZeroShotClassifier(\n options: Partial<Omit<PipelineRequest, 'task'>> = {},\n): ZeroShotClassifier {\n const classifier = new ZeroShotClassifier(\n { task: 'zero-shot-classification', model: DEFAULT_ZERO_SHOT_MODEL, ...options },\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void classifier.destroy());\n return classifier;\n}\n","import { DestroyRef, computed, inject, signal } from '@angular/core';\nimport { PipelineHandle } from './pipeline';\nimport type {\n NgxTransformersConfig,\n TranslateOptions,\n TranslatorOptions,\n} from './transformers.models';\nimport {\n NGX_TRANSFORMERS_CONFIG,\n PIPELINE_FACTORY,\n type PipelineFactory,\n} from './transformers.providers';\n\n/**\n * Default checkpoint for a language pair: Helsinki-NLP's Marian opus-mt\n * models, one per direction, ~105 MB q8 each (e.g. Xenova/opus-mt-en-ru).\n */\nexport function defaultTranslationModel(from: string, to: string): string {\n return `Xenova/opus-mt-${from}-${to}`;\n}\n\n/** Checkpoint for a pair: provideTransformers({ translationModels }) first, then opus-mt. */\nexport function resolveTranslationModel(\n from: string,\n to: string,\n config: NgxTransformersConfig,\n): string {\n return config.translationModels?.[`${from}-${to}`] ?? defaultTranslationModel(from, to);\n}\n\n/**\n * Multilingual families take the pair per call as src_lang / tgt_lang;\n * Marian opus-mt checkpoints translate one fixed direction and ignore them.\n */\nconst MULTILINGUAL_MODEL_PATTERN = /nllb|m2m[_-]?100|mbart|madlad/i;\n\n/** Raw translation pipeline output, one entry per input text. */\ninterface RawTranslation {\n translation_text?: string;\n}\n\nexport type TranslationHandle = PipelineHandle<string, RawTranslation | RawTranslation[]>;\n\n/**\n * Text translation. Pipelines are created lazily, one per checkpoint: with\n * the default opus-mt family every language pair is its own model, so a\n * Translator holds one handle per pair it has been asked for, while a\n * pinned multilingual `model` (NLLB, M2M100) serves every pair from one.\n *\n * The signals mirror the handle used by the most recent call, so a single\n * `<ngx-model-progress>` covers the translator.\n */\nexport class Translator {\n private readonly active = signal<TranslationHandle | null>(null);\n private readonly handles = new Map<string, TranslationHandle>();\n private destroyed = false;\n\n readonly status = computed(() => this.active()?.status() ?? 'idle');\n readonly progress = computed(() => this.active()?.progress() ?? null);\n readonly error = computed(() => this.active()?.error() ?? null);\n readonly ready = computed(() => this.active()?.ready() ?? false);\n readonly busy = computed(() => this.active()?.busy() ?? false);\n\n constructor(\n private readonly options: TranslatorOptions,\n private readonly factory: PipelineFactory,\n private readonly config: NgxTransformersConfig,\n ) {}\n\n /** Downloads the model for a pair ahead of the first translate() call. */\n async load(pair: TranslateOptions = {}): Promise<void> {\n return this.handleFor(pair).load();\n }\n\n /** Translates one text; the pair defaults to the one given at creation. */\n async translate(text: string, pair: TranslateOptions = {}): Promise<string> {\n const handle = this.handleFor(pair);\n const raw = await handle.run(text, this.languageOptions(pair));\n const first = Array.isArray(raw) ? raw[0] : raw;\n return (first?.translation_text ?? '').trim();\n }\n\n /** Checkpoint for a pair: the pinned model, else the configured or default one. */\n modelFor(pair: TranslateOptions = {}): string {\n if (this.options.model) return this.options.model;\n const from = pair.from ?? this.options.from;\n const to = pair.to ?? this.options.to;\n if (!from || !to) {\n throw new Error(\n 'Translator: no language pair - pass { from, to } to createTranslator() or translate(), or pin a multilingual model.',\n );\n }\n return resolveTranslationModel(from, to, this.config);\n }\n\n /**\n * The handle serving a pair, created on first use. Exposed for apps that\n * keep several pairs warm and want a progress line per model.\n */\n handleFor(pair: TranslateOptions = {}): TranslationHandle {\n if (this.destroyed) {\n throw new Error('Translator: destroyed with its component; create a new translator.');\n }\n const model = this.modelFor(pair);\n let handle = this.handles.get(model);\n if (!handle) {\n handle = new PipelineHandle(\n {\n task: 'translation',\n model,\n device: this.options.device,\n dtype: this.options.dtype,\n options: this.options.options,\n },\n this.factory,\n this.config,\n );\n this.handles.set(model, handle);\n }\n this.active.set(handle);\n return handle;\n }\n\n /**\n * dispose() for good: later calls reject instead of loading a model nobody\n * would release. createTranslator() registers this with the DestroyRef.\n */\n destroy(): Promise<void> {\n this.destroyed = true;\n return this.dispose();\n }\n\n /** Frees every model. The translator can be used again afterwards. */\n async dispose(): Promise<void> {\n const handles = [...this.handles.values()];\n this.handles.clear();\n this.active.set(null);\n await Promise.all(handles.map((handle) => handle.dispose()));\n }\n\n /** src_lang / tgt_lang for multilingual checkpoints; opus-mt models get nothing. */\n private languageOptions(pair: TranslateOptions): Record<string, unknown> {\n const runOptions: Record<string, unknown> = {};\n if (!MULTILINGUAL_MODEL_PATTERN.test(this.modelFor(pair))) return runOptions;\n const from = pair.from ?? this.options.from;\n const to = pair.to ?? this.options.to;\n if (from !== undefined) runOptions['src_lang'] = from;\n if (to !== undefined) runOptions['tgt_lang'] = to;\n return runOptions;\n }\n}\n\n/** Creates a Translator in an injection context. */\nexport function createTranslator(options: TranslatorOptions = {}): Translator {\n const translator = new Translator(\n options,\n inject(PIPELINE_FACTORY),\n inject(NGX_TRANSFORMERS_CONFIG),\n );\n inject(DestroyRef, { optional: true })?.onDestroy(() => void translator.destroy());\n return translator;\n}\n","import { DestroyRef, inject, signal } from '@angular/core';\n\n/** Minimal recorder surface - lets tests (and exotic runtimes) inject fakes. */\nexport interface RecorderLike {\n start(): void;\n stop(): void;\n ondataavailable: ((event: { data: Blob }) => void) | null;\n onstop: (() => void) | null;\n mimeType?: string;\n}\n\nexport interface MicRecorderDeps {\n /** Defaults to navigator.mediaDevices.getUserMedia({ audio: true }). */\n getUserMedia?: () => Promise<MediaStream>;\n /** Defaults to new MediaRecorder(stream). */\n createRecorder?: (stream: MediaStream) => RecorderLike;\n}\n\n/**\n * Microphone capture with a signals API. start() asks for mic permission\n * and records; stop() resolves with the encoded audio Blob - pass it to\n * SpeechRecognizer.transcribe(). Browser-only.\n *\n * ```ts\n * readonly mic = createMicRecorder();\n * readonly whisper = createSpeechRecognizer();\n *\n * async toggle() {\n * if (this.mic.recording()) {\n * const audio = await this.mic.stop();\n * const { text } = await this.whisper.transcribe(audio);\n * } else {\n * await this.mic.start();\n * }\n * }\n * ```\n */\nexport class MicRecorder {\n readonly recording = signal(false);\n /** Elapsed recording time in whole seconds. */\n readonly seconds = signal(0);\n readonly error = signal<unknown>(null);\n\n private stream: MediaStream | null = null;\n private recorder: RecorderLike | null = null;\n private chunks: Blob[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(private readonly deps: MicRecorderDeps = {}) {}\n\n /** Requests the microphone and starts recording. No-op while recording. */\n async start(): Promise<void> {\n if (this.recording()) return;\n this.error.set(null);\n try {\n this.stream = await (this.deps.getUserMedia\n ? this.deps.getUserMedia()\n : navigator.mediaDevices.getUserMedia({ audio: true }));\n this.recorder = this.deps.createRecorder\n ? this.deps.createRecorder(this.stream)\n : (new MediaRecorder(this.stream) as unknown as RecorderLike);\n this.chunks = [];\n this.recorder.ondataavailable = (event) => {\n if (event.data.size > 0) this.chunks.push(event.data);\n };\n this.recorder.start();\n this.recording.set(true);\n this.seconds.set(0);\n this.timer = setInterval(() => this.seconds.set(this.seconds() + 1), 1000);\n } catch (err) {\n this.error.set(err);\n this.cleanup();\n throw err;\n }\n }\n\n /** Stops recording and resolves with the captured audio. */\n stop(): Promise<Blob> {\n const recorder = this.recorder;\n if (!recorder || !this.recording()) {\n return Promise.reject(new Error('MicRecorder.stop() called while not recording.'));\n }\n return new Promise<Blob>((resolve) => {\n recorder.onstop = () => {\n const blob = new Blob(this.chunks, { type: recorder.mimeType || 'audio/webm' });\n this.cleanup();\n resolve(blob);\n };\n recorder.stop();\n });\n }\n\n /** Stops tracks and timers without resolving audio (e.g. on destroy). */\n dispose(): void {\n this.cleanup();\n }\n\n private cleanup(): void {\n if (this.timer !== null) clearInterval(this.timer);\n this.timer = null;\n this.stream?.getTracks().forEach((track) => track.stop());\n this.stream = null;\n this.recorder = null;\n this.recording.set(false);\n }\n}\n\n/** Creates a MicRecorder in an injection context; disposed with the component. */\nexport function createMicRecorder(deps: MicRecorderDeps = {}): MicRecorder {\n const recorder = new MicRecorder(deps);\n inject(DestroyRef, { optional: true })?.onDestroy(() => recorder.dispose());\n return recorder;\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport type { ModelProgress, PipelineStatus } from './transformers.models';\n\n/**\n * Drop-in status line for a PipelineHandle: shows model download progress\n * while loading, then the ready/busy/error state. Themeable via CSS custom\n * properties (--nt-accent, --nt-ink, --nt-muted, --nt-track).\n *\n * ```html\n * <ngx-model-progress [status]=\"classifier.status()\" [progress]=\"classifier.progress()\" />\n * ```\n */\n@Component({\n selector: 'ngx-model-progress',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"nt-row\" [class.nt-error]=\"status() === 'error'\" role=\"status\">\n <span class=\"nt-dot\" [attr.data-status]=\"status()\"></span>\n <span class=\"nt-label\">{{ label() }}</span>\n @if (status() === 'loading' && progress(); as p) {\n <span class=\"nt-file\">{{ p.file }}</span>\n <div\n class=\"nt-track\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"p.progress\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n >\n <div class=\"nt-fill\" [style.width.%]=\"p.progress\"></div>\n </div>\n <span class=\"nt-pct\">{{ p.progress }}%</span>\n }\n </div>\n `,\n styles: `\n :host {\n --nt-accent: #f59e0b;\n --nt-ink: #1e293b;\n --nt-muted: #64748b;\n --nt-track: #e2e8f0;\n display: block;\n font-size: 12.5px;\n color: var(--nt-ink);\n }\n .nt-row {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .nt-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex: none;\n background: var(--nt-muted);\n }\n .nt-dot[data-status='loading'] {\n background: var(--nt-accent);\n animation: nt-blink 1s ease-in-out infinite;\n }\n .nt-dot[data-status='ready'] {\n background: #22c55e;\n }\n .nt-dot[data-status='busy'] {\n background: #3b82f6;\n animation: nt-blink 0.7s ease-in-out infinite;\n }\n .nt-dot[data-status='error'] {\n background: #dc2626;\n }\n .nt-label {\n font-weight: 600;\n }\n .nt-file {\n color: var(--nt-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 180px;\n }\n .nt-track {\n flex: 1;\n min-width: 60px;\n height: 6px;\n border-radius: 3px;\n background: var(--nt-track);\n overflow: hidden;\n }\n .nt-fill {\n height: 100%;\n background: var(--nt-accent);\n border-radius: 3px;\n transition: width 120ms linear;\n }\n .nt-pct {\n font-variant-numeric: tabular-nums;\n color: var(--nt-muted);\n }\n .nt-error .nt-label {\n color: #dc2626;\n }\n @keyframes nt-blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.35;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .nt-dot {\n animation: none;\n }\n .nt-fill {\n transition: none;\n }\n }\n `,\n})\nexport class ModelProgressComponent {\n status = input.required<PipelineStatus>();\n progress = input<ModelProgress | null>(null);\n /** Labels per status; override to localize. */\n labels = input<Partial<Record<PipelineStatus, string>>>({});\n\n readonly label = computed(() => {\n const defaults: Record<PipelineStatus, string> = {\n idle: 'Model not loaded',\n loading: 'Downloading model',\n ready: 'Model ready',\n busy: 'Running',\n error: 'Failed to load model',\n };\n return this.labels()[this.status()] ?? defaults[this.status()];\n });\n}\n","/*\n * Public API Surface of ngx-transformers\n */\n\nexport * from './lib/transformers.models';\nexport * from './lib/transformers.providers';\nexport * from './lib/pipeline';\nexport * from './lib/device-detection';\nexport * from './lib/text-classifier';\nexport * from './lib/text-embedder';\nexport * from './lib/speech-recognizer';\nexport * from './lib/zero-shot-classifier';\nexport * from './lib/translator';\nexport * from './lib/mic-recorder';\nexport * from './lib/model-progress.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-transformers",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Run Hugging Face Transformers.js models in Angular - on-device ML with a signals API: text classification, zero-shot classification, embeddings, semantic search, translation, Whisper speech-to-text. No server, no API key.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -112,6 +112,31 @@ type PipelineLike = ((input: unknown, options?: Record<string, unknown>) => Prom
|
|
|
112
112
|
* @huggingface/transformers; tests and SSR shims can provide their own.
|
|
113
113
|
*/
|
|
114
114
|
type PipelineFactory = (task: string, model: string | undefined, options: Record<string, unknown>) => Promise<PipelineLike>;
|
|
115
|
+
/**
|
|
116
|
+
* The slice of the @huggingface/transformers module the default factory
|
|
117
|
+
* uses. The real module satisfies it, so an importer can configure
|
|
118
|
+
* `env` and return the module as is.
|
|
119
|
+
*/
|
|
120
|
+
interface TransformersModuleLike {
|
|
121
|
+
pipeline(task: string, model?: string, options?: object): Promise<unknown>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The factory behind PIPELINE_FACTORY. It imports @huggingface/transformers
|
|
125
|
+
* lazily, on the first pipeline, so the library adds nothing to the initial
|
|
126
|
+
* bundle. Wrap it to add options or logging while keeping the lazy import:
|
|
127
|
+
*
|
|
128
|
+
* ```ts
|
|
129
|
+
* const base = createDefaultPipelineFactory();
|
|
130
|
+
* const factory: PipelineFactory = (task, model, options) =>
|
|
131
|
+
* base(task, model, { ...options, revision: 'v2' });
|
|
132
|
+
* providers: [{ provide: PIPELINE_FACTORY, useValue: factory }]
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* `load` is the importer. Tests pass a stub module; apps that need to
|
|
136
|
+
* configure Transformers.js (`env.allowRemoteModels`, `env.localModelPath`)
|
|
137
|
+
* do it there, before returning the module.
|
|
138
|
+
*/
|
|
139
|
+
declare function createDefaultPipelineFactory(load?: () => Promise<TransformersModuleLike>): PipelineFactory;
|
|
115
140
|
declare const PIPELINE_FACTORY: InjectionToken<PipelineFactory>;
|
|
116
141
|
declare const NGX_TRANSFORMERS_CONFIG: InjectionToken<NgxTransformersConfig>;
|
|
117
142
|
/**
|
|
@@ -144,8 +169,8 @@ declare class PipelineHandle<TIn = unknown, TOut = unknown> {
|
|
|
144
169
|
/** True once the model is usable (including while a run is in flight). */
|
|
145
170
|
readonly ready: _angular_core.Signal<boolean>;
|
|
146
171
|
readonly busy: _angular_core.Signal<boolean>;
|
|
147
|
-
private
|
|
148
|
-
private
|
|
172
|
+
private session;
|
|
173
|
+
private destroyed;
|
|
149
174
|
constructor(request: PipelineRequest, factory: PipelineFactory, config: NgxTransformersConfig);
|
|
150
175
|
/** Downloads and initializes the model. Idempotent; retries after error. */
|
|
151
176
|
load(): Promise<void>;
|
|
@@ -157,8 +182,19 @@ declare class PipelineHandle<TIn = unknown, TOut = unknown> {
|
|
|
157
182
|
* classification takes (text, candidateLabels, options).
|
|
158
183
|
*/
|
|
159
184
|
protected runWith(input: TIn, ...extraArgs: unknown[]): Promise<TOut>;
|
|
160
|
-
/**
|
|
185
|
+
/**
|
|
186
|
+
* Frees the model. A download still in flight is cancelled: its model is
|
|
187
|
+
* released on arrival and the handle stays idle. The handle can be loaded
|
|
188
|
+
* again afterwards; destroy() is the terminal variant.
|
|
189
|
+
*/
|
|
161
190
|
dispose(): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* dispose() for good: later load() and run() calls reject instead of
|
|
193
|
+
* downloading a model nobody would release. create*() registers this with
|
|
194
|
+
* the DestroyRef of the injection context, so a handle declared in a
|
|
195
|
+
* component ends with the component.
|
|
196
|
+
*/
|
|
197
|
+
destroy(): Promise<void>;
|
|
162
198
|
private doLoad;
|
|
163
199
|
/**
|
|
164
200
|
* An explicit request or global device wins; with `autoDevice` on, an
|
|
@@ -169,7 +205,7 @@ declare class PipelineHandle<TIn = unknown, TOut = unknown> {
|
|
|
169
205
|
}
|
|
170
206
|
/**
|
|
171
207
|
* Creates a PipelineHandle in an injection context (constructor, field
|
|
172
|
-
* initializer, or runInInjectionContext). The handle is
|
|
208
|
+
* initializer, or runInInjectionContext). The handle is destroyed with the
|
|
173
209
|
* surrounding component/injector.
|
|
174
210
|
*/
|
|
175
211
|
declare function createPipeline<TIn = unknown, TOut = unknown>(request: PipelineRequest): PipelineHandle<TIn, TOut>;
|
|
@@ -313,6 +349,7 @@ declare class Translator {
|
|
|
313
349
|
private readonly config;
|
|
314
350
|
private readonly active;
|
|
315
351
|
private readonly handles;
|
|
352
|
+
private destroyed;
|
|
316
353
|
readonly status: _angular_core.Signal<ngx_transformers.PipelineStatus>;
|
|
317
354
|
readonly progress: _angular_core.Signal<ngx_transformers.ModelProgress | null>;
|
|
318
355
|
readonly error: _angular_core.Signal<{} | null>;
|
|
@@ -330,6 +367,11 @@ declare class Translator {
|
|
|
330
367
|
* keep several pairs warm and want a progress line per model.
|
|
331
368
|
*/
|
|
332
369
|
handleFor(pair?: TranslateOptions): TranslationHandle;
|
|
370
|
+
/**
|
|
371
|
+
* dispose() for good: later calls reject instead of loading a model nobody
|
|
372
|
+
* would release. createTranslator() registers this with the DestroyRef.
|
|
373
|
+
*/
|
|
374
|
+
destroy(): Promise<void>;
|
|
333
375
|
/** Frees every model. The translator can be used again afterwards. */
|
|
334
376
|
dispose(): Promise<void>;
|
|
335
377
|
/** src_lang / tgt_lang for multilingual checkpoints; opus-mt models get nothing. */
|
|
@@ -414,5 +456,5 @@ declare class ModelProgressComponent {
|
|
|
414
456
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ModelProgressComponent, "ngx-model-progress", never, { "status": { "alias": "status"; "required": true; "isSignal": true; }; "progress": { "alias": "progress"; "required": false; "isSignal": true; }; "labels": { "alias": "labels"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
415
457
|
}
|
|
416
458
|
|
|
417
|
-
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, DEFAULT_ZERO_SHOT_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, Translator, WHISPER_SAMPLE_RATE, ZeroShotClassifier, cosineSimilarity, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, createTranslator, createZeroShotClassifier, decodeAudio, defaultTranslationModel, detectDevice, hasWebGpu, provideTransformers, resetDeviceDetection, resolveTranslationModel };
|
|
418
|
-
export type { ClassificationResult, MicRecorderDeps, ModelProgress, NgxTransformersConfig, PipelineFactory, PipelineLike, PipelineRequest, PipelineStatus, RankedResult, RecorderLike, TranscribeOptions, Transcription, TranscriptionChunk, TransformersDevice, TransformersDtype, TranslateOptions, TranslationHandle, TranslatorOptions, ZeroShotOptions };
|
|
459
|
+
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, DEFAULT_ZERO_SHOT_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, Translator, WHISPER_SAMPLE_RATE, ZeroShotClassifier, cosineSimilarity, createDefaultPipelineFactory, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, createTranslator, createZeroShotClassifier, decodeAudio, defaultTranslationModel, detectDevice, hasWebGpu, provideTransformers, resetDeviceDetection, resolveTranslationModel };
|
|
460
|
+
export type { ClassificationResult, MicRecorderDeps, ModelProgress, NgxTransformersConfig, PipelineFactory, PipelineLike, PipelineRequest, PipelineStatus, RankedResult, RecorderLike, TranscribeOptions, Transcription, TranscriptionChunk, TransformersDevice, TransformersDtype, TransformersModuleLike, TranslateOptions, TranslationHandle, TranslatorOptions, ZeroShotOptions };
|