Tu suis la course aux modèles IA ?
Chaque sortie (GPT, Claude, Gemini, Mistral…) décryptée le soir même, en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisis ton rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Introduction à l'IA multimodale dans le navigateur
L'intégration de l'intelligence artificielle multimodale directement dans le navigateur est désormais possible grâce à Transformers.js. Ce framework innovant permet d'exécuter des tâches complexes telles que la classification d'images, le légendage d'images et la transcription de la parole, sans nécessiter de serveur externe ni de clé API. Les données sont traitées localement, garantissant ainsi une confidentialité accrue pour l'utilisateur.
Fonctionnalités prises en charge
Transformers.js offre une large gamme de fonctionnalités, notamment la vision par ordinateur avec la classification d'images, la détection d'objets et la segmentation. En matière d'audio, il prend en charge la reconnaissance automatique de la parole, la classification audio et la synthèse vocale. Ces tâches multimodales fonctionnent toutes localement dans le navigateur, ce qui signifie que les données ne quittent jamais l'appareil de l'utilisateur.
Mise en œuvre des capacités multimodales
Le tutoriel proposé par Transformers.js guide les utilisateurs à travers la création de trois capacités distinctes : la classification d'images, le légendage d'images et la transcription de la parole. Chaque capacité est implémentée dans un fichier HTML autonome, pouvant être ouvert directement dans un navigateur. La section finale du tutoriel montre comment combiner ces trois capacités en un analyseur multimédia multimodal unique.
Configuration requise
Pour utiliser Transformers.js, un navigateur moderne est nécessaire. Les versions requises incluent Chrome 109+, Edge 109+, ou Firefox 90+, qui prennent en charge les modules ES et WebAssembly, indispensables pour le fonctionnement de Transformers.js. De plus, un serveur web local est requis pour contourner les restrictions de sécurité des navigateurs qui bloquent les importations de modules ES à partir des URL file://. Les utilisateurs peuvent choisir entre plusieurs options pour démarrer un serveur local, telles que Python, Node.js ou l'extension Live Server de VS Code.
Démarrage d'un serveur local
Pour lancer un serveur local, les utilisateurs peuvent utiliser Python, qui est pré-installé sur macOS et la plupart des systèmes Linux, avec la commande suivante :
python3 -m http.server 8080
Pour ceux qui préfèrent Node.js, la commande suivante peut être utilisée :
npx serve .
Enfin, pour les utilisateurs de VS Code, l'extension Live Server peut être installée. Il suffit ensuite de cliquer avec le bouton droit sur n'importe quel fichier HTML et de choisir "Ouvrir avec Live Server". Une fois le serveur en cours d'exécution, il suffit d'ouvrir http://localhost:8080 dans le navigateur.
Structure du projet
Le projet est structuré de manière à ce que chaque tâche ait son propre fichier HTML. Voici comment organiser les fichiers dans un dossier nommé multimodal-demo :
multimodal-demo/
├── image-classifier.html
├── image-captioner.html
├── speech-transcriber.html
└── media-analyzer.html
Modèles et tailles de téléchargement
Lors de la première exécution, chaque modèle est téléchargé et mis en cache dans le navigateur, permettant un fonctionnement hors ligne par la suite. Voici les détails des modèles utilisés :
- Classification d'images : Le modèle utilisé est Xenova/vit-base-patch16-224, qui pèse environ 88 Mo.
- Légendage d'images : Le modèle Xenova/vit-gpt2-image-captioning est utilisé, avec une taille d'environ 246 Mo.
- Transcription de la parole : Le modèle Xenova/whisper-tiny.en pèse environ 78 Mo.
L'application combinée charge les trois modèles, soit environ 400 Mo au total lors de la première exécution. Un indicateur de progression pour chaque modèle est indispensable pour offrir une bonne expérience utilisateur.
Tâche 1 : Classification d'images
La classification d'images consiste à attribuer des étiquettes d'un ensemble fixe à une image d'entrée. Le modèle utilisé ici est ViT-Base/16, un Vision Transformer entraîné par Google sur ImageNet-21k et affiné sur ImageNet-1k, converti au format ONNX pour une utilisation dans le navigateur. Il classe les images en 1 000 catégories ImageNet et renvoie une liste classée avec des scores de confiance.
Exemple de sortie
// Sortie du classificateur(imageUrl)
[
{ label: 'golden retriever', score: 0.9421 },
{ label: 'Labrador retriever', score: 0.0312 },
{ label: 'Sussex spaniel', score: 0.0098 },
// ... résultats top_k au total
]
Chaque objet a une chaîne d'étiquette (le nom de la classe ImageNet) et un score flottant entre 0 et 1. Par défaut, le pipeline renvoie 5 résultats. Définissez top_k dans l'appel pour obtenir plus ou moins de résultats.
Démonstration complète
Enregistrez ce fichier sous image-classifier.html dans votre dossier de projet. Copiez le code ci-dessous et ouvrez-le sur votre localhost.
<title>Image Classifier</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
max-width: 700px;
margin: 2rem auto;
padding: 0 1rem;
background: #f8fafc;
color: #1e293b;
}
h1 { margin-bottom: 0.25rem; font-size: 1.4rem; }
.subtitle { color: #64748b; font-size: 0.9rem; margin-bottom: 1.5rem; }
#status { font-size: 0.85rem; color: #64748b; margin-bottom: 1rem; }
.upload-area {
border: 2px dashed #cbd5e1;
border-radius: 8px;
padding: 2rem;
text-align: center;
[cursor](/outil/cursor): pointer;
background: white;
transition: border-color 0.2s;
}
.upload-area:hover { border-color: #2563eb; }
.upload-area input { display: none; }
#preview {
margin-top: 1rem;
max-width: 100%;
border-radius: 8px;
display: none;
}
.result-row {
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 0.6rem;
}
.result-label { min-width: 200px; font-size: 0.9rem; }
.bar-bg {
flex: 1;
background: #e2e8f0;
border-radius: 4px;
height: 16px;
}
.bar-fill {
background: #2563eb;
height: 100%;
border-radius: 4px;
transition: width 0.4s ease;
}
.result-score {
min-width: 48px;
text-align: right;
font-size: 0.85rem;
color: #475569;
}
#results { margin-top: 1.25rem; }
#results h3 { font-size: 0.95rem; color: #374151; margin-bottom: 0.5rem; }
</style>
<h1>Image Classifier</h1>
<p class="subtitle">
Téléchargez n'importe quelle image -- ViT la classifie dans les catégories ImageNet.
Fonctionne entièrement dans votre navigateur.
</p>
<div id="status">Téléchargement du modèle (~88 Mo au premier lancement)...</div>
<div class="upload-area" id="drop-zone">
<p>Cliquez pour télécharger ou faites glisser une image ici</p>
<p style="font-size:0.8rem;color:#94a3b8;margin-top:0.4rem">
JPG, PNG, WebP, GIF pris en charge
</p>
</div>
<img id="preview" alt="Aperçu" />
<div id="results"></div>
<script type="module">
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.2';
const statusEl = document.getElementById('status');
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
const preview = document.getElementById('preview');
const resultsEl = document.getElementById('results');
// ── Charger le pipeline de classification d'images ──────────────────────────
let classifier;
pipeline('image-classification', 'Xenova/vit-base-patch16-224', {
dtype: 'q8',
progress_callback: (p) => {
if (p.status === 'progress') {
statusEl.textContent = `Téléchargement du modèle : ${Math.round(p.progress ?? 0)}%`;
}
}
}).then(pipe => {
classifier = pipe;
statusEl.textContent = 'Modèle prêt. Téléchargez une image pour la classifier.';
dropZone.style.borderColor = '#22c55e';
}).catch(err => {
statusEl.textContent = `Erreur de chargement du modèle : ${err.message}`;
});
// ── Classifier une image à partir d'une URL de données ───────────────────────
async function classifyImage(dataUrl) {
statusEl.textContent = 'Classification...';
resultsEl.innerHTML = '';
try {
const results = await classifier(dataUrl, { top_k: 5 });
statusEl.textContent = 'Terminé.';
let html = '<h3>Meilleures prédictions</h3>';
results.forEach(({ label, score }) => {
const pct = (score * 100).toFixed(1);
const bar = (score * 100).toFixed(0);
html += `
<div class="result-row">
<span class="result-label">${label}</span>
<div class="bar-bg">
<div class="bar-fill" style="width:${bar}%"></div>
</div>
<span class="result-score">${pct}%</span>
</div>`;
});
resultsEl.innerHTML = html;
} catch (err) {
statusEl.textContent = `Erreur de classification : ${err.message}`;
}
}
// ── Gestion des fichiers ────────────────────────────────────────────────────
function handleFile(file) {
if (!file || !file.type.startsWith('image/')) return;
const reader = new FileReader();
reader.onload = (e) => {
const dataUrl = e.target.result;
preview.src = dataUrl;
preview.style.display = 'block';
if (classifier) {
classifyImage(dataUrl);
} else {
statusEl.textContent = 'Modèle en cours de chargement -- veuillez patienter un moment et réessayer.';
}
};
reader.readAsDataURL(file);
}
// Cliquez pour parcourir
dropZone.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
// Glisser-déposer
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#2563eb';
});
dropZone.addEventListener('dragleave', () => {
dropZone.style.borderColor = '#cbd5e1';
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#cbd5e1';
handleFile(e.dataTransfer.files[0]);
});
</script>
