ngx-transformers 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -27,6 +27,37 @@ function provideTransformers(config) {
|
|
|
27
27
|
return makeEnvironmentProviders([{ provide: NGX_TRANSFORMERS_CONFIG, useValue: config }]);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
let webGpuProbe = null;
|
|
31
|
+
/**
|
|
32
|
+
* Whether models can run on WebGPU here: `navigator.gpu` exists AND
|
|
33
|
+
* `requestAdapter()` hands back an adapter - it returns null on machines
|
|
34
|
+
* without a usable GPU or with WebGPU disabled, even when the API exists.
|
|
35
|
+
* Resolves false on the server. The probe runs once and is cached.
|
|
36
|
+
*/
|
|
37
|
+
function hasWebGpu() {
|
|
38
|
+
webGpuProbe ??= probeWebGpu();
|
|
39
|
+
return webGpuProbe;
|
|
40
|
+
}
|
|
41
|
+
/** `'webgpu'` when hasWebGpu() resolves true, else `'wasm'`. */
|
|
42
|
+
async function detectDevice() {
|
|
43
|
+
return (await hasWebGpu()) ? 'webgpu' : 'wasm';
|
|
44
|
+
}
|
|
45
|
+
/** Forgets the cached probe so the next hasWebGpu() asks the browser again. */
|
|
46
|
+
function resetDeviceDetection() {
|
|
47
|
+
webGpuProbe = null;
|
|
48
|
+
}
|
|
49
|
+
async function probeWebGpu() {
|
|
50
|
+
const gpu = globalThis.navigator?.gpu;
|
|
51
|
+
if (!gpu)
|
|
52
|
+
return false;
|
|
53
|
+
try {
|
|
54
|
+
return (await gpu.requestAdapter()) !== null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
30
61
|
/**
|
|
31
62
|
* A lazily-loaded Transformers.js pipeline wrapped in signals.
|
|
32
63
|
*
|
|
@@ -66,11 +97,20 @@ class PipelineHandle {
|
|
|
66
97
|
return this.loading;
|
|
67
98
|
}
|
|
68
99
|
/** Runs the pipeline, loading the model first if needed. */
|
|
69
|
-
|
|
100
|
+
run(input, runOptions) {
|
|
101
|
+
return this.runWith(input, runOptions);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Runs the pipeline with extra positional arguments after the input, for
|
|
105
|
+
* tasks whose pipeline signature is not (input, options): zero-shot
|
|
106
|
+
* classification takes (text, candidateLabels, options).
|
|
107
|
+
*/
|
|
108
|
+
async runWith(input, ...extraArgs) {
|
|
70
109
|
await this.load();
|
|
71
110
|
this.status.set('busy');
|
|
72
111
|
try {
|
|
73
|
-
|
|
112
|
+
const pipe = this.pipe;
|
|
113
|
+
return (await pipe(input, ...extraArgs));
|
|
74
114
|
}
|
|
75
115
|
finally {
|
|
76
116
|
// A failed run leaves the model intact - back to ready either way.
|
|
@@ -93,7 +133,7 @@ class PipelineHandle {
|
|
|
93
133
|
...this.request.options,
|
|
94
134
|
progress_callback: (event) => this.onProgress(event),
|
|
95
135
|
};
|
|
96
|
-
const device =
|
|
136
|
+
const device = await this.resolveDevice();
|
|
97
137
|
const dtype = this.request.dtype ?? this.config.dtype;
|
|
98
138
|
if (device && device !== 'auto')
|
|
99
139
|
options['device'] = device;
|
|
@@ -110,6 +150,16 @@ class PipelineHandle {
|
|
|
110
150
|
throw err;
|
|
111
151
|
}
|
|
112
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* An explicit request or global device wins; with `autoDevice` on, an
|
|
155
|
+
* unset or 'auto' device is probed for WebGPU (once, cached) at load time.
|
|
156
|
+
*/
|
|
157
|
+
async resolveDevice() {
|
|
158
|
+
const configured = this.request.device ?? this.config.device;
|
|
159
|
+
if (configured && configured !== 'auto')
|
|
160
|
+
return configured;
|
|
161
|
+
return this.config.autoDevice ? detectDevice() : configured;
|
|
162
|
+
}
|
|
113
163
|
onProgress(event) {
|
|
114
164
|
if (event.status !== 'progress' || !event.file)
|
|
115
165
|
return;
|
|
@@ -297,6 +347,156 @@ function createSpeechRecognizer(options = {}) {
|
|
|
297
347
|
return recognizer;
|
|
298
348
|
}
|
|
299
349
|
|
|
350
|
+
// The Transformers.js docs example for this task and the smallest MNLI
|
|
351
|
+
// checkpoint that behaves well on the WASM runtime (~26 MB q8).
|
|
352
|
+
const DEFAULT_ZERO_SHOT_MODEL = 'Xenova/mobilebert-uncased-mnli';
|
|
353
|
+
/**
|
|
354
|
+
* Zero-shot classification: score any labels you name against a text with
|
|
355
|
+
* an NLI model, no fine-tuning. The default checkpoint is MobileBERT MNLI
|
|
356
|
+
* (~26 MB q8); Xenova/distilbert-base-uncased-mnli (~80 MB) is the
|
|
357
|
+
* higher-accuracy alternative.
|
|
358
|
+
*/
|
|
359
|
+
class ZeroShotClassifier extends PipelineHandle {
|
|
360
|
+
/**
|
|
361
|
+
* Scores each candidate label for one text; resolves sorted by score (top
|
|
362
|
+
* first). Single-label mode (default) normalizes across labels so scores
|
|
363
|
+
* sum to 1; `multiLabel` scores each label on its own.
|
|
364
|
+
*/
|
|
365
|
+
async classify(text, labels, options = {}) {
|
|
366
|
+
if (labels.length === 0)
|
|
367
|
+
return [];
|
|
368
|
+
const runOptions = {};
|
|
369
|
+
if (options.multiLabel !== undefined)
|
|
370
|
+
runOptions['multi_label'] = options.multiLabel;
|
|
371
|
+
if (options.hypothesisTemplate !== undefined)
|
|
372
|
+
runOptions['hypothesis_template'] = options.hypothesisTemplate;
|
|
373
|
+
const raw = await this.runWith(text, [...labels], runOptions);
|
|
374
|
+
const first = Array.isArray(raw) ? raw[0] : raw;
|
|
375
|
+
const scoredLabels = first?.labels ?? [];
|
|
376
|
+
const scores = first?.scores ?? [];
|
|
377
|
+
return scoredLabels
|
|
378
|
+
.map((label, index) => ({ label, score: scores[index] ?? 0 }))
|
|
379
|
+
.sort((left, right) => right.score - left.score);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/** Creates a ZeroShotClassifier in an injection context. */
|
|
383
|
+
function createZeroShotClassifier(options = {}) {
|
|
384
|
+
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());
|
|
386
|
+
return classifier;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Default checkpoint for a language pair: Helsinki-NLP's Marian opus-mt
|
|
391
|
+
* models, one per direction, ~105 MB q8 each (e.g. Xenova/opus-mt-en-ru).
|
|
392
|
+
*/
|
|
393
|
+
function defaultTranslationModel(from, to) {
|
|
394
|
+
return `Xenova/opus-mt-${from}-${to}`;
|
|
395
|
+
}
|
|
396
|
+
/** Checkpoint for a pair: provideTransformers({ translationModels }) first, then opus-mt. */
|
|
397
|
+
function resolveTranslationModel(from, to, config) {
|
|
398
|
+
return config.translationModels?.[`${from}-${to}`] ?? defaultTranslationModel(from, to);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Multilingual families take the pair per call as src_lang / tgt_lang;
|
|
402
|
+
* Marian opus-mt checkpoints translate one fixed direction and ignore them.
|
|
403
|
+
*/
|
|
404
|
+
const MULTILINGUAL_MODEL_PATTERN = /nllb|m2m[_-]?100|mbart|madlad/i;
|
|
405
|
+
/**
|
|
406
|
+
* Text translation. Pipelines are created lazily, one per checkpoint: with
|
|
407
|
+
* the default opus-mt family every language pair is its own model, so a
|
|
408
|
+
* Translator holds one handle per pair it has been asked for, while a
|
|
409
|
+
* pinned multilingual `model` (NLLB, M2M100) serves every pair from one.
|
|
410
|
+
*
|
|
411
|
+
* The signals mirror the handle used by the most recent call, so a single
|
|
412
|
+
* `<ngx-model-progress>` covers the translator.
|
|
413
|
+
*/
|
|
414
|
+
class Translator {
|
|
415
|
+
options;
|
|
416
|
+
factory;
|
|
417
|
+
config;
|
|
418
|
+
active = signal(null, /* @ts-ignore */
|
|
419
|
+
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
420
|
+
handles = new Map();
|
|
421
|
+
status = computed(() => this.active()?.status() ?? 'idle', /* @ts-ignore */
|
|
422
|
+
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
423
|
+
progress = computed(() => this.active()?.progress() ?? null, /* @ts-ignore */
|
|
424
|
+
...(ngDevMode ? [{ debugName: "progress" }] : /* istanbul ignore next */ []));
|
|
425
|
+
error = computed(() => this.active()?.error() ?? null, /* @ts-ignore */
|
|
426
|
+
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
427
|
+
ready = computed(() => this.active()?.ready() ?? false, /* @ts-ignore */
|
|
428
|
+
...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
|
|
429
|
+
busy = computed(() => this.active()?.busy() ?? false, /* @ts-ignore */
|
|
430
|
+
...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
|
|
431
|
+
constructor(options, factory, config) {
|
|
432
|
+
this.options = options;
|
|
433
|
+
this.factory = factory;
|
|
434
|
+
this.config = config;
|
|
435
|
+
}
|
|
436
|
+
/** Downloads the model for a pair ahead of the first translate() call. */
|
|
437
|
+
load(pair = {}) {
|
|
438
|
+
return this.handleFor(pair).load();
|
|
439
|
+
}
|
|
440
|
+
/** Translates one text; the pair defaults to the one given at creation. */
|
|
441
|
+
async translate(text, pair = {}) {
|
|
442
|
+
const handle = this.handleFor(pair);
|
|
443
|
+
const raw = await handle.run(text, this.languageOptions(pair));
|
|
444
|
+
const first = Array.isArray(raw) ? raw[0] : raw;
|
|
445
|
+
return (first?.translation_text ?? '').trim();
|
|
446
|
+
}
|
|
447
|
+
/** Checkpoint for a pair: the pinned model, else the configured or default one. */
|
|
448
|
+
modelFor(pair = {}) {
|
|
449
|
+
if (this.options.model)
|
|
450
|
+
return this.options.model;
|
|
451
|
+
const from = pair.from ?? this.options.from;
|
|
452
|
+
const to = pair.to ?? this.options.to;
|
|
453
|
+
if (!from || !to) {
|
|
454
|
+
throw new Error('Translator: no language pair - pass { from, to } to createTranslator() or translate(), or pin a multilingual model.');
|
|
455
|
+
}
|
|
456
|
+
return resolveTranslationModel(from, to, this.config);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* The handle serving a pair, created on first use. Exposed for apps that
|
|
460
|
+
* keep several pairs warm and want a progress line per model.
|
|
461
|
+
*/
|
|
462
|
+
handleFor(pair = {}) {
|
|
463
|
+
const model = this.modelFor(pair);
|
|
464
|
+
let handle = this.handles.get(model);
|
|
465
|
+
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);
|
|
467
|
+
this.handles.set(model, handle);
|
|
468
|
+
}
|
|
469
|
+
this.active.set(handle);
|
|
470
|
+
return handle;
|
|
471
|
+
}
|
|
472
|
+
/** Frees every model. The translator can be used again afterwards. */
|
|
473
|
+
async dispose() {
|
|
474
|
+
const handles = [...this.handles.values()];
|
|
475
|
+
this.handles.clear();
|
|
476
|
+
this.active.set(null);
|
|
477
|
+
await Promise.all(handles.map((handle) => handle.dispose()));
|
|
478
|
+
}
|
|
479
|
+
/** src_lang / tgt_lang for multilingual checkpoints; opus-mt models get nothing. */
|
|
480
|
+
languageOptions(pair) {
|
|
481
|
+
const runOptions = {};
|
|
482
|
+
if (!MULTILINGUAL_MODEL_PATTERN.test(this.modelFor(pair)))
|
|
483
|
+
return runOptions;
|
|
484
|
+
const from = pair.from ?? this.options.from;
|
|
485
|
+
const to = pair.to ?? this.options.to;
|
|
486
|
+
if (from !== undefined)
|
|
487
|
+
runOptions['src_lang'] = from;
|
|
488
|
+
if (to !== undefined)
|
|
489
|
+
runOptions['tgt_lang'] = to;
|
|
490
|
+
return runOptions;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/** Creates a Translator in an injection context. */
|
|
494
|
+
function createTranslator(options = {}) {
|
|
495
|
+
const translator = new Translator(options, inject(PIPELINE_FACTORY), inject(NGX_TRANSFORMERS_CONFIG));
|
|
496
|
+
inject(DestroyRef, { optional: true })?.onDestroy(() => void translator.dispose());
|
|
497
|
+
return translator;
|
|
498
|
+
}
|
|
499
|
+
|
|
300
500
|
/**
|
|
301
501
|
* Microphone capture with a signals API. start() asks for mic permission
|
|
302
502
|
* and records; stop() resolves with the encoded audio Blob - pass it to
|
|
@@ -464,5 +664,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
464
664
|
* Generated bundle index. Do not edit.
|
|
465
665
|
*/
|
|
466
666
|
|
|
467
|
-
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, WHISPER_SAMPLE_RATE, cosineSimilarity, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, decodeAudio, provideTransformers };
|
|
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 };
|
|
468
668
|
//# 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/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/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","import { DestroyRef, computed, inject, signal } from '@angular/core';\nimport type { ModelProgress, NgxTransformersConfig, PipelineRequest, PipelineStatus } 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 async run(input: TIn, runOptions?: Record<string, unknown>): Promise<TOut> {\n await this.load();\n this.status.set('busy');\n try {\n return (await this.pipe!(input, runOptions)) 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 = this.request.device ?? this.config.device;\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 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, 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/text-classifier';\nexport * from './lib/text-embedder';\nexport * from './lib/speech-recognizer';\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 = ((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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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-transformers",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Run Hugging Face Transformers.js models in Angular - on-device ML with a signals API: text classification, embeddings, semantic search, Whisper speech-to-text. No server, no API key.",
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
7
7
|
"transformers",
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
"signals",
|
|
18
18
|
"whisper",
|
|
19
19
|
"speech-to-text",
|
|
20
|
-
"speech-recognition"
|
|
20
|
+
"speech-recognition",
|
|
21
|
+
"zero-shot-classification",
|
|
22
|
+
"translation"
|
|
21
23
|
],
|
|
22
24
|
"license": "MIT",
|
|
23
25
|
"author": "Muzaffar Qosimov",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { InjectionToken, EnvironmentProviders } from '@angular/core';
|
|
3
|
+
import * as ngx_transformers from 'ngx-transformers';
|
|
3
4
|
|
|
4
5
|
/** Lifecycle of a model pipeline. `error` is terminal until load() is retried. */
|
|
5
6
|
type PipelineStatus = 'idle' | 'loading' | 'ready' | 'busy' | 'error';
|
|
@@ -17,9 +18,19 @@ type TransformersDtype = 'fp32' | 'fp16' | 'q8' | 'q4';
|
|
|
17
18
|
/** Global defaults applied to every pipeline; see provideTransformers(). */
|
|
18
19
|
interface NgxTransformersConfig {
|
|
19
20
|
device?: TransformersDevice;
|
|
21
|
+
/**
|
|
22
|
+
* Probe WebGPU once and use it when available, else WASM, for every
|
|
23
|
+
* handle that sets no device (or 'auto'). An explicit device still wins.
|
|
24
|
+
*/
|
|
25
|
+
autoDevice?: boolean;
|
|
20
26
|
dtype?: TransformersDtype;
|
|
21
27
|
/** Extra options forwarded verbatim to every pipeline() call. */
|
|
22
28
|
pipelineOptions?: Record<string, unknown>;
|
|
29
|
+
/**
|
|
30
|
+
* Translation checkpoints per language pair, keyed "from-to" (e.g.
|
|
31
|
+
* "en-ru"). Pairs not listed fall back to Xenova/opus-mt-{from}-{to}.
|
|
32
|
+
*/
|
|
33
|
+
translationModels?: Record<string, string>;
|
|
23
34
|
}
|
|
24
35
|
/** Per-pipeline request; wins over the global config where both are set. */
|
|
25
36
|
interface PipelineRequest {
|
|
@@ -66,6 +77,28 @@ interface TranscribeOptions {
|
|
|
66
77
|
/** 'transcribe' (default) or 'translate' (multilingual checkpoints only). */
|
|
67
78
|
task?: 'transcribe' | 'translate';
|
|
68
79
|
}
|
|
80
|
+
/** Options for ZeroShotClassifier.classify(). */
|
|
81
|
+
interface ZeroShotOptions {
|
|
82
|
+
/** Score every label on its own (several can be high) instead of picking one. */
|
|
83
|
+
multiLabel?: boolean;
|
|
84
|
+
/** NLI hypothesis with a {} placeholder for the label; default "This example is {}.". */
|
|
85
|
+
hypothesisTemplate?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Language pair for one translate() call. Codes follow the checkpoint:
|
|
89
|
+
* ISO 639-1 for opus-mt ("en", "ru"), FLORES-200 for NLLB ("eng_Latn").
|
|
90
|
+
*/
|
|
91
|
+
interface TranslateOptions {
|
|
92
|
+
from?: string;
|
|
93
|
+
to?: string;
|
|
94
|
+
}
|
|
95
|
+
/** createTranslator() options: a default pair and/or a pinned checkpoint. */
|
|
96
|
+
interface TranslatorOptions extends Partial<Omit<PipelineRequest, 'task'>> {
|
|
97
|
+
/** Default source language for translate(); required unless every call passes one or `model` is pinned. */
|
|
98
|
+
from?: string;
|
|
99
|
+
/** Default target language for translate(). */
|
|
100
|
+
to?: string;
|
|
101
|
+
}
|
|
69
102
|
|
|
70
103
|
/**
|
|
71
104
|
* The callable returned by Transformers.js pipeline(), reduced to the
|
|
@@ -118,9 +151,20 @@ declare class PipelineHandle<TIn = unknown, TOut = unknown> {
|
|
|
118
151
|
load(): Promise<void>;
|
|
119
152
|
/** Runs the pipeline, loading the model first if needed. */
|
|
120
153
|
run(input: TIn, runOptions?: Record<string, unknown>): Promise<TOut>;
|
|
154
|
+
/**
|
|
155
|
+
* Runs the pipeline with extra positional arguments after the input, for
|
|
156
|
+
* tasks whose pipeline signature is not (input, options): zero-shot
|
|
157
|
+
* classification takes (text, candidateLabels, options).
|
|
158
|
+
*/
|
|
159
|
+
protected runWith(input: TIn, ...extraArgs: unknown[]): Promise<TOut>;
|
|
121
160
|
/** Frees the model. The handle can be loaded again afterwards. */
|
|
122
161
|
dispose(): Promise<void>;
|
|
123
162
|
private doLoad;
|
|
163
|
+
/**
|
|
164
|
+
* An explicit request or global device wins; with `autoDevice` on, an
|
|
165
|
+
* unset or 'auto' device is probed for WebGPU (once, cached) at load time.
|
|
166
|
+
*/
|
|
167
|
+
private resolveDevice;
|
|
124
168
|
private onProgress;
|
|
125
169
|
}
|
|
126
170
|
/**
|
|
@@ -130,6 +174,18 @@ declare class PipelineHandle<TIn = unknown, TOut = unknown> {
|
|
|
130
174
|
*/
|
|
131
175
|
declare function createPipeline<TIn = unknown, TOut = unknown>(request: PipelineRequest): PipelineHandle<TIn, TOut>;
|
|
132
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Whether models can run on WebGPU here: `navigator.gpu` exists AND
|
|
179
|
+
* `requestAdapter()` hands back an adapter - it returns null on machines
|
|
180
|
+
* without a usable GPU or with WebGPU disabled, even when the API exists.
|
|
181
|
+
* Resolves false on the server. The probe runs once and is cached.
|
|
182
|
+
*/
|
|
183
|
+
declare function hasWebGpu(): Promise<boolean>;
|
|
184
|
+
/** `'webgpu'` when hasWebGpu() resolves true, else `'wasm'`. */
|
|
185
|
+
declare function detectDevice(): Promise<'webgpu' | 'wasm'>;
|
|
186
|
+
/** Forgets the cached probe so the next hasWebGpu() asks the browser again. */
|
|
187
|
+
declare function resetDeviceDetection(): void;
|
|
188
|
+
|
|
133
189
|
declare const DEFAULT_TEXT_CLASSIFICATION_MODEL = "Xenova/distilbert-base-uncased-finetuned-sst-2-english";
|
|
134
190
|
/**
|
|
135
191
|
* Text classification (sentiment by default). The default model is
|
|
@@ -206,6 +262,82 @@ declare class SpeechRecognizer extends PipelineHandle<string | Float32Array, Raw
|
|
|
206
262
|
*/
|
|
207
263
|
declare function createSpeechRecognizer(options?: Partial<Omit<PipelineRequest, 'task'>>): SpeechRecognizer;
|
|
208
264
|
|
|
265
|
+
declare const DEFAULT_ZERO_SHOT_MODEL = "Xenova/mobilebert-uncased-mnli";
|
|
266
|
+
/** Raw zero-shot output: labels ordered by score, scores aligned by index. */
|
|
267
|
+
interface RawZeroShotResult {
|
|
268
|
+
sequence: string;
|
|
269
|
+
labels: string[];
|
|
270
|
+
scores: number[];
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Zero-shot classification: score any labels you name against a text with
|
|
274
|
+
* an NLI model, no fine-tuning. The default checkpoint is MobileBERT MNLI
|
|
275
|
+
* (~26 MB q8); Xenova/distilbert-base-uncased-mnli (~80 MB) is the
|
|
276
|
+
* higher-accuracy alternative.
|
|
277
|
+
*/
|
|
278
|
+
declare class ZeroShotClassifier extends PipelineHandle<string, RawZeroShotResult | RawZeroShotResult[]> {
|
|
279
|
+
/**
|
|
280
|
+
* Scores each candidate label for one text; resolves sorted by score (top
|
|
281
|
+
* first). Single-label mode (default) normalizes across labels so scores
|
|
282
|
+
* sum to 1; `multiLabel` scores each label on its own.
|
|
283
|
+
*/
|
|
284
|
+
classify(text: string, labels: readonly string[], options?: ZeroShotOptions): Promise<ClassificationResult[]>;
|
|
285
|
+
}
|
|
286
|
+
/** Creates a ZeroShotClassifier in an injection context. */
|
|
287
|
+
declare function createZeroShotClassifier(options?: Partial<Omit<PipelineRequest, 'task'>>): ZeroShotClassifier;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Default checkpoint for a language pair: Helsinki-NLP's Marian opus-mt
|
|
291
|
+
* models, one per direction, ~105 MB q8 each (e.g. Xenova/opus-mt-en-ru).
|
|
292
|
+
*/
|
|
293
|
+
declare function defaultTranslationModel(from: string, to: string): string;
|
|
294
|
+
/** Checkpoint for a pair: provideTransformers({ translationModels }) first, then opus-mt. */
|
|
295
|
+
declare function resolveTranslationModel(from: string, to: string, config: NgxTransformersConfig): string;
|
|
296
|
+
/** Raw translation pipeline output, one entry per input text. */
|
|
297
|
+
interface RawTranslation {
|
|
298
|
+
translation_text?: string;
|
|
299
|
+
}
|
|
300
|
+
type TranslationHandle = PipelineHandle<string, RawTranslation | RawTranslation[]>;
|
|
301
|
+
/**
|
|
302
|
+
* Text translation. Pipelines are created lazily, one per checkpoint: with
|
|
303
|
+
* the default opus-mt family every language pair is its own model, so a
|
|
304
|
+
* Translator holds one handle per pair it has been asked for, while a
|
|
305
|
+
* pinned multilingual `model` (NLLB, M2M100) serves every pair from one.
|
|
306
|
+
*
|
|
307
|
+
* The signals mirror the handle used by the most recent call, so a single
|
|
308
|
+
* `<ngx-model-progress>` covers the translator.
|
|
309
|
+
*/
|
|
310
|
+
declare class Translator {
|
|
311
|
+
private readonly options;
|
|
312
|
+
private readonly factory;
|
|
313
|
+
private readonly config;
|
|
314
|
+
private readonly active;
|
|
315
|
+
private readonly handles;
|
|
316
|
+
readonly status: _angular_core.Signal<ngx_transformers.PipelineStatus>;
|
|
317
|
+
readonly progress: _angular_core.Signal<ngx_transformers.ModelProgress | null>;
|
|
318
|
+
readonly error: _angular_core.Signal<{} | null>;
|
|
319
|
+
readonly ready: _angular_core.Signal<boolean>;
|
|
320
|
+
readonly busy: _angular_core.Signal<boolean>;
|
|
321
|
+
constructor(options: TranslatorOptions, factory: PipelineFactory, config: NgxTransformersConfig);
|
|
322
|
+
/** Downloads the model for a pair ahead of the first translate() call. */
|
|
323
|
+
load(pair?: TranslateOptions): Promise<void>;
|
|
324
|
+
/** Translates one text; the pair defaults to the one given at creation. */
|
|
325
|
+
translate(text: string, pair?: TranslateOptions): Promise<string>;
|
|
326
|
+
/** Checkpoint for a pair: the pinned model, else the configured or default one. */
|
|
327
|
+
modelFor(pair?: TranslateOptions): string;
|
|
328
|
+
/**
|
|
329
|
+
* The handle serving a pair, created on first use. Exposed for apps that
|
|
330
|
+
* keep several pairs warm and want a progress line per model.
|
|
331
|
+
*/
|
|
332
|
+
handleFor(pair?: TranslateOptions): TranslationHandle;
|
|
333
|
+
/** Frees every model. The translator can be used again afterwards. */
|
|
334
|
+
dispose(): Promise<void>;
|
|
335
|
+
/** src_lang / tgt_lang for multilingual checkpoints; opus-mt models get nothing. */
|
|
336
|
+
private languageOptions;
|
|
337
|
+
}
|
|
338
|
+
/** Creates a Translator in an injection context. */
|
|
339
|
+
declare function createTranslator(options?: TranslatorOptions): Translator;
|
|
340
|
+
|
|
209
341
|
/** Minimal recorder surface - lets tests (and exotic runtimes) inject fakes. */
|
|
210
342
|
interface RecorderLike {
|
|
211
343
|
start(): void;
|
|
@@ -282,5 +414,5 @@ declare class ModelProgressComponent {
|
|
|
282
414
|
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>;
|
|
283
415
|
}
|
|
284
416
|
|
|
285
|
-
export { DEFAULT_ASR_MODEL, DEFAULT_EMBEDDING_MODEL, DEFAULT_TEXT_CLASSIFICATION_MODEL, MicRecorder, ModelProgressComponent, NGX_TRANSFORMERS_CONFIG, PIPELINE_FACTORY, PipelineHandle, SpeechRecognizer, TextClassifier, TextEmbedder, WHISPER_SAMPLE_RATE, cosineSimilarity, createMicRecorder, createPipeline, createSpeechRecognizer, createTextClassifier, createTextEmbedder, decodeAudio, provideTransformers };
|
|
286
|
-
export type { ClassificationResult, MicRecorderDeps, ModelProgress, NgxTransformersConfig, PipelineFactory, PipelineLike, PipelineRequest, PipelineStatus, RankedResult, RecorderLike, TranscribeOptions, Transcription, TranscriptionChunk, TransformersDevice, TransformersDtype };
|
|
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 };
|