Classification & NER
Text classification, zero-shot classification, and named entity recognition.
LocalMode provides provider-agnostic functions for text classification, zero-shot classification, and named entity recognition (NER). Pass any model that implements the corresponding interface — the core functions handle retries, cancellation, and structured results.
See it in action
Try Sentiment Analyzer and Email Classifier for working demos of these APIs.
classify()
Classify a single text using a trained classification model:
import { classify } from '@localmode/core';
import { transformers } from '@localmode/transformers';
const model = transformers.classifier('Xenova/distilbert-base-uncased-finetuned-sst-2-english');
const { label, score, usage, response } = await classify({
model,
text: 'I love this product!',
});
console.log('Label:', label); // 'POSITIVE'
console.log('Score:', score); // 0.9998
console.log('Duration:', usage.durationMs); // ~120
console.log('Model:', response.modelId);const controller = new AbortController();
setTimeout(() => controller.abort(), 5000); // Cancel after 5s
const { label, score } = await classify({
model,
text: 'I love this product!',
abortSignal: controller.signal,
});ClassifyOptions
Prop
Type
ClassifyResult
Prop
Type
classifyMany()
Classify multiple texts in a single call:
import { classifyMany } from '@localmode/core';
import { transformers } from '@localmode/transformers';
const model = transformers.classifier('Xenova/distilbert-base-uncased-finetuned-sst-2-english');
const { results, usage } = await classifyMany({
model,
texts: ['I love this!', 'This is terrible!', 'It is okay.'],
});
results.forEach((r, i) => {
console.log(`Text ${i}: ${r.label} (${r.score.toFixed(2)})`);
});
// Text 0: POSITIVE (1.00)
// Text 1: NEGATIVE (1.00)
// Text 2: POSITIVE (0.56)ClassifyManyResult
Prop
Type
ClassificationResultItem
Prop
Type
classifyZeroShot()
Classify text into arbitrary labels without fine-tuning:
import { classifyZeroShot } from '@localmode/core';
import { transformers } from '@localmode/transformers';
const model = transformers.zeroShot('Xenova/mobilebert-uncased-mnli');
const { labels, scores } = await classifyZeroShot({
model,
text: 'I just bought a new Tesla Model 3',
candidateLabels: ['automotive', 'technology', 'finance', 'sports'],
});
console.log(labels[0]); // 'automotive'
console.log(scores[0]); // 0.87const { labels, scores } = await classifyZeroShot({
model,
text: 'The new iPhone uses advanced AI for photography',
candidateLabels: ['technology', 'photography', 'smartphones'],
multiLabel: true,
});
// Multiple labels can have high scores simultaneously
labels.forEach((label, i) => {
console.log(`${label}: ${scores[i].toFixed(2)}`);
});
// technology: 0.92
// smartphones: 0.85
// photography: 0.78ClassifyZeroShotOptions
Prop
Type
ClassifyZeroShotResult
Prop
Type
extractEntities()
Extract named entities (people, organizations, locations, etc.) from text:
import { extractEntities } from '@localmode/core';
import { transformers } from '@localmode/transformers';
const model = transformers.ner('Xenova/bert-base-NER');
const { entities, usage } = await extractEntities({
model,
text: 'John works at Microsoft in Seattle',
});
// entities: [
// { text: 'John', type: 'PERSON', start: 0, end: 4, score: 0.99 },
// { text: 'Microsoft', type: 'ORG', start: 14, end: 23, score: 0.98 },
// { text: 'Seattle', type: 'LOC', start: 27, end: 34, score: 0.97 }
// ]ExtractEntitiesOptions
Prop
Type
ExtractEntitiesResult
Prop
Type
Entity
Prop
Type
extractEntitiesMany()
Extract entities from multiple texts in a single call:
import { extractEntitiesMany } from '@localmode/core';
import { transformers } from '@localmode/transformers';
const model = transformers.ner('Xenova/bert-base-NER');
const { results, usage } = await extractEntitiesMany({
model,
texts: [
'John works at Microsoft',
'Apple is based in Cupertino',
'The Eiffel Tower is in Paris',
],
});
results.forEach((r, i) => {
console.log(`Text ${i}:`, r.entities.map((e) => `${e.text} (${e.type})`));
});
// Text 0: ['John (PERSON)', 'Microsoft (ORG)']
// Text 1: ['Apple (ORG)', 'Cupertino (LOC)']
// Text 2: ['Eiffel Tower (LOC)', 'Paris (LOC)']Cancellation Support
All classification and NER operations support AbortSignal for cancellation:
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const { label } = await classify({
model,
text: 'I love this product!',
abortSignal: controller.signal,
});
} catch (error) {
if (error.name === 'AbortError') {
console.log('Classification was cancelled');
}
}Custom Provider Implementations
Implement the core interfaces to create custom classification, zero-shot, and NER providers.
import type {
ClassificationModel,
DoClassifyOptions,
DoClassifyResult,
} from '@localmode/core';
class MyClassifier implements ClassificationModel {
readonly modelId = 'custom:my-classifier';
readonly provider = 'custom';
readonly labels = ['positive', 'negative', 'neutral'];
async doClassify(options: DoClassifyOptions): Promise<DoClassifyResult> {
const { texts } = options;
// Your classification logic here
const results = texts.map((text) => ({
label: 'positive',
score: 0.95,
allScores: { positive: 0.95, negative: 0.03, neutral: 0.02 },
}));
return {
results,
usage: {
inputTokens: texts.join('').length,
durationMs: 0,
},
};
}
}import type {
ZeroShotClassificationModel,
DoClassifyZeroShotOptions,
DoClassifyZeroShotResult,
} from '@localmode/core';
class MyZeroShotClassifier implements ZeroShotClassificationModel {
readonly modelId = 'custom:zero-shot';
readonly provider = 'custom';
async doClassifyZeroShot(
options: DoClassifyZeroShotOptions
): Promise<DoClassifyZeroShotResult> {
const { texts, candidateLabels } = options;
// Your zero-shot logic here
const results = texts.map(() => ({
labels: candidateLabels,
scores: candidateLabels.map(() => 1 / candidateLabels.length),
}));
return {
results,
usage: {
inputTokens: texts.join('').length,
durationMs: 0,
},
};
}
}import type {
NERModel,
DoExtractEntitiesOptions,
DoExtractEntitiesResult,
} from '@localmode/core';
class MyNERModel implements NERModel {
readonly modelId = 'custom:ner';
readonly provider = 'custom';
readonly entityTypes = ['PERSON', 'ORG', 'LOC'];
async doExtract(
options: DoExtractEntitiesOptions
): Promise<DoExtractEntitiesResult> {
const { texts } = options;
// Your NER logic here
const results = texts.map(() => ({
entities: [],
}));
return {
results,
usage: {
inputTokens: texts.join('').length,
durationMs: 0,
},
};
}
}For recommended models, provider-specific options, and practical recipes, see the Transformers.js provider pages: Classification, Zero-Shot Classification, and NER.
Next Steps
Reranking
Rerank retrieved documents for more accurate RAG pipelines.
Embeddings
Generate embeddings for semantic search and similarity.
RAG
Build retrieval-augmented generation pipelines.