ngx-transformers 0.1.0 → 0.1.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/README.md +111 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,64 +1,139 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ngx-transformers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/ngx-transformers)
|
|
4
|
+
[](https://github.com/qwertymuzaffar/ngx-transformers/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
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, and semantic search that execute entirely in the browser: no server, no API key, works offline once the model is cached.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
**[Live demo (Storybook)](https://qwertymuzaffar.github.io/ngx-transformers/)** - loads real models in your browser.
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Transformers.js has a React tutorial and hooks ecosystem - Angular has nothing. This library closes that gap with idiomatic Angular: lazily-loaded pipelines wrapped in signals, DI-friendly configuration, automatic cleanup with the owning component, and a drop-in progress component for the model download.
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Install
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
|
|
18
|
+
npm i ngx-transformers @huggingface/transformers
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
`@huggingface/transformers` (v4) is a peer dependency. Angular >= 22.
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { Component, signal } from '@angular/core';
|
|
27
|
+
import { createTextClassifier, ModelProgressComponent } from 'ngx-transformers';
|
|
28
|
+
|
|
29
|
+
@Component({
|
|
30
|
+
imports: [ModelProgressComponent],
|
|
31
|
+
template: `
|
|
32
|
+
<textarea #box></textarea>
|
|
33
|
+
<button (click)="analyze(box.value)" [disabled]="classifier.busy()">Analyze</button>
|
|
34
|
+
<ngx-model-progress [status]="classifier.status()" [progress]="classifier.progress()" />
|
|
35
|
+
@if (label(); as l) { <strong>{{ l }}</strong> }
|
|
36
|
+
`,
|
|
37
|
+
})
|
|
38
|
+
export class SentimentComponent {
|
|
39
|
+
readonly classifier = createTextClassifier(); // no download yet - lazy
|
|
40
|
+
readonly label = signal<string | null>(null);
|
|
41
|
+
|
|
42
|
+
async analyze(text: string) {
|
|
43
|
+
const [top] = await this.classifier.classify(text); // downloads model on first call
|
|
44
|
+
this.label.set(`${top.label} ${(top.score * 100).toFixed(1)}%`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
20
48
|
|
|
21
|
-
|
|
49
|
+
The model downloads on the first `classify()` call (with progress reported through the `progress` signal), is cached by the browser, and is disposed automatically when the component is destroyed.
|
|
22
50
|
|
|
23
|
-
|
|
24
|
-
ng build ngx-transformers
|
|
25
|
-
```
|
|
51
|
+
## Semantic search
|
|
26
52
|
|
|
27
|
-
|
|
53
|
+
```ts
|
|
54
|
+
import { createTextEmbedder } from 'ngx-transformers';
|
|
28
55
|
|
|
29
|
-
|
|
56
|
+
readonly embedder = createTextEmbedder(); // all-MiniLM-L6-v2, ~23 MB q8
|
|
30
57
|
|
|
31
|
-
|
|
58
|
+
const ranked = await this.embedder.rank('how do I make my app faster?', docs);
|
|
59
|
+
// [{ text: 'Use trackBy and virtual scrolling...', score: 0.28, index: 2 }, ...]
|
|
32
60
|
|
|
33
|
-
|
|
61
|
+
const score = await this.embedder.similarity('car', 'automobile'); // ~0.8
|
|
62
|
+
const vectors = await this.embedder.embed(['one', 'two']); // number[][]
|
|
63
|
+
```
|
|
34
64
|
|
|
35
|
-
|
|
36
|
-
cd dist/ngx-transformers
|
|
37
|
-
```
|
|
65
|
+
## Any pipeline
|
|
38
66
|
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm publish
|
|
42
|
-
```
|
|
67
|
+
`createPipeline()` exposes the full Transformers.js task surface with the same signal lifecycle:
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
```ts
|
|
70
|
+
import { createPipeline } from 'ngx-transformers';
|
|
45
71
|
|
|
46
|
-
|
|
72
|
+
readonly summarizer = createPipeline<string, { summary_text: string }[]>({
|
|
73
|
+
task: 'summarization',
|
|
74
|
+
model: 'Xenova/distilbart-cnn-6-6',
|
|
75
|
+
});
|
|
47
76
|
|
|
48
|
-
|
|
49
|
-
ng test
|
|
77
|
+
const [out] = await this.summarizer.run(longText);
|
|
50
78
|
```
|
|
51
79
|
|
|
52
|
-
##
|
|
80
|
+
## Global configuration
|
|
53
81
|
|
|
54
|
-
|
|
82
|
+
```ts
|
|
83
|
+
import { provideTransformers } from 'ngx-transformers';
|
|
55
84
|
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
bootstrapApplication(App, {
|
|
86
|
+
providers: [provideTransformers({ device: 'webgpu', dtype: 'q8' })],
|
|
87
|
+
});
|
|
58
88
|
```
|
|
59
89
|
|
|
60
|
-
|
|
90
|
+
Per-pipeline `device`/`dtype`/`options` win over the global config.
|
|
91
|
+
|
|
92
|
+
## API
|
|
93
|
+
|
|
94
|
+
### Handles
|
|
95
|
+
|
|
96
|
+
| Export | What it is |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `createPipeline(request)` | Generic `PipelineHandle` for any Transformers.js task |
|
|
99
|
+
| `createTextClassifier(options?)` | `TextClassifier` - sentiment/classification, `classify(text, topK?)` |
|
|
100
|
+
| `createTextEmbedder(options?)` | `TextEmbedder` - `embed()`, `similarity()`, `rank()` |
|
|
101
|
+
| `cosineSimilarity(a, b)` | Standalone vector math helper |
|
|
102
|
+
|
|
103
|
+
All `create*` functions must run in an injection context (field initializer, constructor, or `runInInjectionContext`); handles are disposed with the surrounding component.
|
|
104
|
+
|
|
105
|
+
### PipelineHandle signals
|
|
106
|
+
|
|
107
|
+
| Signal | Type | Meaning |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `status` | `'idle' \| 'loading' \| 'ready' \| 'busy' \| 'error'` | Lifecycle; `error` only from a failed load, retryable |
|
|
110
|
+
| `progress` | `ModelProgress \| null` | Download progress: `file`, `progress` (0-100), bytes |
|
|
111
|
+
| `error` | `unknown` | The load error, if any |
|
|
112
|
+
| `ready` / `busy` | `boolean` (computed) | Convenience for buttons and spinners |
|
|
113
|
+
|
|
114
|
+
### `<ngx-model-progress>`
|
|
115
|
+
|
|
116
|
+
Status line + download bar for any handle. Inputs: `status` (required), `progress`, `labels` (override per-status text). Themeable via `--nt-accent`, `--nt-ink`, `--nt-muted`, `--nt-track`.
|
|
117
|
+
|
|
118
|
+
## Default models
|
|
119
|
+
|
|
120
|
+
| Wrapper | Model | Size (q8) | License |
|
|
121
|
+
|---|---|---|---|
|
|
122
|
+
| `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 |
|
|
123
|
+
| `createTextEmbedder` | [Xenova/all-MiniLM-L6-v2](https://huggingface.co/Xenova/all-MiniLM-L6-v2) | ~23 MB | Apache-2.0 |
|
|
124
|
+
|
|
125
|
+
Swap any compatible checkpoint via `{ model: '...' }`. Check the license of the model you ship.
|
|
126
|
+
|
|
127
|
+
## SSR
|
|
128
|
+
|
|
129
|
+
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.
|
|
130
|
+
|
|
131
|
+
## Roadmap
|
|
132
|
+
|
|
133
|
+
- v0.2: speech-to-text (`createSpeechRecognizer`, Whisper) with mic capture helpers
|
|
134
|
+
- Zero-shot classification and translation wrappers
|
|
135
|
+
- WebGPU feature-detection helper
|
|
61
136
|
|
|
62
|
-
##
|
|
137
|
+
## License
|
|
63
138
|
|
|
64
|
-
|
|
139
|
+
MIT (c) Muzaffar Qosimov
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-transformers",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Run Hugging Face Transformers.js models in Angular - on-device ML with a signals API: text classification, embeddings, semantic similarity. No server, no API key.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|