🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples Hugging Face JavaScript
Exemples JavaScript/TypeScript Hugging Face utilisant Transformers.js pour les tâches NLP, de vision par ordinateur et multimodales dans le navigateur et Node.js
💻 Bases de Transformers.js javascript
🟢 simple
Premiers pas avec Transformers.js pour exécuter des modèles pré-entraînés en JavaScript
// Hugging Face Transformers.js Basics
// 1. Installation
// npm install @huggingface/transformers
// or in browser: <script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@latest"></script>
import { pipeline, AutoModel, AutoTokenizer } from '@huggingface/transformers';
// 2. Basic Text Classification
async function basicTextClassification() {
console.log('Initializing text classification pipeline...');
// Create a text classification pipeline
const classifier = await pipeline('text-classification', 'distilbert-base-uncased-finetuned-sst-2-english');
// Classify text
const texts = [
'I love this movie! It was fantastic.',
'The weather is terrible today.',
'This book is okay, but could be better.'
];
for (const text of texts) {
const result = await classifier(text);
console.log(`Text: "${text}"`);
console.log('Classification:', result);
console.log('---');
}
// Batch classification
const batchResults = await classifier(texts);
console.log('Batch results:', batchResults);
}
// 3. Sentiment Analysis
async function sentimentAnalysis() {
const sentimentClassifier = await pipeline('sentiment-analysis', 'cardiffnlp/twitter-roberta-base-sentiment-latest');
const reviews = [
'The product exceeded my expectations!',
'Poor customer service and slow delivery.',
'Average quality, nothing special.',
'Amazing experience, would recommend to everyone!'
];
console.log('Sentiment Analysis Results:');
for (const review of reviews) {
const result = await sentimentClassifier(review);
console.log(`${review} -> ${result[0].label} (${(result[0].score * 100).toFixed(2)}%)`);
}
}
// 4. Named Entity Recognition (NER)
async function namedEntityRecognition() {
const nerPipeline = await pipeline('ner', 'dbmdz/bert-large-cased-finetuned-conll03-english');
const text = "Apple Inc. was founded by Steve Jobs in Cupertino, California in 1976.";
const entities = await nerPipeline(text);
console.log('Named Entity Recognition:');
console.log('Text:', text);
console.log('Entities:', entities);
// Group entities by type
const groupedEntities = entities.reduce((acc, entity) => {
const type = entity.entity_group;
if (!acc[type]) acc[type] = [];
acc[type].push(entity.word);
return acc;
}, {});
console.log('Grouped Entities:', groupedEntities);
}
// 5. Question Answering
async function questionAnswering() {
const qaPipeline = await pipeline('question-answering', 'distilbert-base-cased-distilled-squad');
const context = `
The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.
It is named after the engineer Gustave Eiffel, whose company designed and built the tower.
Constructed from 1887 to 1889 as the entrance to the 1889 World's Fair, it was initially
criticized by some of France's leading artists and intellectuals for its design, but it has
become a global cultural icon of France and one of the most recognizable structures in the world.
The tower is 330 metres (1,083 ft) tall, about the same height as an 81-storey building,
and is the tallest structure in Paris.
`;
const questions = [
'Who designed the Eiffel Tower?',
'When was the Eiffel Tower built?',
'How tall is the Eiffel Tower?'
];
console.log('Question Answering:');
console.log('Context:', context);
console.log('');
for (const question of questions) {
const result = await qaPipeline(question, context);
console.log(`Q: ${question}`);
console.log(`A: ${result.answer} (confidence: ${(result.score * 100).toFixed(2)}%)`);
console.log('');
}
}
// 6. Text Generation
async function textGeneration() {
const generator = await pipeline('text-generation', 'gpt2');
const prompts = [
'Once upon a time in a magical forest,',
'The future of artificial intelligence is',
'In the year 2050,'
];
console.log('Text Generation:');
for (const prompt of prompts) {
const result = await generator(prompt, {
max_length: 50,
num_return_sequences: 2,
temperature: 0.7,
do_sample: true,
top_p: 0.9
});
console.log(`Prompt: ${prompt}`);
result.forEach((seq, i) => {
console.log(` ${i + 1}: ${seq.generated_text}`);
});
console.log('');
}
}
// 7. Zero-Shot Classification
async function zeroShotClassification() {
const zeroShotClassifier = await pipeline('zero-shot-classification', 'facebook/bart-large-mnli');
const text = "I just got a new puppy and I'm so excited to train him!";
const candidateLabels = ['politics', 'sports', 'technology', 'pets', 'business'];
const result = await zeroShotClassifier(text, candidateLabels);
console.log('Zero-Shot Classification:');
console.log('Text:', text);
console.log('Candidate Labels:', candidateLabels);
console.log('Scores:');
result.labels.forEach((label, i) => {
console.log(` ${label}: ${(result.scores[i] * 100).toFixed(2)}%`);
});
}
// 8. Translation
async function textTranslation() {
const translator = await pipeline('translation', 't5-base');
const texts = [
'Hello, how are you?',
'I love machine learning',
'The weather is beautiful today'
];
console.log('Translation:');
for (const text of texts) {
const result = await translator(text);
console.log(`English: ${text}`);
console.log(`Translated: ${result[0].translation_text}`);
console.log('');
}
}
// 9. Summarization
async function textSummarization() {
const summarizer = await pipeline('summarization', 'facebook/bart-large-cnn');
const longText = `
Artificial intelligence (AI) is intelligence demonstrated by machines, in contrast to the natural
intelligence displayed by humans and animals. Leading AI textbooks define the field as the study of
"intelligent agents": any device that perceives its environment and takes actions that maximize its
chance of successfully achieving its goals. Colloquially, the term "artificial intelligence" is often
used to describe machines that mimic "cognitive" functions that humans associate with the human mind,
such as "learning" and "problem solving". AI applications include advanced web search engines,
recommendation systems (used by YouTube, Amazon and Netflix), understanding human speech (such as Siri
and Alexa), self-driving cars (e.g., Tesla), and competing at the highest level in strategic games
(such as chess and Go).
`;
const summary = await summarizer(longText, {
max_length: 60,
min_length: 20
});
console.log('Original Text Length:', longText.length);
console.log('Summary:', summary[0].summary_text);
}
// 10. Feature Extraction
async function featureExtraction() {
const featureExtractor = await pipeline('feature-extraction', 'sentence-transformers/all-MiniLM-L6-v2');
const sentences = [
'The cat sits on the mat.',
'A feline is resting on the floor covering.',
'The dog plays in the garden.',
'Machine learning is fascinating.'
];
const embeddings = await featureExtractor(sentences);
console.log('Feature Extraction:');
console.log('Sentences:', sentences);
console.log('Embedding shape:', embeddings.shape);
console.log('First sentence embedding (first 5 values):', embeddings[0][0].slice(0, 5));
// Calculate similarity between sentences
const similarity = calculateCosineSimilarity(embeddings[0][0], embeddings[1][0]);
console.log(`Similarity between first two sentences: ${similarity.toFixed(4)}`);
}
// Helper function for cosine similarity
function calculateCosineSimilarity(vecA, vecB) {
const dotProduct = vecA.reduce((sum, val, i) => sum + val * vecB[i], 0);
const magnitudeA = Math.sqrt(vecA.reduce((sum, val) => sum + val * val, 0));
const magnitudeB = Math.sqrt(vecB.reduce((sum, val) => sum + val * val, 0));
return dotProduct / (magnitudeA * magnitudeB);
}
// 11. Async Processing with Progress
async function batchProcessingWithProgress() {
console.log('Starting batch processing...');
const classifier = await pipeline('text-classification', 'distilbert-base-uncased-finetuned-sst-2-english');
const texts = Array(100).fill(null).map((_, i) => `Text number ${i + 1} for batch processing.`);
const batchSize = 10;
for (let i = 0; i < texts.length; i += batchSize) {
const batch = texts.slice(i, i + batchSize);
const results = await classifier(batch);
console.log(`Processed batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(texts.length / batchSize)}`);
// Process results
results.forEach((result, j) => {
console.log(` ${i + j + 1}: ${result.label} (${(result.score * 100).toFixed(1)}%)`);
});
}
}
// 12. Error Handling and Fallbacks
async function robustTextProcessing() {
try {
const classifier = await pipeline('text-classification', 'non-existent-model');
} catch (error) {
console.log('Failed to load primary model, using fallback...');
// Use fallback model
const fallbackClassifier = await pipeline('text-classification', 'distilbert-base-uncased-finetuned-sst-2-english');
try {
const result = await fallbackClassifier('This is a test sentence.');
console.log('Fallback result:', result);
} catch (error) {
console.error('Even fallback failed:', error);
}
}
}
// Run all examples
async function runAllExamples() {
console.log('=== Hugging Face Transformers.js Examples ===
');
await basicTextClassification();
console.log('
' + '='.repeat(50) + '
');
await sentimentAnalysis();
console.log('
' + '='.repeat(50) + '
');
await namedEntityRecognition();
console.log('
' + '='.repeat(50) + '
');
await questionAnswering();
console.log('
' + '='.repeat(50) + '
');
await textGeneration();
console.log('
' + '='.repeat(50) + '
');
await zeroShotClassification();
console.log('
' + '='.repeat(50) + '
');
await textSummarization();
console.log('
' + '='.repeat(50) + '
');
await featureExtraction();
console.log('
' + '='.repeat(50) + '
');
await batchProcessingWithProgress();
}
// Export functions for modular usage
export {
basicTextClassification,
sentimentAnalysis,
namedEntityRecognition,
questionAnswering,
textGeneration,
zeroShotClassification,
textTranslation,
textSummarization,
featureExtraction
};
// Run examples if called directly
if (typeof window === 'undefined') {
runAllExamples().catch(console.error);
}
💻 Tâches Multimodales avec Transformers.js javascript
🟡 intermediate
Modèles vision-langage pour la sous-titrage d'images, le问答 visual et le traitement de documents
// Multimodal Tasks with Transformers.js
import { pipeline, AutoProcessor, AutoModel, AutoTokenizer } from '@huggingface/transformers';
// 1. Image Captioning
async function imageCaptioning() {
console.log('Initializing image captioning model...');
const captioner = await pipeline('image-to-text', 'nlpconnect/vit-gpt2-image-captioning');
// Example with image URL
const imageUrl = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/image-to-text/huggingface-tourists.jpg';
const caption = await captioner(imageUrl);
console.log('Generated Caption:', caption[0].generated_text);
// Example with file upload (in browser)
if (typeof window !== 'undefined' && document.getElementById('imageInput')) {
document.getElementById('imageInput').addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
const caption = await captioner(file);
console.log('File Caption:', caption[0].generated_text);
document.getElementById('captionResult').textContent = caption[0].generated_text;
}
});
}
}
// 2. Visual Question Answering (VQA)
async function visualQuestionAnswering() {
console.log('Initializing VQA model...');
const vqaPipeline = await pipeline('visual-question-answering', 'dandelin/vilt-b32-finetuned-vqa');
const imageUrl = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/image-to-text/huggingface-tourists.jpg';
const question = 'How many people are in the image?';
const answer = await vqaPipeline(imageUrl, question);
console.log(`Question: ${question}`);
console.log('Answer:', answer);
// Multiple questions
const questions = [
'What color is the building in the background?',
'Are the people indoors or outdoors?',
'What objects can you see in the image?'
];
for (const q of questions) {
const answer = await vqaPipeline(imageUrl, q);
console.log(`Q: ${q} -> A: ${answer[0].answer} (${(answer[0].score * 100).toFixed(1)}%)`);
}
}
// 3. Document Intelligence
async function documentProcessing() {
console.log('Initializing document intelligence model...');
const documentProcessor = await pipeline('document-question-answering', 'impira/layoutlm-base-uncased');
const documentUrl = 'https://huggingface.co/spaces/impira/docquery/resolve/2359223c1557ff4c24c35ad5999fd6b43a5ec080/invoice.png';
const questions = [
'What is the invoice number?',
'What is the total amount?',
'Who is the recipient?',
'What is the date of the invoice?'
];
console.log('Document Analysis:');
for (const question of questions) {
const answer = await documentProcessor({
image: documentUrl,
question: question
});
console.log(`Q: ${question}`);
if (answer.length > 0) {
answer.forEach(a => {
console.log(` ${a.answer} (confidence: ${(a.score * 100).toFixed(1)}%)`);
});
} else {
console.log(' No answer found');
}
}
}
// 4. Zero-Shot Image Classification
async function zeroShotImageClassification() {
console.log('Initializing zero-shot image classifier...');
const classifier = await pipeline('zero-shot-image-classification', 'openai/clip-vit-base-patch32');
const imageUrl = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/image-to-text/huggingface-tourists.jpg';
const candidateLabels = [
'tourists', 'vacation', 'travel', 'building', 'monument',
'outdoor', 'city', 'landmark', 'people', 'sightseeing'
];
const results = await classifier(imageUrl, candidateLabels);
console.log('Zero-Shot Image Classification:');
console.log('Image:', imageUrl);
console.log('Top predictions:');
results.slice(0, 5).forEach((result, i) => {
console.log(` ${i + 1}. ${result.label}: ${(result.score * 100).toFixed(2)}%`);
});
}
// 5. Image-to-Image Tasks
async function imageToImageTasks() {
console.log('Initializing image-to-image models...');
// Image Classification
const imageClassifier = await pipeline('image-classification', 'google/vit-base-patch16-224');
const imageUrl = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/image-to-text/huggingface-tourists.jpg';
const classification = await imageClassifier(imageUrl);
console.log('Image Classification:');
classification.slice(0, 5).forEach((result, i) => {
console.log(` ${i + 1}. ${result.label}: ${(result.score * 100).toFixed(2)}%`);
});
// Object Detection
const objectDetector = await pipeline('object-detection', 'facebook/detr-resnet-50');
const detections = await objectDetector(imageUrl);
console.log('\nObject Detection:');
detections.forEach((detection, i) => {
console.log(` ${i + 1}. ${detection.label}: ${(detection.score * 100).toFixed(2)}% at [${detection.box}]`);
});
}
// 6. Advanced Multimodal Chat
class MultimodalChat {
constructor() {
this.conversationHistory = [];
this.visionModel = null;
this.textModel = null;
}
async initialize() {
console.log('Initializing multimodal chat models...');
// Initialize vision-language model
this.visionModel = await pipeline('image-to-text', 'nlpconnect/vit-gpt2-image-captioning');
// Initialize text model for conversation
this.textModel = await pipeline('conversational', 'microsoft/DialoGPT-medium');
}
async processMessage(message, imageUrl = null) {
let response = '';
// Process image if provided
if (imageUrl) {
console.log('Processing image...');
const caption = await this.visionModel(imageUrl);
response += `I can see an image. It appears to show: ${caption[0].generated_text}. `;
}
// Process text with conversation context
const conversation = {
past_user_inputs: this.conversationHistory.filter((_, i) => i % 2 === 0),
generated_responses: this.conversationHistory.filter((_, i) => i % 2 === 1),
text: message
};
const textResponse = await this.textModel(conversation);
response += textResponse.generated_text;
// Update conversation history
this.conversationHistory.push(message);
this.conversationHistory.push(textResponse.generated_text);
// Keep only last 10 exchanges
if (this.conversationHistory.length > 20) {
this.conversationHistory = this.conversationHistory.slice(-20);
}
return response;
}
}
// 7. Content Moderation System
class ContentModerator {
constructor() {
this.textModerator = null;
this.imageModerator = null;
this.sensitiveCategories = ['violence', 'adult', 'hate', 'weapons'];
}
async initialize() {
console.log('Initializing content moderation models...');
// Text classification for moderation
this.textModerator = await pipeline('text-classification', 'unitary/toxic-bert');
// Image classification for safety
this.imageModerator = await pipeline('image-classification', 'Falconsai/nsfw_image_detection');
}
async moderateText(text) {
try {
const result = await this.textModerator(text);
const toxicityScore = result[0].score;
return {
isAppropriate: toxicityScore < 0.5,
toxicityScore,
categories: result
};
} catch (error) {
console.error('Text moderation error:', error);
return { isAppropriate: true, toxicityScore: 0, error };
}
}
async moderateImage(imageUrl) {
try {
const result = await this.imageModerator(imageUrl);
const nsfwScore = result.find(r => r.label === 'nsfw')?.score || 0;
return {
isAppropriate: nsfwScore < 0.5,
nsfwScore,
categories: result
};
} catch (error) {
console.error('Image moderation error:', error);
return { isAppropriate: true, nsfwScore: 0, error };
}
}
async moderateContent(text, imageUrl = null) {
const results = {
text: await this.moderateText(text),
image: imageUrl ? await this.moderateImage(imageUrl) : null,
overallAppropriate: true
};
results.overallAppropriate =
results.text.isAppropriate &&
(!results.image || results.image.isAppropriate);
return results;
}
}
// 8. Web Application Example
class MultimodalWebApp {
constructor() {
this.initializeElements();
this.initializeModels();
}
initializeElements() {
this.imageInput = document.getElementById('imageInput');
this.textInput = document.getElementById('textInput');
this.questionInput = document.getElementById('questionInput');
this.resultDiv = document.getElementById('results');
this.processBtn = document.getElementById('processBtn');
this.setupEventListeners();
}
setupEventListeners() {
this.processBtn.addEventListener('click', () => this.processContent());
this.imageInput.addEventListener('change', (e) => {
if (e.target.files[0]) {
this.displayImage(e.target.files[0]);
}
});
}
async initializeModels() {
console.log('Loading models...');
this.captioner = await pipeline('image-to-text', 'nlpconnect/vit-gpt2-image-captioning');
this.vqaModel = await pipeline('visual-question-answering', 'dandelin/vilt-b32-finetuned-vqa');
this.textModel = await pipeline('sentiment-analysis', 'cardiffnlp/twitter-roberta-base-sentiment-latest');
console.log('Models loaded successfully!');
this.processBtn.disabled = false;
}
displayImage(file) {
const reader = new FileReader();
reader.onload = (e) => {
const img = document.getElementById('previewImage');
img.src = e.target.result;
img.style.display = 'block';
};
reader.readAsDataURL(file);
}
async processContent() {
this.resultDiv.innerHTML = '<p>Processing...</p>';
try {
const results = [];
// Process text
if (this.textInput.value) {
const sentiment = await this.textModel(this.textInput.value);
results.push({
type: 'Text Sentiment',
result: sentiment[0]
});
}
// Process image
if (this.imageInput.files[0]) {
const caption = await this.captioner(this.imageInput.files[0]);
results.push({
type: 'Image Caption',
result: caption[0].generated_text
});
// Answer question about image if provided
if (this.questionInput.value) {
const answer = await this.vqaModel(this.imageInput.files[0], this.questionInput.value);
results.push({
type: 'Visual Question Answer',
question: this.questionInput.value,
result: answer[0]
});
}
}
this.displayResults(results);
} catch (error) {
console.error('Processing error:', error);
this.resultDiv.innerHTML = `<p>Error: ${error.message}</p>`;
}
}
displayResults(results) {
let html = '<h3>Results:</h3>';
results.forEach(r => {
html += `<div class="result-section">
<h4>${r.type}:</h4>`;
if (r.question) {
html += `<p><strong>Question:</strong> ${r.question}</p>`;
}
if (r.result.generated_text) {
html += `<p>${r.result.generated_text}</p>`;
} else if (r.result.answer) {
html += `<p>${r.result.answer} (${(r.result.score * 100).toFixed(1)}% confidence)</p>`;
} else {
html += `<p>${r.result.label}: ${(r.result.score * 100).toFixed(1)}%</p>`;
}
html += '</div>';
});
this.resultDiv.innerHTML = html;
}
}
// 9. HTML Template for Web App
const webAppHTML = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multimodal AI Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@huggingface/transformers@latest"></script>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.input-section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
#previewImage { max-width: 100%; margin: 10px 0; }
.result-section { margin: 10px 0; padding: 10px; background: #f5f5f5; border-radius: 5px; }
button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
button:disabled { background: #ccc; cursor: not-allowed; }
input, textarea { width: 100%; padding: 8px; margin: 5px 0; border: 1px solid #ddd; border-radius: 3px; }
</style>
</head>
<body>
<h1>Multimodal AI Demo</h1>
<div class="input-section">
<h3>Upload Image</h3>
<input type="file" id="imageInput" accept="image/*">
<img id="previewImage" style="display: none;">
</div>
<div class="input-section">
<h3>Text Analysis</h3>
<textarea id="textInput" rows="3" placeholder="Enter text for sentiment analysis..."></textarea>
</div>
<div class="input-section">
<h3>Ask About Image</h3>
<input type="text" id="questionInput" placeholder="What can you see in the image?">
</div>
<button id="processBtn" disabled>Process</button>
<div id="results"></div>
<script>
// Initialize the web app
document.addEventListener('DOMContentLoaded', () => {
new MultimodalWebApp();
});
</script>
</body>
</html>
`;
// 10. Example Usage
async function demonstrateMultimodal() {
console.log('=== Multimodal AI Examples ===\n');
// Image Captioning
await imageCaptioning();
console.log('\n' + '='.repeat(50) + '\n');
// Visual Question Answering
await visualQuestionAnswering();
console.log('\n' + '='.repeat(50) + '\n');
// Document Processing
await documentProcessing();
console.log('\n' + '='.repeat(50) + '\n');
// Zero-Shot Image Classification
await zeroShotImageClassification();
console.log('\n' + '='.repeat(50) + '\n');
// Image-to-Image Tasks
await imageToImageTasks();
}
// Export classes and functions
export {
imageCaptioning,
visualQuestionAnswering,
documentProcessing,
zeroShotImageClassification,
imageToImageTasks,
MultimodalChat,
ContentModerator,
MultimodalWebApp,
webAppHTML
};
// Run demonstration
if (typeof window === 'undefined') {
demonstrateMultimodal().catch(console.error);
}
💻 Serveur API Transformers.js Node.js javascript
🔴 complex
Construire des APIs REST et services backend avec Transformers.js pour les déploiements productifs
// Transformers.js Node.js API Server
// 1. Installation
// npm install @huggingface/transformers express multer cors
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const { pipeline } = require('@huggingface/transformers');
// 2. Initialize Express App
class TransformersAPIServer {
constructor(port = 3000) {
this.port = port;
this.app = express();
this.models = new Map();
this.setupMiddleware();
this.setupRoutes();
}
setupMiddleware() {
this.app.use(cors());
this.app.use(express.json({ limit: '50mb' }));
this.app.use(express.urlencoded({ extended: true }));
// File upload configuration
this.upload = multer({
dest: 'uploads/',
limits: {
fileSize: 10 * 1024 * 1024 // 10MB limit
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
cb(null, allowedTypes.includes(file.mimetype));
}
});
}
setupRoutes() {
// Health check
this.app.get('/health', (req, res) => {
res.json({
status: 'healthy',
models_loaded: Array.from(this.models.keys()),
memory: process.memoryUsage(),
uptime: process.uptime()
});
});
// Text classification
this.app.post('/api/classify', this.handleTextClassification.bind(this));
// Text generation
this.app.post('/api/generate', this.handleTextGeneration.bind(this));
// Image classification
this.app.post('/api/classify-image',
this.upload.single('image'),
this.handleImageClassification.bind(this)
);
// Image captioning
this.app.post('/api/caption',
this.upload.single('image'),
this.handleImageCaptioning.bind(this)
);
// Visual question answering
this.app.post('/api/vqa',
this.upload.single('image'),
this.handleVisualQA.bind(this)
);
// Zero-shot classification
this.app.post('/api/zero-shot', this.handleZeroShot.bind(this));
// Batch processing
this.app.post('/api/batch-process', this.handleBatchProcess.bind(this));
// Model management
this.app.get('/api/models', this.handleListModels.bind(this));
this.app.post('/api/models/load', this.handleLoadModel.bind(this));
this.app.post('/api/models/unload', this.handleUnloadModel.bind(this));
}
async handleTextClassification(req, res) {
try {
const { text, model = 'distilbert-base-uncased-finetuned-sst-2-english' } = req.body;
if (!text) {
return res.status(400).json({ error: 'Text is required' });
}
const classifier = await this.getModel('classification', model);
const result = await classifier(text);
res.json({
text,
model,
results: Array.isArray(result) ? result : [result]
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async handleTextGeneration(req, res) {
try {
const {
prompt,
model = 'gpt2',
max_length = 100,
temperature = 0.7,
do_sample = true,
top_p = 0.9
} = req.body;
if (!prompt) {
return res.status(400).json({ error: 'Prompt is required' });
}
const generator = await this.getModel('generation', model);
const result = await generator(prompt, {
max_length,
temperature,
do_sample,
top_p
});
res.json({
prompt,
model,
generated_text: result[0].generated_text,
parameters: { max_length, temperature, do_sample, top_p }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async handleImageClassification(req, res) {
try {
if (!req.file) {
return res.status(400).json({ error: 'Image file is required' });
}
const { model = 'google/vit-base-patch16-224' } = req.body;
const classifier = await this.getModel('image-classification', model);
const result = await classifier(req.file.path);
// Clean up uploaded file
fs.unlinkSync(req.file.path);
res.json({
model,
filename: req.file.originalname,
results: result.slice(0, 5) // Return top 5 results
});
} catch (error) {
// Clean up file on error
if (req.file) {
fs.unlinkSync(req.file.path);
}
res.status(500).json({ error: error.message });
}
}
async handleImageCaptioning(req, res) {
try {
if (!req.file) {
return res.status(400).json({ error: 'Image file is required' });
}
const { model = 'nlpconnect/vit-gpt2-image-captioning' } = req.body;
const captioner = await this.getModel('image-captioning', model);
const result = await captioner(req.file.path);
// Clean up uploaded file
fs.unlinkSync(req.file.path);
res.json({
model,
filename: req.file.originalname,
caption: result[0].generated_text
});
} catch (error) {
if (req.file) {
fs.unlinkSync(req.file.path);
}
res.status(500).json({ error: error.message });
}
}
async handleVisualQA(req, res) {
try {
if (!req.file) {
return res.status(400).json({ error: 'Image file is required' });
}
const { question, model = 'dandelin/vilt-b32-finetuned-vqa' } = req.body;
if (!question) {
fs.unlinkSync(req.file.path);
return res.status(400).json({ error: 'Question is required' });
}
const vqaModel = await this.getModel('visual-qa', model);
const result = await vqaModel(req.file.path, question);
// Clean up uploaded file
fs.unlinkSync(req.file.path);
res.json({
model,
filename: req.file.originalname,
question,
answer: result[0].answer,
score: result[0].score
});
} catch (error) {
if (req.file) {
fs.unlinkSync(req.file.path);
}
res.status(500).json({ error: error.message });
}
}
async handleZeroShot(req, res) {
try {
const {
text,
candidate_labels,
model = 'facebook/bart-large-mnli'
} = req.body;
if (!text || !candidate_labels) {
return res.status(400).json({
error: 'Text and candidate_labels are required'
});
}
const classifier = await this.getModel('zero-shot', model);
const result = await classifier(text, candidate_labels);
res.json({
text,
candidate_labels,
model,
labels: result.labels,
scores: result.scores
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async handleBatchProcess(req, res) {
try {
const { task, items, model, parameters = {} } = req.body;
if (!task || !items || !Array.isArray(items)) {
return res.status(400).json({
error: 'Task and items array are required'
});
}
const batchSize = parameters.batchSize || 10;
const results = [];
// Get appropriate model
const modelKey = this.getModelKeyFromTask(task);
const pipelineModel = await this.getModel(modelKey, model);
// Process in batches
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
try {
const batchResults = await this.processBatch(pipelineModel, batch, task, parameters);
results.push(...batchResults);
} catch (error) {
console.error(`Batch processing error for batch ${Math.floor(i/batchSize)}:`, error);
results.push(...batch.map(item => ({
item,
error: error.message
})));
}
}
res.json({
task,
model,
total_items: items.length,
results
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async processBatch(model, batch, task, parameters) {
switch (task) {
case 'text-classification':
return await Promise.all(
batch.map(item => model(item.text || item))
);
case 'text-generation':
return await Promise.all(
batch.map(item => model(item.text || item, parameters))
);
default:
throw new Error(`Unsupported batch task: ${task}`);
}
}
async handleListModels(req, res) {
res.json({
loaded_models: Array.from(this.models.keys()),
available_tasks: [
'classification',
'generation',
'image-classification',
'image-captioning',
'visual-qa',
'zero-shot'
]
});
}
async handleLoadModel(req, res) {
try {
const { task, model } = req.body;
if (!task || !model) {
return res.status(400).json({
error: 'Task and model are required'
});
}
const modelKey = `${task}-${model}`;
if (this.models.has(modelKey)) {
return res.json({ message: 'Model already loaded' });
}
console.log(`Loading model: ${modelKey}`);
const pipelineModel = await pipeline(this.getTaskName(task), model);
this.models.set(modelKey, pipelineModel);
res.json({
message: 'Model loaded successfully',
model_key: modelKey
});
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async handleUnloadModel(req, res) {
try {
const { task, model } = req.body;
const modelKey = `${task}-${model}`;
if (this.models.has(modelKey)) {
this.models.delete(modelKey);
res.json({ message: 'Model unloaded successfully' });
} else {
res.status(404).json({ error: 'Model not found' });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getModel(task, modelName) {
const modelKey = `${task}-${modelName}`;
if (!this.models.has(modelKey)) {
console.log(`Loading model: ${modelKey}`);
const pipelineModel = await pipeline(this.getTaskName(task), modelName);
this.models.set(modelKey, pipelineModel);
}
return this.models.get(modelKey);
}
getModelKeyFromTask(task) {
const mapping = {
'text-classification': 'classification',
'text-generation': 'generation',
'zero-shot-classification': 'zero-shot'
};
return mapping[task] || task;
}
getTaskName(task) {
const mapping = {
'classification': 'text-classification',
'generation': 'text-generation',
'image-classification': 'image-classification',
'image-captioning': 'image-to-text',
'visual-qa': 'visual-question-answering',
'zero-shot': 'zero-shot-classification'
};
return mapping[task] || task;
}
start() {
// Create uploads directory if it doesn't exist
if (!fs.existsSync('uploads')) {
fs.mkdirSync('uploads');
}
this.app.listen(this.port, () => {
console.log(`Transformers.js API Server running on port ${this.port}`);
console.log('Available endpoints:');
console.log(' POST /api/classify - Text classification');
console.log(' POST /api/generate - Text generation');
console.log(' POST /api/classify-image - Image classification');
console.log(' POST /api/caption - Image captioning');
console.log(' POST /api/vqa - Visual question answering');
console.log(' POST /api/zero-shot - Zero-shot classification');
console.log(' POST /api/batch-process - Batch processing');
console.log(' GET /api/models - Model management');
console.log(' GET /health - Health check');
});
}
}
// 3. Advanced Features - Model Cache and Memory Management
class ModelCache {
constructor(maxModels = 5, maxAge = 30 * 60 * 1000) { // 30 minutes
this.cache = new Map();
this.maxModels = maxModels;
this.maxAge = maxAge;
}
async get(key, factory) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.maxAge) {
cached.lastUsed = Date.now();
return cached.model;
}
// Remove oldest if cache is full
if (this.cache.size >= this.maxModels) {
this.evictOldest();
}
// Load new model
console.log(`Loading model: ${key}`);
const model = await factory();
this.cache.set(key, {
model,
timestamp: Date.now(),
lastUsed: Date.now()
});
return model;
}
evictOldest() {
let oldestKey = null;
let oldestTime = Date.now();
for (const [key, value] of this.cache) {
if (value.lastUsed < oldestTime) {
oldestTime = value.lastUsed;
oldestKey = key;
}
}
if (oldestKey) {
console.log(`Evicting model: ${oldestKey}`);
this.cache.delete(oldestKey);
}
}
cleanup() {
this.cache.clear();
}
}
// 4. Rate Limiting
class RateLimiter {
constructor(maxRequests = 100, windowMs = 60000) { // 100 requests per minute
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = new Map();
}
isAllowed(clientId) {
const now = Date.now();
const windowStart = now - this.windowMs;
// Get or initialize client requests
let clientRequests = this.requests.get(clientId) || [];
// Remove old requests outside the window
clientRequests = clientRequests.filter(time => time > windowStart);
// Check if under limit
if (clientRequests.length >= this.maxRequests) {
return false;
}
// Add current request
clientRequests.push(now);
this.requests.set(clientId, clientRequests);
return true;
}
middleware() {
return (req, res, next) => {
const clientId = req.ip || req.connection.remoteAddress;
if (!this.isAllowed(clientId)) {
return res.status(429).json({
error: 'Too many requests',
retryAfter: Math.ceil(this.windowMs / 1000)
});
}
next();
};
}
}
// 5. Enhanced Server with Advanced Features
class EnhancedAPIServer extends TransformersAPIServer {
constructor(port = 3000) {
super(port);
this.modelCache = new ModelCache();
this.rateLimiter = new RateLimiter();
this.setupAdvancedMiddleware();
}
setupAdvancedMiddleware() {
// Add rate limiting
this.app.use(this.rateLimiter.middleware());
// Add request logging
this.app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} - ${res.statusCode} (${duration}ms)`);
});
next();
});
// Add error handling
this.app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
res.status(500).json({
error: 'Internal server error',
requestId: req.id
});
});
}
async getModel(task, modelName) {
const modelKey = `${task}-${modelName}`;
return await this.modelCache.get(modelKey, async () => {
return await pipeline(this.getTaskName(task), modelName);
});
}
}
// 6. Deployment Configuration
// package.json scripts:
// "start": "node server.js",
// "dev": "nodemon server.js",
// "pm2": "pm2 start ecosystem.config.js"
// ecosystem.config.js for PM2:
const ecosystemConfig = {
apps: [{
name: 'transformers-api',
script: './server.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000
},
max_memory_restart: '1G',
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log'
}]
};
// Dockerfile:
const dockerfile = `
FROM node:18-slim
WORKDIR /app
# Install system dependencies for Transformers.js
RUN apt-get update && apt-get install -y \
build-essential \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Create necessary directories
RUN mkdir -p uploads logs
# Expose port
EXPOSE 3000
# Start the application
CMD ["npm", "start"]
`;
// 7. Start the server
if (require.main === module) {
const server = new EnhancedAPIServer(process.env.PORT || 3000);
server.start();
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('Received SIGTERM, shutting down gracefully');
process.exit(0);
});
process.on('SIGINT', () => {
console.log('Received SIGINT, shutting down gracefully');
process.exit(0);
});
}
module.exports = {
TransformersAPIServer,
EnhancedAPIServer,
ModelCache,
RateLimiter,
ecosystemConfig,
dockerfile
};