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 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
  [![CI](https://github.com/qwertymuzaffar/ngx-transformers/actions/workflows/ci.yml/badge.svg)](https://github.com/qwertymuzaffar/ngx-transformers/actions/workflows/ci.yml)
5
5
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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
- **[Live demo (Storybook)](https://qwertymuzaffar.github.io/ngx-transformers/)** - loads real models in your browser.
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 disposed with the surrounding component.
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
- ## Roadmap
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
- - Zero-shot classification and translation wrappers
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 defaultPipelineFactory = async (task, model, options) => {
5
- const { pipeline } = await import('@huggingface/transformers');
6
- const pipe = await pipeline(task, model, options);
7
- return pipe;
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: () => defaultPipelineFactory,
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
- pipe = null;
86
- loading = null;
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.pipe)
113
+ if (this.destroyed)
114
+ return Promise.reject(destroyedError());
115
+ const session = this.session;
116
+ if (session.pipe)
95
117
  return Promise.resolve();
96
- this.loading ??= this.doLoad().finally(() => (this.loading = null));
97
- return this.loading;
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
- // A failed run leaves the model intact - back to ready either way.
117
- this.status.set('ready');
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
- /** Frees the model. The handle can be loaded again afterwards. */
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 pipe = this.pipe;
123
- this.pipe = null;
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
- this.pipe = await this.factory(this.request.task, this.request.model, options);
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 disposed with the
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.dispose());
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.dispose());
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) => ({ text: documents[index], score: cosineSimilarity(queryVec, 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.dispose());
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.dispose());
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.dispose());
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({ task: 'translation', model, device: this.options.device, dtype: this.options.dtype, options: this.options.options }, this.factory, this.config);
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.dispose());
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 class="nt-track" role="progressbar" [attr.aria-valuenow]="p.progress" aria-valuemin="0" aria-valuemax="100">
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 class="nt-track" role="progressbar" [attr.aria-valuenow]="p.progress" aria-valuemin="0" aria-valuemax="100">
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.0",
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 pipe;
148
- private loading;
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
- /** Frees the model. The handle can be loaded again afterwards. */
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 disposed with the
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 };