const state = { activeId: null, fields: {}, specs: {} }; const elements = { tabs: document.querySelectorAll('.tab-btn'), fieldsContainer: document.getElementById('fields-container'), inferenceForm: document.getElementById('inference-form'), resultDisplay: document.getElementById('result-display'), infoTrigger: document.querySelector('.info-trigger'), modal: document.getElementById('modal-overlay'), modalClose: document.getElementById('modal-close'), specsContent: document.getElementById('specs-content'), modalTitle: document.getElementById('modal-title'), btnAutofill: document.getElementById('btn-autofill') }; async function autofill() { elements.btnAutofill.disabled = true; const btnText = elements.btnAutofill.querySelector('.btn-text'); const originalText = btnText.innerText; btnText.innerText = 'Extracting...'; try { const res = await fetch(`/api/sample/${state.activeId}`); const data = await res.json(); Object.entries(data).forEach(([key, val]) => { const input = elements.inferenceForm.querySelector(`[name="${key}"]`); if (input) { input.value = val; input.style.borderColor = 'var(--secondary)'; input.style.boxShadow = '0 0 15px rgba(0, 210, 255, 0.3)'; setTimeout(() => { input.style.borderColor = ''; input.style.boxShadow = ''; }, 1500); } }); } catch (e) { console.error(e); } finally { elements.btnAutofill.disabled = false; btnText.innerText = originalText; } } elements.btnAutofill.onclick = autofill; async function loadTab(id) { if (state.activeId === id) return; state.activeId = id; elements.tabs.forEach(btn => btn.classList.toggle('active', btn.dataset.id === id)); elements.fieldsContainer.style.opacity = '0'; elements.fieldsContainer.style.transform = 'translateY(10px)'; try { const [fields, info] = await Promise.all([ fetch(`/api/fields/${id}`).then(r => r.json()), fetch(`/api/info/${id}`).then(r => r.json()) ]); state.fields[id] = fields; state.specs[id] = info; renderFields(fields); elements.resultDisplay.innerHTML = `

System Initialized. Awaiting Input Data.

`; } catch (e) { elements.fieldsContainer.innerHTML = `

System Error: ${e.message}

`; } finally { setTimeout(() => { elements.fieldsContainer.style.opacity = '1'; elements.fieldsContainer.style.transform = 'translateY(0)'; elements.fieldsContainer.style.transition = 'all 0.5s cubic-bezier(0.2, 0.8, 0.2, 1)'; }, 50); } } function renderFields(fields) { elements.fieldsContainer.innerHTML = fields.map((f, i) => `
${f.type === 'select' ? ` ` : ` `}
`).join(''); } elements.inferenceForm.onsubmit = async (e) => { e.preventDefault(); const formData = new FormData(elements.inferenceForm); const payload = { features: {} }; let hasEmpty = false; formData.forEach((v, k) => { if (v === "") hasEmpty = true; payload.features[k] = v; }); if (hasEmpty) { alert("Please complete all parameters before execution."); return; } const btn = document.querySelector('.btn-primary'); const btnText = btn.querySelector('.btn-text'); const originalText = btnText.innerText; btn.disabled = true; btnText.innerText = 'Calculating...'; elements.resultDisplay.scrollIntoView({ behavior: 'smooth', block: 'center' }); try { const res = await fetch(`/api/run/${state.activeId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await res.json(); if (!res.ok) throw new Error(data.detail || 'Inference engine failure'); renderResult(data); } catch (e) { elements.resultDisplay.innerHTML = `

Execution Error: ${e.message}

`; } finally { btn.disabled = false; btnText.innerText = originalText; } }; function renderResult(data) { const scores = Object.entries(data.scores).sort((a, b) => b[1] - a[1]); const shap = Object.entries(data.shap || {}); const maxShap = Math.max(...shap.map(s => Math.abs(s[1])), 0.001); elements.resultDisplay.innerHTML = `
Prediction Output
${data.result}
Probability Vectors ${scores.map(([label, score]) => `
${label}
${(score * 100).toFixed(1)}%
`).join('')}
SHAP Decision Drivers ${shap.map(([feat, val]) => `
${feat}
${val >= 0 ? '+' : ''}${val.toFixed(2)}
`).join('')}
`; setTimeout(() => { const fills = elements.resultDisplay.querySelectorAll('.bar-fill'); scores.forEach((s, i) => fills[i].style.width = `${s[1] * 100}%`); const shapBars = elements.resultDisplay.querySelectorAll('.shap-bar'); shap.forEach((s, i) => { const width = (Math.abs(s[1]) / maxShap) * 50; // Max 50% from center shapBars[i].style.width = `${width}%`; }); }, 100); } elements.infoTrigger.onclick = () => { const info = state.specs[state.activeId]; if (!info) return; elements.modalTitle.innerText = `${info.title} Architecture`; elements.specsContent.innerHTML = `

Volume

${info.dataset.rows.toLocaleString()}

Dimensions

${info.dataset.cols}

Model Type

${info.model.type || 'Ensemble'}

Target

${info.dataset.target}

${info.metrics.length ? Object.keys(info.metrics[0]).map(k => ``).join('') : ''} ${info.metrics.map(m => ` ${Object.values(m).map(v => ``).join('')} `).join('')}
${k}
${typeof v === 'number' ? v.toFixed(4) : v}
Explore Kaggle Dataset `; elements.modal.classList.remove('hidden'); document.body.style.overflow = 'hidden'; }; elements.modalClose.onclick = () => { elements.modal.classList.add('hidden'); document.body.style.overflow = 'auto'; }; window.onclick = (e) => { if (e.target === elements.modal) { elements.modal.classList.add('hidden'); document.body.style.overflow = 'auto'; } }; elements.tabs.forEach(btn => btn.onclick = () => { loadTab(btn.dataset.id); btn.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }); }); const initialId = elements.tabs[0]?.dataset.id; if (initialId) loadTab(initialId);