// Dashboard functionality for Marine Species API
class MarineDashboard {
constructor() {
this.currentImage = null;
this.currentImageFile = null;
this.isProcessing = false;
this.initializeElements();
this.bindEvents();
this.checkAPIStatus();
this.loadSampleImages();
}
initializeElements() {
// Upload elements
this.uploadArea = document.getElementById('uploadArea');
this.fileInput = document.getElementById('fileInput');
this.identifyBtn = document.getElementById('identifyBtn');
// Settings elements
this.confidenceSlider = document.getElementById('confidenceSlider');
this.confidenceValue = document.getElementById('confidenceValue');
this.iouSlider = document.getElementById('iouSlider');
this.iouValue = document.getElementById('iouValue');
// Display elements
this.annotatedImageContainer = document.getElementById('annotatedImageContainer');
// Results elements
this.metadataSection = document.getElementById('metadataSection');
this.speciesSection = document.getElementById('speciesSection');
this.processingTime = document.getElementById('processingTime');
this.speciesCount = document.getElementById('speciesCount');
this.imageSize = document.getElementById('imageSize');
this.speciesList = document.getElementById('speciesList');
// Status elements
this.statusDot = document.getElementById('statusDot');
this.statusText = document.getElementById('statusText');
this.modelInfo = document.getElementById('modelInfo');
// Model details elements
this.totalSpecies = document.getElementById('totalSpecies');
this.deviceInfo = document.getElementById('deviceInfo');
// Sample images
this.sampleImagesSlider = document.getElementById('sampleImagesSlider');
this.sliderPrev = document.getElementById('sliderPrev');
this.sliderNext = document.getElementById('sliderNext');
}
bindEvents() {
// Upload area events
this.uploadArea.addEventListener('click', () => this.fileInput.click());
this.uploadArea.addEventListener('dragover', this.handleDragOver.bind(this));
this.uploadArea.addEventListener('dragleave', this.handleDragLeave.bind(this));
this.uploadArea.addEventListener('drop', this.handleDrop.bind(this));
// File input change
this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
// Settings sliders
this.confidenceSlider.addEventListener('input', this.updateConfidenceValue.bind(this));
this.iouSlider.addEventListener('input', this.updateIouValue.bind(this));
// Identify button
this.identifyBtn.addEventListener('click', this.identifySpecies.bind(this));
// Slider controls
this.sliderPrev.addEventListener('click', this.scrollSliderLeft.bind(this));
this.sliderNext.addEventListener('click', this.scrollSliderRight.bind(this));
}
// API Status Check
async checkAPIStatus() {
try {
const response = await fetch('/api/v1/health');
const data = await response.json();
if (data.model_loaded) {
this.statusDot.className = 'status-dot healthy';
this.statusText.textContent = 'API Ready';
if (data.model_info) {
this.modelInfo.textContent = `Model: ${data.model_info.model_name} (${data.model_info.total_classes} species)`;
this.totalSpecies.textContent = data.model_info.total_classes;
this.deviceInfo.textContent = data.model_info.device;
}
} else {
this.statusDot.className = 'status-dot error';
this.statusText.textContent = 'Model Loading...';
this.modelInfo.textContent = 'Please wait while the model loads';
}
} catch (error) {
this.statusDot.className = 'status-dot error';
this.statusText.textContent = 'API Unavailable';
this.modelInfo.textContent = 'Unable to connect to API';
console.error('API status check failed:', error);
}
}
// Drag and Drop Handlers
handleDragOver(e) {
e.preventDefault();
this.uploadArea.classList.add('dragover');
}
handleDragLeave(e) {
e.preventDefault();
this.uploadArea.classList.remove('dragover');
}
handleDrop(e) {
e.preventDefault();
this.uploadArea.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
this.processFile(files[0]);
}
}
// File Selection Handler
handleFileSelect(e) {
const file = e.target.files[0];
if (file) {
this.processFile(file);
}
}
// Process Selected File
processFile(file) {
// Validate file type
if (!file.type.startsWith('image/')) {
window.MarineAPI.utils.showNotification('Please select an image file', 'error');
return;
}
// Validate file size (10MB limit)
if (file.size > 10 * 1024 * 1024) {
window.MarineAPI.utils.showNotification('File size must be less than 10MB', 'error');
return;
}
this.currentImageFile = file;
this.displayUploadedImage(file);
this.identifyBtn.disabled = false;
// Update upload area
this.uploadArea.classList.add('has-image');
}
// Display Uploaded Image in Upload Area
displayUploadedImage(file) {
const reader = new FileReader();
reader.onload = (e) => {
this.currentImage = e.target.result;
this.uploadArea.innerHTML = `
`;
};
reader.readAsDataURL(file);
}
// Settings Handlers
updateConfidenceValue() {
this.confidenceValue.textContent = `${this.confidenceSlider.value}%`;
}
updateIouValue() {
this.iouValue.textContent = `${this.iouSlider.value}%`;
}
// Main Identification Function
async identifySpecies() {
if (!this.currentImage || this.isProcessing) return;
this.isProcessing = true;
window.MarineAPI.utils.setLoading(this.identifyBtn, true);
try {
// Prepare request data
const requestData = {
image: this.currentImage.split(',')[1], // Remove data:image/jpeg;base64, prefix
confidence_threshold: this.confidenceSlider.value / 100,
iou_threshold: this.iouSlider.value / 100,
image_size: 640,
return_annotated_image: true
};
// Make API request
const response = await fetch('/api/v1/detect', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData)
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const result = await response.json();
this.displayResults(result);
window.MarineAPI.utils.showNotification('Species identification completed!', 'success');
} catch (error) {
console.error('Identification failed:', error);
window.MarineAPI.utils.showNotification('Identification failed. Please try again.', 'error');
} finally {
this.isProcessing = false;
window.MarineAPI.utils.setLoading(this.identifyBtn, false);
}
}
// Display Results
displayResults(result) {
const { detections, annotated_image, processing_time, image_dimensions } = result;
// Display annotated image
if (annotated_image) {
this.annotatedImageContainer.innerHTML = `
`;
}
// Update metadata
this.processingTime.textContent = `${processing_time.toFixed(3)}s`;
this.speciesCount.textContent = detections.length;
this.imageSize.textContent = `${image_dimensions.width}×${image_dimensions.height}`;
// Show metadata section
this.metadataSection.style.display = 'block';
// Display species list
if (detections.length > 0) {
this.speciesList.innerHTML = detections.map(detection => `
No marine species detected. Try adjusting the confidence threshold.
'; this.speciesSection.style.display = 'block'; } } // Load Sample Images loadSampleImages() { const sampleImages = [ { name: 'crab.png', description: 'Crab Species' }, { name: 'fish.png', description: 'Fish Species' }, { name: 'fish_2.png', description: 'Fish Variety' }, { name: 'fish_3.png', description: 'Marine Fish' }, { name: 'fish_4.png', description: 'Ocean Fish' }, { name: 'fish_5.png', description: 'Deep Sea Fish' }, { name: 'flat_fish.png', description: 'Flatfish' }, { name: 'flat_red_fish.png', description: 'Red Flatfish' }, { name: 'jelly.png', description: 'Jellyfish' }, { name: 'jelly_2.png', description: 'Jellyfish Species' }, { name: 'jelly_3.png', description: 'Marine Jelly' }, { name: 'puff.png', description: 'Pufferfish' }, { name: 'red_fish.png', description: 'Red Fish' }, { name: 'red_fish_2.png', description: 'Red Fish Species' }, { name: 'scene.png', description: 'Marine Scene' }, { name: 'scene_2.png', description: 'Ocean Scene' }, { name: 'scene_3.png', description: 'Underwater Scene' }, { name: 'scene_4.png', description: 'Deep Sea Scene' }, { name: 'scene_5.png', description: 'Marine Habitat' }, { name: 'scene_6.png', description: 'Ocean Floor' }, { name: 'soft_coral.png', description: 'Soft Coral' }, { name: 'starfish.png', description: 'Starfish' }, { name: 'starfish_2.png', description: 'Sea Star' } ].map(img => ({ ...img, url: `https://huggingface.co/seamo-ai/marina-species-v1/resolve/main/images/${img.name}` })); this.sampleImagesSlider.innerHTML = sampleImages.map(image => `