Spaces:
Running
Running
File size: 8,753 Bytes
04b72bb 3cc3895 04b72bb 3cc3895 04b72bb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | '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 <strong>.csv</strong>.', 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 <strong>${SM.fmt(rows.length)}</strong> teks dengan model machine learning IndoBERT. Hasil analisis telah siap untuk ditinjau.
<br><br>
<span style="font-size:13.5px;color:var(--tx2);display:block;background:var(--bg-card2);padding:16px;border-radius:12px;text-align:left;line-height:1.5;">
<strong>Peringatan Penting:</strong> Seluruh data sentimen dan riwayat file CSV Anda disimpan secara permanen di memori lokal (<em>Local Storage</em>) peramban web ini untuk menjamin privasi. <strong>Tolong jangan menghapus riwayat peramban atau <em>Cache / Clear Data</em></strong>, karena akan menyebabkan semua data di Riwayat Analisis hilang secara permanen.
</span>
`,
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: `
<strong>Model IndoBERT tidak dapat diakses.</strong><br><br>
${SM.esc(err.message || 'Terjadi kesalahan yang tidak diketahui.')}
<br><br>
<span style="font-size:13px;color:var(--tx2);display:block;background:var(--bg-card2);padding:14px;border-radius:10px;text-align:left;line-height:1.5;">
<strong>Solusi:</strong><br>
1. Pastikan server Python sudah berjalan (<code>python app.py</code>)<br>
2. Pastikan model IndoBERT sudah terunduh dengan benar<br>
3. Pastikan dependensi Python sudah terinstall (<code>pip install -r requirements.txt</code>)
</span>
`,
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 <strong>${rows.length}</strong> 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';
}
});
}
|