import { pipeline } from '@huggingface/transformers'; const MODEL_ID = 'lucianfialho/atos-de-fala-ptbr'; const EXAMPLE = 'Bom dia! Você pode revisar o relatório? Obrigado.'; const $ = (id) => document.getElementById(id); const input = $('text-input'); const btn = $('classify-btn'); const status = $('status'); const output = $('output'); const jsonOut = $('json-out'); const dtypeSelect = $('dtype'); const deviceSelect = $('device'); const progress = document.createElement('div'); progress.id = 'progress'; input.parentElement.appendChild(progress); let clf = null; let loadedConfig = null; // { dtype, device } do modelo carregado input.value = EXAMPLE; document.querySelectorAll('.example').forEach((b) => { b.addEventListener('click', () => { input.value = b.dataset.text; input.focus(); }); }); // troca de config invalida o modelo em cache function invalidate() { if (clf) { clf = null; loadedConfig = null; setStatus('', ''); } } dtypeSelect.addEventListener('change', invalidate); deviceSelect.addEventListener('change', invalidate); btn.addEventListener('click', run); function currentConfig() { return { dtype: dtypeSelect.value, device: deviceSelect.value }; } async function ensureModel() { const cfg = currentConfig(); if (clf && loadedConfig && loadedConfig.dtype === cfg.dtype && loadedConfig.device === cfg.device) { return clf; } setStatus('loading', `Baixando (${cfg.dtype}, ${cfg.device})…`); clf = await pipeline('token-classification', MODEL_ID, { dtype: cfg.dtype, device: cfg.device, progress_callback: (p) => { if (p.status === 'progress') { const f = p.file?.split('/').pop() ?? '?'; progress.textContent = `${f}: ${Math.round(p.progress ?? 0)}%`; } else if (p.status === 'done') { progress.textContent = ''; } }, }); loadedConfig = cfg; setStatus('done', 'Pronto'); return clf; } function setStatus(state, msg) { status.className = 'status ' + state; status.textContent = msg; } function render(atos) { if (!atos.length) { output.innerHTML = '

Nenhum ato detectado.

'; jsonOut.textContent = '[]'; return; } const chips = atos.map((a) => `
${escapeHtml(a.word)} ${a.entity_group} ${a.score.toFixed(2)}
`).join(''); output.innerHTML = `
${chips}
`; jsonOut.textContent = JSON.stringify(atos, null, 2); } function escapeHtml(s) { return s.replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); } async function run() { const text = input.value.trim(); if (!text) return; btn.disabled = true; try { const cfg = currentConfig(); setStatus('loading', `Carregando modelo (${cfg.dtype}/${cfg.device})…`); await ensureModel(); setStatus('loading', 'Classificando…'); const t0 = performance.now(); const atos = await clf(text, { aggregation_strategy: 'simple' }); const dt = performance.now() - t0; render(atos); setStatus('done', `${atos.length} ato(s) · ${dt.toFixed(0)} ms · ${cfg.dtype}/${cfg.device}`); } catch (e) { console.error(e); setStatus('error', e?.message ?? String(e)); } finally { btn.disabled = false; } }