|
|
<!doctype html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta name="description" content="Free AI-powered tool for identifying Mediterranean fish species. Upload a photo to classify 101 species using DINOv2 and YOLOv11 models."> |
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-QFG67BD3FB"></script> |
|
|
<script> |
|
|
window.dataLayer = window.dataLayer || []; |
|
|
function gtag(){dataLayer.push(arguments);} |
|
|
gtag('js', new Date()); |
|
|
|
|
|
|
|
|
gtag('config', 'G-QFG67BD3FB', { |
|
|
'cookie_flags': 'SameSite=None;Secure', |
|
|
'cookie_domain': 'auto' |
|
|
}); |
|
|
</script> |
|
|
|
|
|
<meta charset="utf-8" /> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|
|
<title>NEMO Tools</title> |
|
|
|
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<style> |
|
|
.toggle-wrapper { display:flex; align-items:center; gap:10px; cursor:pointer; } |
|
|
.toggle { width:44px; height:24px; background:#d1d5db; border-radius:9999px; position:relative; transition:0.2s; } |
|
|
.toggle-circle { width:20px; height:20px; background:white; border-radius:50%; position:absolute; top:2px; left:2px; transition:0.2s; } |
|
|
.toggle.active { background:#7c3aed; } |
|
|
.toggle.active .toggle-circle { transform:translateX(20px); } |
|
|
|
|
|
body { |
|
|
background-image: url('/static/background.jpg'); |
|
|
background-size: cover; |
|
|
background-position: center; |
|
|
background-attachment: fixed; |
|
|
background-repeat: no-repeat; |
|
|
color: #f9fafb; |
|
|
} |
|
|
body::before { |
|
|
content: ""; |
|
|
position: fixed; |
|
|
top: 0; left: 0; |
|
|
width: 100%; height: 100%; |
|
|
background: rgba(0, 10, 20, 0.3); |
|
|
z-index: -1; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
|
|
|
<body class="bg-gray-100 min-h-screen flex flex-col font-sans"> |
|
|
|
|
|
<header class="sticky top-0 z-50 backdrop-blur-md bg-white/70 border-b border-white/20 shadow-sm transition-all duration-300"> |
|
|
<div class="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between"> |
|
|
|
|
|
<div class="flex items-center gap-4 group cursor-pointer"> |
|
|
<div class="relative"> |
|
|
<div class="absolute -inset-1 bg-gradient-to-r from-blue-400 to-indigo-500 rounded-full blur opacity-25 group-hover:opacity-50 transition duration-500"></div> |
|
|
<img src="/static/assets/logo.png" |
|
|
alt="NEMO logo" |
|
|
class="relative h-16 w-16 rounded-full shadow-md border-2 border-white object-cover transform group-hover:scale-105 transition duration-300" /> |
|
|
</div> |
|
|
<div> |
|
|
<h1 class="text-2xl font-extrabold text-indigo-900 tracking-tight leading-none group-hover:text-indigo-700 transition">NEMO tools</h1> |
|
|
<p class="text-xs font-semibold text-indigo-500 uppercase tracking-wide mt-1">Mediterranean Fish Species Classification Tool</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<nav class="flex gap-2 md:gap-3 bg-white/50 p-1.5 rounded-full border border-white/40 shadow-inner"> |
|
|
<button id="tab-research" |
|
|
class="tab-btn px-5 py-2 rounded-full text-sm font-semibold text-slate-600 hover:text-indigo-700 hover:bg-white/80 transition-all duration-200 focus:outline-none" |
|
|
onclick="showTab('research')"> |
|
|
Research |
|
|
</button> |
|
|
<button id="tab-people" |
|
|
class="tab-btn px-5 py-2 rounded-full text-sm font-semibold text-slate-600 hover:text-indigo-700 hover:bg-white/80 transition-all duration-200 focus:outline-none" |
|
|
onclick="showTab('people')"> |
|
|
People |
|
|
</button> |
|
|
<button id="tab-tools" |
|
|
class="tab-btn px-6 py-2 rounded-full text-sm font-bold text-white bg-indigo-600 shadow-md hover:bg-indigo-700 hover:shadow-lg transition-all duration-200 transform hover:-translate-y-0.5 focus:outline-none" |
|
|
onclick="showTab('tools')"> |
|
|
Tools |
|
|
</button> |
|
|
</nav> |
|
|
|
|
|
</div> |
|
|
</header> |
|
|
|
|
|
<main class="max-w-6xl mx-auto px-4 py-8 w-full flex-grow"> |
|
|
|
|
|
<section id="page-people" class="hidden max-w-6xl mx-auto mb-12"> |
|
|
<div class="text-center mb-12"> |
|
|
<h2 class="text-3xl font-bold text-indigo-900">The Team</h2> |
|
|
<p class="text-lg text-gray-800 mt-2"> |
|
|
Our interdisciplinary team combines expertise in ecology, marine biology, and artificial intelligence. |
|
|
</p> |
|
|
</div> |
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/kofidis.jpg" alt="Andreas Kofidis" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Andreas Kofidis</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Data Scientist, IACM-FORTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
His research focuses on deep learning and computer vision, specifically in the development of robust algorithms for object detection and classification in challenging environments. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/dretaki.jpg" alt="Eleni Dretaki" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Eleni Dretaki</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Data Scientist, IACM-FORTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
A data scientist specializing in applied mathematics and statistical analysis. Her work involves processing complex datasets and developing computational methodologies for scientific applications. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/zotou.jpg" alt="Maria Zotou" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Maria Zotou</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">PhD candidate, UAegean</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
Her research interests lie in marine biodiversity assessment and ecosystem monitoring. She specializes in the taxonomy of Mediterranean marine fauna and field survey methodologies. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/poursanidis.jpg" alt="Dimitris Poursanidis" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Dr. Dimitris Poursanidis</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Technical Researcher, IACM-FORTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
An expert in remote sensing and coastal habitat mapping. His work utilizes satellite and drone imagery to study spatial patterns in marine environments and support conservation planning. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/doxa.jpg" alt="Aggeliki Doxa" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Dr. Aggeliki Doxa</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Associate Prof. of Biology, IACM-FORTH & UoC</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
Her research focuses on ecological modeling, biodiversity dynamics, and the impact of environmental changes on species distributions and ecosystem services. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/mazaris.jpg" alt="Antonios Mazaris" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Prof. Antonios D. Mazaris</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Professor of Ecology, AUTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
His work addresses large-scale conservation challenges, focusing on global biodiversity patterns, extinction risk assessments, and the effectiveness of protected area networks. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/katsanevakis.jpg" alt="Stelios Katsanevakis" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Prof. Stelios Katsanevakis</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Marine Ecologist, UAegean</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
His research investigates marine ecosystem dynamics, biological invasions, and marine conservation planning, aiming to support ecosystem-based management strategies. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/kamarianakis.jpg" alt="Yiannis Kamarianakis" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Dr. Yiannis Kamarianakis</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Research Director, IACM-FORTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
An expert in applied mathematics and statistics. He specializes in time-series analysis, spatial statistics, and the development of predictive models for complex systems. |
|
|
</p> |
|
|
</div> |
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col items-center text-center hover:shadow-xl transition"> |
|
|
<img src="/static/team/pantazis.jpg" alt="Yannis Pantazis" class="w-24 h-24 rounded-full mb-4 object-cover border-4 border-indigo-50 shadow-sm"> |
|
|
<h3 class="text-lg font-bold text-gray-800">Dr. Yannis Pantazis</h3> |
|
|
<span class="text-indigo-600 font-medium text-sm mb-3">Principal Researcher, IACM-FORTH</span> |
|
|
<p class="text-gray-600 text-sm leading-relaxed"> |
|
|
His research spans machine learning, signal processing, and data-driven discovery, focusing on developing novel AI architectures and mathematical frameworks for scientific applications. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
<section id="page-research" class="hidden max-w-5xl mx-auto mb-12"> |
|
|
<div class="bg-white shadow-lg rounded-2xl p-8"> |
|
|
|
|
|
<div class="border-b pb-6 mb-6"> |
|
|
<h2 class="text-3xl font-bold text-indigo-900">NEMO-Tools Project</h2> |
|
|
<p class="text-lg text-indigo-600 font-medium mt-2"> |
|
|
<span class="text-indigo-900 font-bold">NE</span>xt-generation |
|
|
<span class="text-indigo-900 font-bold">MO</span>nitoring and mapping |
|
|
<span class="text-indigo-900 font-bold">Tools</span> to assess marine ecosystems and biodiversity |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="prose max-w-none text-gray-700 leading-relaxed space-y-4"> |
|
|
<p> |
|
|
<strong>NEMO-Tools</strong> is an ambitious research initiative designed to develop affordable, user-friendly, and smart tools for marine biodiversity monitoring. Its primary goal is to support the <strong>EU Biodiversity Strategy for 2030</strong> by providing high-precision data to measure ecosystem health and recovery. |
|
|
</p> |
|
|
|
|
|
<p> |
|
|
While this web interface focuses on <strong>Artificial Intelligence (AI)</strong> for species identification, the full NEMO-Tools project integrates a hierarchical approach combining multiple cutting-edge technologies: |
|
|
</p> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 my-8"> |
|
|
<div class="bg-indigo-50 p-5 rounded-xl border border-indigo-100"> |
|
|
<h3 class="font-bold text-indigo-800 mb-2 flex items-center gap-2">🤖 Artificial Intelligence</h3> |
|
|
<p class="text-sm"> |
|
|
Utilizing Deep Learning (DINOv2, YOLOv11) to classify species from underwater imagery. This tool specifically utilizes the <strong>MEDFISH101</strong> dataset to identify 101 Mediterranean fish species. |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="bg-indigo-50 p-5 rounded-xl border border-indigo-100"> |
|
|
<h3 class="font-bold text-indigo-800 mb-2 flex items-center gap-2">🛰️ Remote Sensing</h3> |
|
|
<p class="text-sm"> |
|
|
Employing satellite (Planet SuperDove) and drone (UAV) imagery to map macroalgae forests and detect marine megafauna in shallow coastal waters. |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="bg-indigo-50 p-5 rounded-xl border border-indigo-100"> |
|
|
<h3 class="font-bold text-indigo-800 mb-2 flex items-center gap-2">🧬 Environmental DNA (eDNA)</h3> |
|
|
<p class="text-sm"> |
|
|
Developing cost-effective sampling protocols and low-cost 3D-printed probes to detect rare or elusive species through genetic material released in the water. |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="bg-indigo-50 p-5 rounded-xl border border-indigo-100"> |
|
|
<h3 class="font-bold text-indigo-800 mb-2 flex items-center gap-2">⚓ Robotics & Acoustics</h3> |
|
|
<p class="text-sm"> |
|
|
Deploying upgraded ROVs for quantitative benthic assessments and Ground Unmanned Vehicles (GUVs) for sandy shore monitoring. Includes low-cost hydrophones for citizen-science acoustic monitoring. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<p> |
|
|
The identification tool provided here addresses the challenge of monitoring visually similar species. |
|
|
It leverages the <strong>MEDFISH101</strong> dataset, a rigorously curated collection of approximately |
|
|
<strong>70,000 expert-validated images</strong>. This dataset represents 101 fish species |
|
|
inhabiting the Hellenic and Mediterranean seas, spanning major families such as <em>Sparidae</em>, |
|
|
<em>Serranidae</em>, and <em>Labridae</em>. |
|
|
</p> |
|
|
<p> |
|
|
By encompassing commercial, protected, and invasive species—including the Indo-Pacific Lionfish (<em>Pterois miles</em>)—the tool facilitates near real-time ecological monitoring and early detection |
|
|
of biological threats. Powered by state-of-the-art Vision Foundation Models achieving up to |
|
|
<strong>94,12% accuracy</strong> using DINOv2-Giant, it empowers citizen scientists to contribute reliable data for |
|
|
evidence-based marine management. |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="mt-10"> |
|
|
<h3 class="text-xl font-bold text-indigo-700 mb-4 flex items-center gap-2"> |
|
|
🐟 MEDFISH101 Species List |
|
|
</h3> |
|
|
<p class="text-sm text-gray-500 mb-4"> |
|
|
The following 101 species are currently supported by the model classification engine: |
|
|
</p> |
|
|
|
|
|
<div class="bg-gray-50 rounded-xl p-6 border border-gray-200 h-[500px] overflow-y-auto"> |
|
|
<ul class="grid grid-cols-1 md:grid-cols-3 gap-y-2 gap-x-4 text-sm text-gray-700 font-medium"> |
|
|
<li><i>Aidablennius sphynx</i></li> |
|
|
<li><i>Apogon imberbis</i></li> |
|
|
<li><i>Arnoglossus laterna</i></li> |
|
|
<li><i>Atherina boyeri</i></li> |
|
|
<li><i>Atherina hepsetus</i></li> |
|
|
<li><i>Boops boops</i></li> |
|
|
<li><i>Bothus podas</i></li> |
|
|
<li><i>Callionymus pusillus</i></li> |
|
|
<li><i>Callionymus risso</i></li> |
|
|
<li><i>Caranx crysos</i></li> |
|
|
<li><i>Chelidonichthys lucerna</i></li> |
|
|
<li><i>Chromis chromis</i></li> |
|
|
<li><i>Coris julis</i></li> |
|
|
<li><i>Dactylopterus volitans</i></li> |
|
|
<li><i>Dasyatis pastinaca</i></li> |
|
|
<li><i>Diplodus annularis</i></li> |
|
|
<li><i>Diplodus puntazzo</i></li> |
|
|
<li><i>Diplodus sargus</i></li> |
|
|
<li><i>Diplodus vulgaris</i></li> |
|
|
<li><i>Echiichthys vipera</i></li> |
|
|
<li><i>Epinephelus costae</i></li> |
|
|
<li><i>Epinephelus marginatus</i></li> |
|
|
<li><i>Fistularia commersonii</i></li> |
|
|
<li><i>Gobius auratus</i></li> |
|
|
<li><i>Gobius bucchichi</i></li> |
|
|
<li><i>Gobius cobitis</i></li> |
|
|
<li><i>Gobius cruentatus</i></li> |
|
|
<li><i>Gobius geniporus</i></li> |
|
|
<li><i>Gobius incognitus</i></li> |
|
|
<li><i>Gobius niger</i></li> |
|
|
<li><i>Gobius paganellus</i></li> |
|
|
<li><i>Gobius vittatus</i></li> |
|
|
<li><i>Hippocampus guttulatus</i></li> |
|
|
<li><i>Hippocampus hippocampus</i></li> |
|
|
<li><i>Labrus bergylta</i></li> |
|
|
<li><i>Labrus merula</i></li> |
|
|
<li><i>Labrus mixtus</i></li> |
|
|
<li><i>Labrus viridis</i></li> |
|
|
<li><i>Lagocephalus sceleratus</i></li> |
|
|
<li><i>Lithognathus mormyrus</i></li> |
|
|
<li><i>Microlipophrys nigriceps</i></li> |
|
|
<li><i>Mugil auratus</i></li> |
|
|
<li><i>Mugil cephalus</i></li> |
|
|
<li><i>Mullus barbatus</i></li> |
|
|
<li><i>Mullus surmuletus</i></li> |
|
|
<li><i>Muraena helena</i></li> |
|
|
<li><i>Oblada melanura</i></li> |
|
|
<li><i>Pagrus pagrus</i></li> |
|
|
<li><i>Parablennius gattorugine</i></li> |
|
|
<li><i>Parablennius incognitus</i></li> |
|
|
<li><i>Parablennius pilicornis</i></li> |
|
|
<li><i>Parablennius rouxi</i></li> |
|
|
<li><i>Parablennius sanguinolentus</i></li> |
|
|
<li><i>Parablennius tentacularis</i></li> |
|
|
<li><i>Parablennius zvonimiri</i></li> |
|
|
<li><i>Parupeneus forsskali</i></li> |
|
|
<li><i>Phycis phycis</i></li> |
|
|
<li><i>Plotosus lineatus</i></li> |
|
|
<li><i>Pomatoschistus marmoratus</i></li> |
|
|
<li><i>Pterois miles</i></li> |
|
|
<li><i>Salaria pavo</i></li> |
|
|
<li><i>Sargocentron rubrum</i></li> |
|
|
<li><i>Sarpa salpa</i></li> |
|
|
<li><i>Sciaena umbra</i></li> |
|
|
<li><i>Scorpaena maderensis</i></li> |
|
|
<li><i>Scorpaena notata</i></li> |
|
|
<li><i>Scorpaena scrofa</i></li> |
|
|
<li><i>Serranus cabrilla</i></li> |
|
|
<li><i>Serranus hepatus</i></li> |
|
|
<li><i>Serranus scriba</i></li> |
|
|
<li><i>Siganus luridus</i></li> |
|
|
<li><i>Siganus rivulatus</i></li> |
|
|
<li><i>Solea solea</i></li> |
|
|
<li><i>Sparisoma cretense</i></li> |
|
|
<li><i>Sparus aurata</i></li> |
|
|
<li><i>Spicara maena</i></li> |
|
|
<li><i>Spicara smaris</i></li> |
|
|
<li><i>Spondyliosoma cantharus</i></li> |
|
|
<li><i>Stephanolepis diaspros</i></li> |
|
|
<li><i>Symphodus cinereus</i></li> |
|
|
<li><i>Symphodus mediterraneus</i></li> |
|
|
<li><i>Symphodus melanocercus</i></li> |
|
|
<li><i>Symphodus ocellatus</i></li> |
|
|
<li><i>Symphodus roissali</i></li> |
|
|
<li><i>Symphodus rostratus</i></li> |
|
|
<li><i>Symphodus tinca</i></li> |
|
|
<li><i>Syngnathus abaster</i></li> |
|
|
<li><i>Syngnathus tenuirostris</i></li> |
|
|
<li><i>Syngnathus typhle</i></li> |
|
|
<li><i>Thalassoma pavo</i></li> |
|
|
<li><i>Thorogobius ephippiatus</i></li> |
|
|
<li><i>Torpedo marmorata</i></li> |
|
|
<li><i>Torquigener flavimaculosus</i></li> |
|
|
<li><i>Trachinus araneus</i></li> |
|
|
<li><i>Trachinus draco</i></li> |
|
|
<li><i>Trachinus radiatus</i></li> |
|
|
<li><i>Tripterygion delaisi</i></li> |
|
|
<li><i>Tripterygion melanurus</i></li> |
|
|
<li><i>Tripterygion tripteronotus</i></li> |
|
|
<li><i>Uranoscopus scaber</i></li> |
|
|
<li><i>Xyrichtys novacula</i></li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
<section id="page-tools"> |
|
|
<div class="bg-white shadow-lg rounded-2xl p-8 w-full"> |
|
|
<h2 class="text-2xl font-bold text-indigo-600 mb-6 flex items-center gap-2">🧰 Tools</h2> |
|
|
|
|
|
<div class="flex gap-3 mb-6 border-b pb-2"> |
|
|
<button id="sub-classification" class="subtab-btn text-indigo-600 font-medium border-b-2 border-indigo-600 pb-1" onclick="showSubTool('classification')">🔍 Classification</button> |
|
|
<button id="sub-attention" class="subtab-btn text-gray-500 hover:text-indigo-600 pb-1" onclick="showSubTool('attention')">🧠 Visualization</button> |
|
|
</div> |
|
|
|
|
|
<div id="tool-attention" class="flex flex-col items-center w-full mt-6"> |
|
|
|
|
|
<div class="flex flex-col md:flex-row w-full items-stretch justify-center gap-8 px-4"> |
|
|
|
|
|
<div class="flex-1 flex flex-col justify-center items-start gap-4 min-w-[250px]"> |
|
|
<p class="text-gray-600 font-semibold mb-1 text-sm">Choose your model:</p> |
|
|
|
|
|
<div class="toggle-wrapper group" onclick="setModel('dino')"> |
|
|
<div id="toggle-dino-vis" class="toggle active group-hover:ring-2 group-hover:ring-green-300"> |
|
|
<div class="toggle-circle shadow-sm"></div> |
|
|
</div> |
|
|
<div class="flex flex-col"> |
|
|
<span class="text-gray-800 font-bold text-sm">DINOv2-Giant</span> |
|
|
<span class="text-gray-400 text-xs">High accuracy, slower</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="toggle-wrapper group" onclick="setModel('yolo')"> |
|
|
<div id="toggle-yolo-vis" class="toggle group-hover:ring-2 group-hover:ring-green-300"> |
|
|
<div class="toggle-circle shadow-sm"></div> |
|
|
</div> |
|
|
<div class="flex flex-col"> |
|
|
<span class="text-gray-800 font-bold text-sm">YOLOv11-X</span> |
|
|
<span class="text-gray-400 text-xs">Lower accuracy, faster</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex-1 flex flex-col justify-center items-center text-center border-2 border-dashed border-gray-300 rounded-xl p-6 bg-gray-50 hover:bg-gray-100 transition min-w-[300px]"> |
|
|
<p class="text-gray-700 font-bold mb-2">Upload Image</p> |
|
|
<p class="text-gray-400 text-xs mb-5">Supported: JPG, PNG</p> |
|
|
|
|
|
<label for="vis-file" |
|
|
class="inline-flex items-center justify-center gap-2 px-8 py-3 bg-green-600 hover:bg-green-700 text-white font-bold rounded-full cursor-pointer shadow-md transition-all transform hover:scale-105"> |
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5"> |
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /> |
|
|
</svg> |
|
|
Choose File |
|
|
</label> |
|
|
|
|
|
<input id="vis-file" type="file" accept="image/*" class="hidden" onchange="onVisFileSelected()" /> |
|
|
<p id="vis-filename" class="text-gray-500 mt-3 text-xs italic font-medium"></p> |
|
|
</div> |
|
|
|
|
|
<div class="flex-1 min-w-[250px] hidden md:block"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="w-full flex justify-center mt-6"> |
|
|
<button id="vis-run" onclick="runVisualization()" |
|
|
style="display:none;" |
|
|
class="px-8 py-3 bg-indigo-600 text-white text-lg font-semibold rounded-full shadow-md hover:bg-indigo-700 transition transform hover:scale-105"> |
|
|
▶️ Run Visualization |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div id="attention-extra" class="hidden flex flex-col items-center gap-6 w-full mt-8"> |
|
|
|
|
|
<div class="flex flex-col md:flex-row justify-center items-start gap-6"> |
|
|
<div class="flex flex-col items-center"> |
|
|
<h4 class="text-gray-600 mb-2 font-medium">Original Image</h4> |
|
|
<img id="original" class="rounded-lg shadow-md max-w-[200px] hidden" /> |
|
|
</div> |
|
|
|
|
|
<div class="flex flex-col items-center"> |
|
|
<h4 class="text-gray-600 mb-2 font-medium">PCA Attention</h4> |
|
|
<img id="output" class="rounded-lg shadow-md max-w-[200px] hidden" /> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="headsContainer" class="hidden mt-8 w-full"> |
|
|
<h4 class="text-gray-600 mb-3 font-medium text-center">All Attention Heads</h4> |
|
|
<div id="headsGrid" class="flex flex-wrap justify-center gap-3"></div> |
|
|
</div> |
|
|
|
|
|
<p id="status" class="text-center text-gray-500 mt-2 text-sm"></p> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div id="tool-classification" class="hidden flex flex-col items-start mt-6 w-full"> |
|
|
|
|
|
<div class="flex flex-col md:flex-row w-full items-stretch justify-center gap-8 px-4"> |
|
|
|
|
|
<div class="flex-1 flex flex-col justify-center items-start gap-4 min-w-[250px]"> |
|
|
<p class="text-gray-600 font-semibold mb-1 text-sm">Choose your model:</p> |
|
|
|
|
|
<div class="toggle-wrapper group" onclick="setModel('dino')"> |
|
|
<div id="toggle-dino-cls" class="toggle active group-hover:ring-2 group-hover:ring-green-300"> |
|
|
<div class="toggle-circle shadow-sm"></div> |
|
|
</div> |
|
|
<div class="flex flex-col"> |
|
|
<span class="text-gray-800 font-bold text-sm">DINOv2-Giant</span> |
|
|
<span class="text-gray-400 text-xs">High accuracy, slower</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="toggle-wrapper group" onclick="setModel('yolo')"> |
|
|
<div id="toggle-yolo-cls" class="toggle group-hover:ring-2 group-hover:ring-green-300"> |
|
|
<div class="toggle-circle shadow-sm"></div> |
|
|
</div> |
|
|
<div class="flex flex-col"> |
|
|
<span class="text-gray-800 font-bold text-sm">YOLOv11-X</span> |
|
|
<span class="text-gray-400 text-xs">Lower accuracy, faster</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex-1 flex flex-col justify-center items-center text-center border-2 border-dashed border-gray-300 rounded-xl p-6 bg-gray-50 hover:bg-gray-100 transition min-w-[300px]"> |
|
|
<p class="text-gray-700 font-bold mb-2">Upload Image</p> |
|
|
<p class="text-gray-400 text-xs mb-5">Supported: JPG, PNG</p> |
|
|
|
|
|
<label for="cls-file" |
|
|
class="inline-flex items-center justify-center gap-2 px-8 py-3 bg-green-600 hover:bg-green-700 text-white font-bold rounded-full cursor-pointer shadow-md transition-all transform hover:scale-105"> |
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5"> |
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /> |
|
|
</svg> |
|
|
Choose File |
|
|
</label> |
|
|
|
|
|
<input id="cls-file" type="file" accept="image/*" class="hidden" onchange="onClsFileSelected()" /> |
|
|
<p id="cls-filename" class="text-gray-500 mt-3 text-xs italic"></p> |
|
|
</div> |
|
|
|
|
|
<div class="flex-1 flex flex-col justify-center gap-4 min-w-[250px] pl-12"> |
|
|
<div> |
|
|
<label class="block text-gray-700 font-bold mb-1 text-sm">Location of observation:</label> |
|
|
<input id="obs-location" type="text" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm text-gray-900 focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all focus:outline-none shadow-sm" placeholder="e.g. Aegean Sea" /> |
|
|
</div> |
|
|
<div> |
|
|
<label class="block text-gray-700 font-bold mb-1 text-sm">Potential species name:</label> |
|
|
<input id="obs-species" type="text" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm text-gray-900 focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all focus:outline-none shadow-sm" placeholder="e.g. Sparus aurata" /> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="w-full flex justify-center mt-6"> |
|
|
<button id="cls-run" onclick="runClassification()" style="display:none;" class="px-8 py-3 bg-green-600 text-white text-lg font-semibold rounded-full shadow-md hover:bg-green-700 transition"> |
|
|
▶️ Run Classification |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div id="cls-result" class="text-center text-gray-700 mt-6 text-lg font-medium w-full"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</section> |
|
|
</main> |
|
|
|
|
|
<script> |
|
|
let selectedModel = "dino"; |
|
|
|
|
|
function setModel(name) { |
|
|
selectedModel = name; |
|
|
|
|
|
|
|
|
document.getElementById("toggle-dino-vis")?.classList.toggle("active", name === "dino"); |
|
|
document.getElementById("toggle-yolo-vis")?.classList.toggle("active", name === "yolo"); |
|
|
|
|
|
|
|
|
document.getElementById("toggle-dino-cls")?.classList.toggle("active", name === "dino"); |
|
|
document.getElementById("toggle-yolo-cls")?.classList.toggle("active", name === "yolo"); |
|
|
|
|
|
console.log("MODEL SELECTED:", selectedModel); |
|
|
} |
|
|
|
|
|
let activeTool = "attention"; |
|
|
|
|
|
function showSubTool(name) { |
|
|
const subs = ["attention", "classification"]; |
|
|
subs.forEach(s => { |
|
|
document.getElementById("tool-" + s).classList.add("hidden"); |
|
|
document.getElementById("sub-" + s).classList.remove("text-indigo-600", "font-medium", "border-b-2", "border-indigo-600"); |
|
|
document.getElementById("sub-" + s).classList.add("text-gray-500"); |
|
|
}); |
|
|
document.getElementById("tool-" + name).classList.remove("hidden"); |
|
|
document.getElementById("sub-" + name).classList.add("text-indigo-600", "font-medium", "border-b-2", "border-indigo-600"); |
|
|
document.getElementById("sub-" + name).classList.remove("text-gray-500"); |
|
|
activeTool = name; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function onVisFileSelected() { |
|
|
const fileInput = document.getElementById("vis-file"); |
|
|
const nameEl = document.getElementById("vis-filename"); |
|
|
const runBtn = document.getElementById("vis-run"); |
|
|
const extra = document.getElementById("attention-extra"); |
|
|
const original = document.getElementById("original"); |
|
|
|
|
|
|
|
|
extra.classList.add("hidden"); |
|
|
|
|
|
if (fileInput.files.length > 0) { |
|
|
const file = fileInput.files[0]; |
|
|
nameEl.textContent = file.name; |
|
|
runBtn.style.display = "block"; |
|
|
|
|
|
|
|
|
const reader = new FileReader(); |
|
|
reader.onload = e => { |
|
|
original.src = e.target.result; |
|
|
original.classList.remove("hidden"); |
|
|
}; |
|
|
reader.readAsDataURL(file); |
|
|
} else { |
|
|
nameEl.textContent = ""; |
|
|
runBtn.style.display = "none"; |
|
|
} |
|
|
} |
|
|
|
|
|
async function runVisualization() { |
|
|
const file = document.getElementById("vis-file").files[0]; |
|
|
const output = document.getElementById("output"); |
|
|
const status = document.getElementById("status"); |
|
|
const headsContainer = document.getElementById("headsContainer"); |
|
|
const headsGrid = document.getElementById("headsGrid"); |
|
|
const btn = document.getElementById("vis-run"); |
|
|
const extra = document.getElementById("attention-extra"); |
|
|
|
|
|
if (!file) return alert("Please choose an image first!"); |
|
|
|
|
|
|
|
|
btn.disabled = true; |
|
|
btn.classList.add("opacity-80", "cursor-not-allowed"); |
|
|
|
|
|
btn.innerHTML = ` |
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> |
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> |
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> |
|
|
</svg> |
|
|
Processing... |
|
|
`; |
|
|
|
|
|
|
|
|
extra.classList.remove("hidden"); |
|
|
output.classList.add("hidden"); |
|
|
headsContainer.classList.add("hidden"); |
|
|
headsGrid.innerHTML = ""; |
|
|
status.textContent = "Running model inference..."; |
|
|
|
|
|
|
|
|
if (typeof gtag === 'function') { |
|
|
gtag('event', 'run_visualization', { 'event_category': 'Model', 'event_label': 'DINOv2_Hybrid' }); |
|
|
} |
|
|
|
|
|
const fd = new FormData(); |
|
|
fd.append("file", file); |
|
|
|
|
|
try { |
|
|
const res = await fetch("/attention", { method: "POST", body: fd }); |
|
|
const json = await res.json(); |
|
|
|
|
|
|
|
|
if (json.pca_image) { |
|
|
output.src = "data:image/png;base64," + json.pca_image; |
|
|
output.classList.remove("hidden"); |
|
|
} |
|
|
|
|
|
|
|
|
if (json.head_attention_maps) { |
|
|
json.head_attention_maps.forEach((b64, i) => { |
|
|
const img = document.createElement("img"); |
|
|
img.src = "data:image/png;base64," + b64; |
|
|
img.className = "rounded-md shadow-sm w-[120px] transition hover:scale-110"; |
|
|
img.title = `Head ${i+1}`; |
|
|
headsGrid.appendChild(img); |
|
|
}); |
|
|
headsContainer.classList.remove("hidden"); |
|
|
} |
|
|
|
|
|
status.textContent = "✅ Visualization Complete!"; |
|
|
|
|
|
} catch (err) { |
|
|
status.textContent = "❌ Error: " + err.message; |
|
|
} finally { |
|
|
|
|
|
btn.disabled = false; |
|
|
btn.innerHTML = "▶️ Run Visualization"; |
|
|
btn.classList.remove("opacity-80", "cursor-not-allowed"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function onClsFileSelected() { |
|
|
const fileInput = document.getElementById("cls-file"); |
|
|
const fileName = document.getElementById("cls-filename"); |
|
|
const runBtn = document.getElementById("cls-run"); |
|
|
|
|
|
|
|
|
document.getElementById("cls-result").innerHTML = ""; |
|
|
|
|
|
if (fileInput.files.length > 0) { |
|
|
fileName.textContent = fileInput.files[0].name; |
|
|
runBtn.style.display = "block"; |
|
|
} else { |
|
|
fileName.textContent = ""; |
|
|
runBtn.style.display = "none"; |
|
|
} |
|
|
} |
|
|
|
|
|
async function runClassification() { |
|
|
const file = document.getElementById("cls-file").files[0]; |
|
|
const result = document.getElementById("cls-result"); |
|
|
const btn = document.getElementById("cls-run"); |
|
|
|
|
|
if (!file) return alert("Please choose an image to classify!"); |
|
|
|
|
|
|
|
|
btn.disabled = true; |
|
|
btn.classList.add("opacity-80", "cursor-not-allowed"); |
|
|
btn.innerHTML = ` |
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> |
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> |
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> |
|
|
</svg> |
|
|
Processing... |
|
|
`; |
|
|
|
|
|
|
|
|
if (typeof gtag === 'function') { |
|
|
gtag('event', 'run_classification', { 'event_category': 'Model', 'event_label': selectedModel }); |
|
|
} |
|
|
|
|
|
const fd = new FormData(); |
|
|
fd.append("file", file); |
|
|
fd.append("model", selectedModel); |
|
|
|
|
|
try { |
|
|
const res = await fetch("/classify", { method: "POST", body: fd }); |
|
|
const json = await res.json(); |
|
|
|
|
|
result.innerHTML = ""; |
|
|
|
|
|
if (json.ood_metadata && json.ood_metadata.is_ood) { |
|
|
const warningHtml = ` |
|
|
<div class="bg-amber-50 border-l-4 border-amber-400 p-4 mb-4 mx-auto max-w-4xl rounded shadow-sm"> |
|
|
<div class="flex"> |
|
|
<div class="ml-3"> |
|
|
<p class="text-sm text-amber-700"> |
|
|
<strong>⚠️ Out-of-Distribution Warning:</strong> |
|
|
This image does not look like a known fish species from our database (OOD Score: ${json.ood_metadata.distance.toFixed(2)}). |
|
|
Results below may be inaccurate. |
|
|
(<a href="javascript:void(0)" onclick="showTab('research')" class="text-indigo-600 font-bold hover:underline">View supported species list</a>) |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
result.insertAdjacentHTML('afterbegin', warningHtml); |
|
|
} |
|
|
|
|
|
if (json.plot) { |
|
|
const plotImg = document.createElement("img"); |
|
|
plotImg.src = json.plot; |
|
|
plotImg.className = "block mx-auto mt-6 max-w-4xl rounded-lg shadow-md"; |
|
|
result.appendChild(plotImg); |
|
|
} else { |
|
|
result.textContent = "No predictions returned."; |
|
|
} |
|
|
|
|
|
|
|
|
if (json.top5 && json.top5.length > 0) { |
|
|
const topResult = json.top5[0]; |
|
|
const species = topResult.label; |
|
|
const confidence = (topResult.score * 100).toFixed(1); |
|
|
|
|
|
const shareUrl = "https://huggingface.co/spaces/AndrewKof/NEMOtools"; |
|
|
const shareText = `I just identified a ${species} with ${confidence}% confidence using NEMO-Tools! 🐟`; |
|
|
|
|
|
|
|
|
const twitterLink = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}&url=${encodeURIComponent(shareUrl)}&hashtags=MarineBiology,AI,NEMOTools`; |
|
|
const fbLink = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}"e=${encodeURIComponent(shareText)}`; |
|
|
const waLink = `https://api.whatsapp.com/send?text=${encodeURIComponent(shareText + " " + shareUrl)}`; |
|
|
const liLink = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`; |
|
|
|
|
|
|
|
|
const shareHtml = ` |
|
|
<div class="mt-8 flex flex-col items-center w-full"> |
|
|
<p class="text-sm text-gray-500 mb-4 font-medium uppercase tracking-wide">Share your discovery</p> |
|
|
|
|
|
<div class="flex flex-wrap justify-center gap-3 w-full max-w-2xl"> |
|
|
|
|
|
<a href="${twitterLink}" target="_blank" rel="noopener noreferrer" class="flex items-center justify-center gap-2 w-12 h-12 bg-black text-white rounded-full hover:bg-gray-800 transition shadow-sm hover:-translate-y-1 hover:shadow-md" title="Share on X"> |
|
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg> |
|
|
</a> |
|
|
|
|
|
<a href="${fbLink}" target="_blank" rel="noopener noreferrer" class="flex items-center justify-center gap-2 w-12 h-12 bg-[#1877F2] text-white rounded-full hover:bg-blue-700 transition shadow-sm hover:-translate-y-1 hover:shadow-md" title="Share on Facebook"> |
|
|
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"><path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036c-2.648 0-2.928 1.67-2.928 4.353v1.618h2.391l-.928 3.667h-1.463v7.98H9.101Z"/></svg> |
|
|
</a> |
|
|
|
|
|
<a href="${waLink}" target="_blank" rel="noopener noreferrer" class="flex items-center justify-center gap-2 w-12 h-12 bg-[#25D366] text-white rounded-full hover:bg-green-600 transition shadow-sm hover:-translate-y-1 hover:shadow-md" title="Share on WhatsApp"> |
|
|
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/></svg> |
|
|
</a> |
|
|
|
|
|
<a href="${liLink}" target="_blank" rel="noopener noreferrer" class="flex items-center justify-center gap-2 w-12 h-12 bg-[#0077B5] text-white rounded-full hover:bg-blue-800 transition shadow-sm hover:-translate-y-1 hover:shadow-md" title="Share on LinkedIn"> |
|
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg> |
|
|
</a> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
result.insertAdjacentHTML('beforeend', shareHtml); |
|
|
} |
|
|
|
|
|
} catch (err) { |
|
|
result.textContent = "❌ Error: " + err.message; |
|
|
} finally { |
|
|
btn.disabled = false; |
|
|
btn.innerHTML = "▶️ Run Classification"; |
|
|
btn.classList.remove("opacity-80", "cursor-not-allowed"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function copyToClipboard(text) { |
|
|
navigator.clipboard.writeText(text).then(() => { |
|
|
alert("Link copied! You can now open Instagram and paste it in a Story or Message."); |
|
|
window.open("https://instagram.com", "_blank"); |
|
|
}, (err) => { |
|
|
console.error('Could not copy text: ', err); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function runActiveTool() { |
|
|
if (activeTool === "attention") await runVisualization(); |
|
|
else await runClassification(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function showTab(tabName) { |
|
|
|
|
|
['tools', 'research', 'people'].forEach(page => { |
|
|
const el = document.getElementById('page-' + page); |
|
|
if(el) el.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
|
|
|
const selected = document.getElementById('page-' + tabName); |
|
|
if(selected) selected.classList.remove('hidden'); |
|
|
|
|
|
|
|
|
const allButtons = document.querySelectorAll('.tab-btn'); |
|
|
allButtons.forEach(btn => { |
|
|
|
|
|
btn.classList.remove('bg-indigo-600', 'text-white', 'shadow-md'); |
|
|
|
|
|
|
|
|
btn.classList.add('text-slate-600', 'hover:bg-white/80', 'hover:text-indigo-700'); |
|
|
}); |
|
|
|
|
|
|
|
|
const activeBtn = document.getElementById('tab-' + tabName); |
|
|
if(activeBtn) { |
|
|
|
|
|
activeBtn.classList.remove('text-slate-600', 'hover:bg-white/80', 'hover:text-indigo-700'); |
|
|
|
|
|
|
|
|
activeBtn.classList.add('bg-indigo-600', 'text-white', 'shadow-md'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
showSubTool("classification"); |
|
|
</script> |
|
|
|
|
|
<footer class="bg-slate-900 border-t border-slate-800 mt-20 pb-12 text-white"> |
|
|
<div class="max-w-7xl mx-auto px-6 pt-16"> |
|
|
|
|
|
<div class="text-center mb-10"> |
|
|
<h3 class="text-sm font-bold tracking-[0.2em] text-slate-400 uppercase"> |
|
|
Supported By |
|
|
</h3> |
|
|
<div class="w-16 h-1 bg-indigo-500 mx-auto mt-4 rounded-full shadow-lg shadow-indigo-500/50"></div> |
|
|
</div> |
|
|
|
|
|
<div class="bg-white rounded-3xl p-10 shadow-2xl mx-auto max-w-6xl"> |
|
|
<div class="flex flex-wrap justify-center items-center gap-x-16 gap-y-12"> |
|
|
|
|
|
<a href="https://www.iacm.forth.gr/" target="_blank" rel="noopener noreferrer"> |
|
|
<img src="/static/logos/forth.png" alt="IACM-FORTH" class="h-24 md:h-32 w-auto object-contain transition-transform duration-300 hover:scale-110 cursor-pointer"> |
|
|
</a> |
|
|
|
|
|
<a href="https://www.aegean.gr/" target="_blank" rel="noopener noreferrer"> |
|
|
<img src="/static/logos/aegean.png" alt="University of the Aegean" class="h-24 md:h-32 w-auto object-contain transition-transform duration-300 hover:scale-110 cursor-pointer"> |
|
|
</a> |
|
|
|
|
|
<a href="https://www.elidek.gr/en/homepage/" target="_blank" rel="noopener noreferrer"> |
|
|
<img src="/static/logos/hfri.png" alt="HFRI" class="h-24 md:h-32 w-auto object-contain transition-transform duration-300 hover:scale-110 cursor-pointer"> |
|
|
</a> |
|
|
|
|
|
<a href="https://www.uoc.gr/en/home/" target="_blank" rel="noopener noreferrer"> |
|
|
<img src="/static/logos/uoc.png" alt="University of Crete" class="h-24 md:h-32 w-auto object-contain transition-transform duration-300 hover:scale-110 cursor-pointer"> |
|
|
</a> |
|
|
|
|
|
<a href="https://www.auth.gr/en/" target="_blank" rel="noopener noreferrer"> |
|
|
<img src="/static/logos/auth.png" alt="Aristotle University of Thessaloniki" class="h-12 md:h-14 w-auto object-contain transition-transform duration-300 hover:scale-110 cursor-pointer"> |
|
|
</a> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-16 text-center border-t border-slate-800 pt-8"> |
|
|
<p class="text-slate-500 text-sm"> |
|
|
© 2025 NEMO-Tools. Mediterranean Fish Species Classification. All rights reserved. |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</footer> |
|
|
|
|
|
</body> |
|
|
</html> |