'use strict';
SM.injectLayout('nav-upload');
const uploadZone = document.getElementById('uploadZone');
const csvInput = document.getElementById('csvInput');
let selectedFiles = [];
// ── Drag & Drop ──
uploadZone.addEventListener('dragover', e => { e.preventDefault(); uploadZone.classList.add('drag'); });
uploadZone.addEventListener('dragleave', () => uploadZone.classList.remove('drag'));
uploadZone.addEventListener('drop', e => {
e.preventDefault(); uploadZone.classList.remove('drag');
const allFiles = Array.from(e.dataTransfer.files);
if (!allFiles.length) return;
const files = allFiles.filter(f => f.name.endsWith('.csv'));
if (files.length) {
showFilePreview(files);
} else {
SM.showModal({ title: 'Format Tidak Sesuai', message: 'Hanya menerima file .csv', type: 'error' });
}
});
uploadZone.addEventListener('click', e => {
if (e.target.tagName === 'BUTTON') return;
csvInput.click();
});
csvInput.addEventListener('change', e => {
const allFiles = Array.from(e.target.files);
if (!allFiles.length) return;
const files = allFiles.filter(f => f.name.endsWith('.csv'));
if (files.length) {
showFilePreview(files);
} else {
SM.showModal({ title: 'Format Tidak Sesuai', message: 'Hanya menerima file dataset dalam format .csv.', type: 'error' });
}
});
function showFilePreview(files) {
selectedFiles = files;
const totalSize = files.reduce((acc, f) => acc + f.size, 0);
if (files.length === 1) {
window._uploadedFilename = files[0].name;
document.getElementById('fileName').textContent = files[0].name;
} else {
window._uploadedFilename = `${files.length}_File_CSV_Gabungan.csv`;
document.getElementById('fileName').textContent = `${files.length} File CSV Terpilih`;
}
document.getElementById('filePreview').style.display = 'flex';
document.getElementById('fileMeta').textContent = `${(totalSize/1024).toFixed(1)} KB`;
}
document.getElementById('btnCancel').addEventListener('click', () => {
selectedFiles = [];
csvInput.value = '';
document.getElementById('filePreview').style.display = 'none';
});
document.getElementById('btnAnalyze').addEventListener('click', async () => {
if (!selectedFiles || selectedFiles.length === 0) return;
document.getElementById('filePreview').style.display = 'none';
document.getElementById('progressWrap').style.display = 'block';
const steps = ['Membaca file...','Parsing CSV...','Menjalankan Text Cleaning...',
'Tokenisasi IndoBERT...','Klasifikasi Sentimen...','Menyimpan Hasil...','Selesai!'];
let combinedText = '';
for (let i = 0; i < selectedFiles.length; i++) {
let t = await selectedFiles[i].text();
// Untuk file kedua dan seterusnya, hapus baris pertama (header csv) agar tidak ikut terproses
if (i > 0) {
const firstNewline = t.indexOf('\\n');
if (firstNewline !== -1) t = t.substring(firstNewline + 1);
}
// Gabungkan text, pastikan dipisah enter
combinedText += t + (t.endsWith('\\n') ? '' : '\\n');
}
const text = combinedText;
// Update progress UI step
document.getElementById('progressStep').textContent = steps[0];
// Run in next tick so UI updates first
await new Promise(r => setTimeout(r, 30));
let stepIdx = 0;
function progress(done, total) {
const pct = Math.round((done/total)*100);
document.getElementById('progressBar').style.width = pct + '%';
document.getElementById('progressPct').textContent = pct + '%';
const si = Math.min(Math.floor((pct/100)*steps.length), steps.length-1);
if (si !== stepIdx) { stepIdx = si; document.getElementById('progressStep').textContent = steps[si]; }
}
try {
// processCSV is now async — calls IndoBERT API in batches
const result = await SM.processCSV(text, progress);
if (!result || !result.rows || !result.rows.length) {
SM.showModal({
title: 'Dataset Kosong',
message: 'Tidak ada data teks yang ditemukan dalam file CSV tersebut.',
type: 'error'
});
document.getElementById('progressWrap').style.display = 'none';
document.getElementById('filePreview').style.display = 'flex';
return;
}
const { rows, meta } = result;
// Animate to 100%
document.getElementById('progressBar').style.width = '100%';
document.getElementById('progressPct').textContent = '100%';
document.getElementById('progressStep').textContent = 'Selesai! Menyiapkan dashboard...';
SM.saveData(rows, meta);
// Show center success modal
setTimeout(() => {
SM.showModal({
title: 'Analisis Selesai',
message: `
Berhasil memproses ${SM.fmt(rows.length)} teks dengan model machine learning IndoBERT. Hasil analisis telah siap untuk ditinjau.
Peringatan Penting: Seluruh data sentimen dan riwayat file CSV Anda disimpan secara permanen di memori lokal (Local Storage) peramban web ini untuk menjamin privasi. Tolong jangan menghapus riwayat peramban atau Cache / Clear Data, karena akan menyebabkan semua data di Riwayat Analisis hilang secara permanen.
`,
type: 'success',
onConfirm: () => { window.location.href = 'dashboard'; }
});
}, 400);
} catch (err) {
// Show error popup when IndoBERT model / API fails
document.getElementById('progressWrap').style.display = 'none';
document.getElementById('filePreview').style.display = 'flex';
// Reset progress bar
document.getElementById('progressBar').style.width = '0%';
document.getElementById('progressPct').textContent = '0%';
document.getElementById('progressStep').textContent = '';
SM.showModal({
title: 'Gagal Memproses Sentimen',
message: `
Model IndoBERT tidak dapat diakses.
${SM.esc(err.message || 'Terjadi kesalahan yang tidak diketahui.')}
Solusi:
1. Pastikan server Python sudah berjalan (python app.py)
2. Pastikan model IndoBERT sudah terunduh dengan benar
3. Pastikan dependensi Python sudah terinstall (pip install -r requirements.txt)
`,
type: 'error'
});
}
});
// ── Demo Data Trigger ──
const btnDemo = document.getElementById('btnDemoData');
if (btnDemo) {
btnDemo.addEventListener('click', async () => {
if (typeof window.DEMO_CSV === 'undefined') {
SM.showToast('Data demo tidak tersedia.', 'error');
return;
}
// Set demo filename for meta
window._uploadedFilename = 'demo_300_tweets.csv';
document.getElementById('filePreview').style.display = 'none';
document.getElementById('progressWrap').style.display = 'block';
const steps = ['Membaca data demo...', 'Parsing CSV...', 'Menjalankan Text Cleaning...',
'Tokenisasi IndoBERT...', 'Klasifikasi Sentimen...', 'Menyimpan Hasil...', 'Selesai!'];
document.getElementById('progressStep').textContent = steps[0];
async function progress(done, total) {
const pct = Math.round((done / total) * 100);
document.getElementById('progressBar').style.width = pct + '%';
document.getElementById('progressPct').textContent = pct + '%';
const si = Math.min(Math.floor((pct / 100) * steps.length), steps.length - 1);
document.getElementById('progressStep').textContent = steps[si];
}
try {
const result = await SM.processCSV(window.DEMO_CSV, progress);
const { rows, meta } = result;
document.getElementById('progressBar').style.width = '100%';
document.getElementById('progressPct').textContent = '100%';
document.getElementById('progressStep').textContent = 'Selesai! Menyiapkan dashboard...';
SM.saveData(rows, meta);
setTimeout(() => {
SM.showModal({
title: 'Demo Selesai',
message: `Berhasil memproses ${rows.length} tweet demo dengan model IndoBERT. Lihat hasilnya di dashboard!`,
type: 'success',
onConfirm: () => { window.location.href = 'dashboard'; }
});
}, 400);
} catch (err) {
SM.showToast('Gagal memproses demo: ' + err.message, 'error');
document.getElementById('progressWrap').style.display = 'none';
}
});
}