| import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0'; |
|
|
| |
| env.allowLocalModels = false; |
|
|
| |
| const statusText = document.getElementById('status-text'); |
| const fileUpload = document.getElementById('file-upload'); |
| const uploadLabel = document.querySelector('.upload-label'); |
| const imagePreview = document.getElementById('image-preview'); |
| const labelsInput = document.getElementById('labels-input'); |
| const classifyBtn = document.getElementById('classify-btn'); |
| const resultsContainer = document.getElementById('results-container'); |
| const spinner = document.querySelector('.spinner'); |
|
|
|
|
| |
| statusText.textContent = 'Loading model...'; |
| spinner.style.display = 'block'; |
| const classifier = await pipeline('zero-shot-image-classification', 'Xenova/clip-vit-base-patch16'); |
| statusText.textContent = 'Ready'; |
| spinner.style.display = 'none'; |
|
|
| let imageSrc = null; |
|
|
| function handleFile(file) { |
| if (!file) { |
| return; |
| } |
|
|
| const reader = new FileReader(); |
|
|
| reader.onload = function (e2) { |
| imageSrc = e2.target.result; |
| imagePreview.innerHTML = `<img src="${imageSrc}" alt="uploaded image">`; |
| resultsContainer.innerHTML = `<div class="placeholder"> |
| <i class="fas fa-chart-pie"></i> |
| <h2>Results will be displayed here</h2> |
| <p>Get instant classification results</p> |
| </div>`; |
| }; |
| reader.readAsDataURL(file); |
| } |
|
|
| fileUpload.addEventListener('change', (e) => { |
| handleFile(e.target.files[0]); |
| }); |
|
|
| |
|
|
| function preventDefaults(e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| } |
|
|
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { |
| uploadLabel.addEventListener(eventName, preventDefaults, false); |
| document.body.addEventListener(eventName, preventDefaults, false); |
| }); |
|
|
| ['dragenter', 'dragover'].forEach(eventName => { |
| uploadLabel.addEventListener(eventName, () => { |
| uploadLabel.classList.add('highlight'); |
| }, false); |
| }); |
|
|
| ['dragleave', 'drop'].forEach(eventName => { |
| uploadLabel.addEventListener(eventName, () => { |
| uploadLabel.classList.remove('highlight'); |
| }, false); |
| }); |
|
|
| uploadLabel.addEventListener('drop', (e) => { |
| const dt = e.dataTransfer; |
| const files = dt.files; |
| if (files.length > 0) { |
| handleFile(files[0]); |
| } |
| }); |
|
|
| classifyBtn.addEventListener('click', function () { |
| if (!imageSrc) { |
| alert('Please upload an image first.'); |
| return; |
| } |
| const labels = labelsInput.value.split(',').map(label => label.trim()).filter(label => label); |
| if (labels.length === 0) { |
| alert('Please enter at least one label.'); |
| return; |
| } |
| classify(imageSrc, labels); |
| }); |
|
|
| |
| async function classify(img, labels) { |
| statusText.textContent = 'Analysing...'; |
| spinner.style.display = 'block'; |
| resultsContainer.innerHTML = ''; |
| const output = await classifier(img, labels); |
| statusText.textContent = ''; |
| spinner.style.display = 'none'; |
| renderResults(output); |
| } |
|
|
| |
| function renderResults(output) { |
| resultsContainer.innerHTML = ''; |
| if (output.length === 0) { |
| resultsContainer.innerHTML = '<p>No results found.</p>'; |
| return; |
| } |
| output.sort((a, b) => b.score - a.score); |
| output.forEach(({ label, score }) => { |
| const resultElement = document.createElement('div'); |
| resultElement.className = 'result'; |
|
|
| const labelElement = document.createElement('span'); |
| labelElement.textContent = label; |
|
|
| const scoreElement = document.createElement('span'); |
| scoreElement.textContent = `${(score * 100).toFixed(2)}%`; |
|
|
| resultElement.appendChild(labelElement); |
| resultElement.appendChild(scoreElement); |
| resultsContainer.appendChild(resultElement); |
| }); |
| } |