Getting started
ngx-transformers runs Hugging Face Transformers.js models inside an Angular app: text classification, zero-shot classification, sentence embeddings and semantic search, translation, and Whisper speech-to-text, all executed in the browser on WebAssembly or WebGPU.
Install
npm install ngx-transformers @huggingface/transformers| Requirement | Version |
|---|---|
| Angular | 22 or newer |
@huggingface/transformers | 4.x, a peer dependency the library never bundles |
| Browser | Anything with WebAssembly; WebGPU is used when available |
The library imports @huggingface/transformers lazily, on the first pipeline, so it adds nothing to your initial bundle.
Your first model
import { Component, signal } from '@angular/core';
import { createTextClassifier, ModelProgressComponent } from 'ngx-transformers';
@Component({
selector: 'app-sentiment',
imports: [ModelProgressComponent],
template: `
<textarea #box></textarea>
<button (click)="analyze(box.value)" [disabled]="classifier.busy()">Analyze</button>
<ngx-model-progress [status]="classifier.status()" [progress]="classifier.progress()" />
@if (label(); as l) {
<strong>{{ l }}</strong>
}
`,
})
export class SentimentComponent {
readonly classifier = createTextClassifier(); // nothing downloads yet
readonly label = signal<string | null>(null);
async analyze(text: string) {
const [top] = await this.classifier.classify(text); // downloads the model on the first call
this.label.set(`${top.label} ${(top.score * 100).toFixed(1)}%`);
}
}What happens:
createTextClassifier()creates a handle and registers it for disposal with the component. No network request yet.- The first
classify()downloads DistilBERT SST-2 (about 65 MB, 8-bit) from the Hugging Face Hub. Thestatussignal moves fromidletoloading, andprogressreports each file. - The browser caches the model files, so the next page load skips the download.
- Further calls run in place;
statustoggles betweenreadyandbusy. - When the component is destroyed, the model is released.
The create functions
Every task has a create*() function that returns a handle with the same lifecycle:
| Function | Handle | Main method |
|---|---|---|
createTextClassifier() | TextClassifier | classify(text, topK?) |
createZeroShotClassifier() | ZeroShotClassifier | classify(text, labels, options?) |
createTextEmbedder() | TextEmbedder | embed(), similarity(), rank() |
createTranslator() | Translator | translate(text, { from?, to? }) |
createSpeechRecognizer() | SpeechRecognizer | transcribe(audio, options?) |
createTextGenerator() | TextGenerator | generate(prompt, options?), streamed into output |
createMicRecorder() | MicRecorder | start(), stop() |
createPipeline() | PipelineHandle | run(input, options?) for any other task |
inferenceResource() wraps any of them in an Angular resource that re-runs when an input signal changes; see Reactive inference. They must run in an injection context: a field initializer, a constructor, or runInInjectionContext(). Each takes an options object to change the model, device or dtype for that handle, for example createTextClassifier({ model: 'Xenova/bert-base-multilingual-uncased-sentiment' }).
Showing progress
<ngx-model-progress> is a status line with a download bar. Bind it to any handle:
<ngx-model-progress [status]="handle.status()" [progress]="handle.progress()" />It shows the file being downloaded, how many of the model's files are done, and the percentage over all of them while loading, then the ready, busy or error state. Override the text through the labels input and the colors through the --nt-accent, --nt-ink, --nt-muted and --nt-track custom properties. Or read the signals and render your own; see Concepts.
Preloading
Call load() to download ahead of the first use, for example when the page opens or when the user hovers a button:
ngOnInit() {
void this.classifier.load();
}load() is idempotent: concurrent calls share one download, and calling it again once the model is ready resolves immediately.
Next
- Concepts: the handle lifecycle, signals, disposal and server rendering.
- Configuration: device and dtype defaults, WebGPU detection, custom pipeline factories.
- Web Workers: one provider to run every model off the main thread.
- One page per task under Tasks in the sidebar.