LLaVA-PLLuM / static /js /index.js
WojciechKusa's picture
feat: add blogpost
6ba6082 verified
$(document).ready(function () {
var options = {
slidesToScroll: 1,
slidesToShow: 3,
loop: true,
infinite: true,
autoplay: false,
autoplaySpeed: 3000,
};
// Initialize all div with carousel class
var carousels = bulmaCarousel.attach('.carousel', options);
// Loop on each carousel initialized
for (var i = 0; i < carousels.length; i++) {
// Add listener to event
carousels[i].on('before:show', (state) => {
console.log(state);
});
}
// Access to bulmaCarousel instance of an element
var element = document.querySelector('#my-element');
if (element && element.bulmaCarousel) {
// bulmaCarousel instance is available as element.bulmaCarousel
element.bulmaCarousel.on('before-show', function (state) {
console.log(state);
});
}
$.getJSON('./static/data/examples.json', function (examplesData) {
const container = document.getElementById('qualitative-results-container');
if (container) {
// Event delegation for toggle buttons
container.addEventListener('click', function (e) {
const btn = e.target.closest('.toggle-comparison-btn');
if (!btn) return;
const targetId = btn.dataset.target;
const content = document.getElementById(targetId);
if (content) {
// Use jQuery for smooth slide toggle
$(content).slideToggle(300);
const isCurrentlyVisible = $(content).is(':visible');
// If it is currently visible, it will be hidden, so we want "Show..."
// If it is currently hidden, it will be shown, so we want "Hide..."
const willBeVisible = !isCurrentlyVisible;
const textSpan = btn.querySelector('span:first-child');
if (textSpan) {
textSpan.textContent = willBeVisible ? 'Hide comparison' : 'Show comparison with other models';
}
const iconSpan = btn.querySelector('.icon');
if (iconSpan) {
iconSpan.style.transition = 'transform 0.3s';
iconSpan.style.transform = willBeVisible ? 'rotate(180deg)' : 'rotate(0deg)';
}
}
});
examplesData.forEach((example, index) => {
const othersId = `others-${index}`;
const othersHtml = example.others
.map((other) => {
const icon = other.status === 'success' ? 'check' : other.status === 'danger' ? 'x' : 'triangle-alert';
const iconClass =
other.status === 'success'
? 'has-text-success'
: other.status === 'danger'
? 'has-text-danger'
: 'has-text-warning';
const note = other.note ? `<br/><small>${other.note}</small>` : '';
return `
<div class="notification is-${other.status} is-light">
<span class="tag is-${other.status}">${other.model}</span>
<div class="is-flex is-align-items-center mt-1">
<span class="mr-2">"${other.text}"${note}</span>
<i data-lucide="${icon}" class="${iconClass}" style="flex-shrink: 0;"></i>
</div>
</div>
`;
})
.join('');
const html = `
<div class="box">
<div class="columns is-vcentered">
<div class="column is-two-fifths">
<figure class="image">
<img src="${example.image}" alt="${example.alt}" />
</figure>
<figcaption style="font-size: 0.875rem; color: gray; font-style: italic; text-align: center;">
${example.source}
</figcaption>
</div>
<div class="column">
<div class="notification is-info is-light">
<span class="tag is-info">Question</span>
<p>${example.question}</p>
</div>
<div class="notification is-${example.ours.status} is-light">
<span class="tag is-${example.ours.status}">LLaVA-PLLuM-12B-nc (Ours)</span>
<div class="is-flex is-align-items-center mt-1">
<span class="mr-2">"${example.ours.text}"</span>
<i data-lucide="check" class="has-text-${example.ours.status}" style="flex-shrink: 0;"></i>
</div>
</div>
<button class="button is-small is-ghost mt-2 toggle-comparison-btn" data-target="${othersId}">
<span>Show comparison with other models</span>
<span class="icon">
<i data-lucide="chevron-down"></i>
</span>
</button>
<div id="${othersId}" class="mt-4" style="display: none;">
${othersHtml}
</div>
</div>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
});
}
lucide.createIcons();
});
// Scroll to top button logic
const scrollToTopBtn = document.getElementById('scrollToTopBtn');
const rootElement = document.documentElement;
function handleScroll() {
const scrollTotal = rootElement.scrollHeight - rootElement.clientHeight;
if (rootElement.scrollTop / scrollTotal > 0.1) {
// Show button
scrollToTopBtn.style.display = 'block';
} else {
// Hide button
scrollToTopBtn.style.display = 'none';
}
}
function scrollToTop() {
rootElement.scrollTo({
top: 0,
behavior: 'smooth',
});
}
if (scrollToTopBtn) {
scrollToTopBtn.addEventListener('click', scrollToTop);
document.addEventListener('scroll', handleScroll);
}
// Smooth scrolling for TOC links
document.querySelectorAll('.menu-list a[href^="#"]').forEach((anchor) => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
targetSection.scrollIntoView({
behavior: 'smooth',
});
}
});
});
// ScrollSpy for TOC
window.addEventListener('scroll', function () {
const fromTop = window.scrollY + 150;
let currentSectionId = '';
document.querySelectorAll('.menu-list a[href^="#"]').forEach((link) => {
const targetId = link.getAttribute('href');
if (targetId === '#') return;
const section = document.querySelector(targetId);
if (section) {
if (section.offsetTop <= fromTop) {
currentSectionId = targetId;
}
}
});
document.querySelectorAll('.menu-list a').forEach((link) => {
link.classList.remove('is-active');
if (link.getAttribute('href') === currentSectionId) {
link.classList.add('is-active');
}
});
});
// Chart.js initialization for Training Data Distribution
const chartCtx = document.getElementById('trainingDataChart');
if (chartCtx) {
new Chart(chartCtx, {
type: 'doughnut',
data: {
datasets: [
{
// Outer Ring: Datasets
data: [454000, 150000, 145000, 142000, 15000, 390000, 500000, 100000, 104000],
backgroundColor: [
'#62bdfc', // ALLaVA
'#85cffa', // LLaVA-Instruct
'#a8e1ff', // Q-Instruct
'#cbf2ff', // LVIS-Instruct4V
'#e6f9ff', // A-OKVQA
'#6bf295', // WIT (Green)
'#ff7592', // SynthDoG-PL
'#ffb3c4', // SynthDoG-EN
'#ffe58f', // TallyQA (Yellow)
],
labels: [
'ALLaVA',
'LLaVA-Instruct',
'Q-Instruct',
'LVIS-Instruct4V',
'A-OKVQA',
'WIT',
'SynthDoG-PL',
'SynthDoG-EN',
'TallyQA',
],
borderWidth: 0,
},
{
// Inner Ring: Categories
data: [906000, 390000, 600000, 104000],
backgroundColor: [
'#209cee', // General
'#23d160', // Knowledge (Green)
'#ff3860', // OCR
'#ffdd57', // Counting (Yellow)
],
labels: ['General', 'Knowledge', 'OCR', 'Counting'],
borderWidth: 0,
},
],
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 2.75,
events: [], // Disable all interactions
plugins: {
legend: {
position: 'right',
align: 'center',
onClick: null, // Disable legend click
labels: {
usePointStyle: true,
padding: 15,
generateLabels: function (chart) {
const data = chart.data;
const datasets = data.datasets[0]; // Outer ring (datasets)
let legendItems = [];
// Define the structure: Category Name -> Dataset Indices
const structure = [
{ category: 'General', indices: [0, 1, 2, 3, 4] },
{ category: 'Knowledge', indices: [5] },
{ category: 'OCR', indices: [6, 7] },
{ category: 'Counting', indices: [8] },
];
structure.forEach((group, groupIndex) => {
// Add Category Header
legendItems.push({
text: group.category,
fillStyle: 'rgba(0,0,0,0)',
strokeStyle: 'rgba(0,0,0,0)',
lineWidth: 0,
hidden: false,
index: -1,
fontColor: '#363636',
});
// Add Datasets for this category
group.indices.forEach((index) => {
const value = datasets.data[index];
const valueK = Math.round(value / 1000) + 'K';
const label = `${datasets.labels[index]} (${valueK})`;
legendItems.push({
text: label,
fillStyle: datasets.backgroundColor[index],
strokeStyle: datasets.backgroundColor[index],
hidden: false,
index: index,
datasetIndex: 0,
pointStyle: 'circle',
});
});
});
return legendItems;
},
},
},
tooltip: {
enabled: false,
},
},
animation: false,
},
});
}
});