bindDatasetEvents function domain
Last updated: 2026-03-04T23:21:38.430Z
Metrics
LOC: 254
Complexity: 39
Params: 0
Signature
bindDatasetEvents(): : void
Architecture violations
- [warning] max-cyclomatic-complexity: 'bindDatasetEvents' has cyclomatic complexity 39 (max 10)
- [warning] max-lines: 'bindDatasetEvents' has 254 lines (max 80)
Source Code
function bindDatasetEvents(): void {
// Filter
document.getElementById("dataset-filter")?.addEventListener("input", (e) => {
const val = (e.target as HTMLInputElement).value.trim();
void loadDatasetList(val);
});
// Add entry
document
.getElementById("btn-add-dataset-entry")
?.addEventListener("click", async () => {
const signals = (
document.getElementById("dataset-signals") as HTMLInputElement
).value.trim();
const type = (datasetTypeSelect?.getValue() ?? "") as FieldType;
const difficulty = (
document.getElementById("dataset-difficulty") as HTMLSelectElement
).value as "easy" | "medium" | "hard";
if (!signals) {
showToast(t("toastSignalsRequired"), "error");
return;
}
const entry = (await chrome.runtime.sendMessage({
type: "ADD_DATASET_ENTRY",
payload: { signals, type, source: "manual", difficulty },
})) as DatasetEntry | { error: string };
if ("error" in entry) {
showToast(entry.error, "error");
return;
}
const existingIdx = _allDatasetEntries.findIndex(
(e) => e.id === entry.id,
);
if (existingIdx >= 0) {
_allDatasetEntries[existingIdx] = entry;
} else {
_allDatasetEntries.unshift(entry);
}
await loadDatasetList();
(document.getElementById("dataset-signals") as HTMLInputElement).value =
"";
showToast(t("toastDatasetEntryAdded"));
});
// Seed built-in
document
.getElementById("btn-seed-dataset")
?.addEventListener("click", async () => {
const btn = document.getElementById(
"btn-seed-dataset",
) as HTMLButtonElement;
btn.disabled = true;
btn.textContent = t("importingText");
try {
const result = await seedBuiltinDataset();
const fresh = (await chrome.runtime.sendMessage({
type: "GET_DATASET",
})) as DatasetEntry[];
_allDatasetEntries = Array.isArray(fresh) ? fresh : [];
await loadDatasetList();
if (result.added > 0) {
showToast(t("seedAdded", [String(result.added)]));
} else {
showToast(t("toastDatasetAlreadyFull"));
}
} finally {
btn.disabled = false;
btn.textContent = t("btnSeedDataset");
}
});
// Export JSON
document
.getElementById("btn-export-dataset")
?.addEventListener("click", async () => {
const entries = (await chrome.runtime.sendMessage({
type: "EXPORT_DATASET",
})) as DatasetEntry[];
const json = JSON.stringify(entries, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "fill-all-dataset.json";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showToast(t("toastDatasetExported", [String(entries.length)]));
});
// Import JSON (file picker)
document
.getElementById("btn-import-dataset")
?.addEventListener("click", () => {
document.getElementById("dataset-import-file")?.click();
});
document
.getElementById("dataset-import-file")
?.addEventListener("change", async (e) => {
const input = e.target as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;
try {
const text = await file.text();
const parsed = JSON.parse(text) as unknown;
if (!Array.isArray(parsed))
throw new Error("O arquivo deve ser um array JSON");
const result = (await chrome.runtime.sendMessage({
type: "IMPORT_DATASET",
payload: parsed,
})) as { success: boolean; added: number; error?: string };
if (!result.success) throw new Error(result.error ?? "unknown error");
const fresh = (await chrome.runtime.sendMessage({
type: "GET_DATASET",
})) as DatasetEntry[];
_allDatasetEntries = Array.isArray(fresh) ? fresh : [];
await loadDatasetList();
showToast(t("toastDatasetImported", [String(result.added)]));
} catch (err) {
showToast(
t("errorImportDataset", [
err instanceof Error ? err.message : String(err),
]),
"error",
);
}
input.value = "";
});
// Clear dataset
document
.getElementById("btn-clear-dataset")
?.addEventListener("click", async () => {
if (!confirm(t("confirmClearDataset"))) return;
await chrome.runtime.sendMessage({ type: "CLEAR_DATASET" });
_allDatasetEntries = [];
await loadDatasetList();
showToast(t("toastDatasetCleared"));
});
// Delete runtime model
document
.getElementById("btn-delete-model")
?.addEventListener("click", async () => {
if (!confirm(t("confirmDeleteModel"))) return;
await chrome.runtime.sendMessage({ type: "DELETE_RUNTIME_MODEL" });
await loadModelStatus();
showToast(t("toastModelRemoved"));
});
// Train model
document
.getElementById("btn-train-model")
?.addEventListener("click", async () => {
const trainBtn = document.getElementById(
"btn-train-model",
) as HTMLButtonElement;
const progressBlock = document.getElementById("training-progress-block");
const progressBar = document.getElementById("training-progress-bar");
const progressLabel = document.getElementById("training-progress-label");
const trainingLog = document.getElementById(
"training-log",
) as HTMLPreElement | null;
const entries = (await chrome.runtime.sendMessage({
type: "GET_DATASET",
})) as DatasetEntry[];
if (!Array.isArray(entries) || entries.length < 10) {
showToast(t("errorDatasetTooSmall", [String(entries.length)]), "error");
return;
}
const distinctTypes = new Set(entries.map((e) => e.type)).size;
if (distinctTypes < 2) {
showToast(t("errorDatasetFewTypes", [String(distinctTypes)]), "error");
return;
}
trainBtn.disabled = true;
trainBtn.textContent = t("trainingText");
if (progressBlock) progressBlock.style.display = "block";
if (progressBar) progressBar.style.width = "0%";
if (progressLabel) progressLabel.textContent = "Iniciando...";
if (trainingLog)
trainingLog.textContent = `Iniciando treinamento com ${entries.length} amostras...\n`;
const onProgress = (p: TrainingProgress) => {
const pct = Math.round((p.epoch / p.totalEpochs) * 100);
if (progressBar) progressBar.style.width = `${pct}%`;
if (progressLabel) {
progressLabel.textContent = `Epoch ${p.epoch} / ${p.totalEpochs} — Loss: ${p.loss.toFixed(4)} — Accuracy: ${(p.accuracy * 100).toFixed(1)}%`;
}
if (trainingLog) {
trainingLog.textContent += `Epoch ${String(p.epoch).padStart(3)} | loss: ${p.loss.toFixed(4)} | acc: ${(p.accuracy * 100).toFixed(2)}%\n`;
trainingLog.scrollTop = trainingLog.scrollHeight;
}
};
try {
const result: TrainingResult = await trainModelFromDataset(
entries,
onProgress,
);
if (result.success) {
if (progressBar) progressBar.style.width = "100%";
if (progressLabel)
progressLabel.textContent = "Treinamento concluído!";
if (trainingLog) {
trainingLog.textContent += `\n✅ Concluído em ${result.durationMs}ms\n`;
trainingLog.textContent += ` Épocas: ${result.epochs} | Acurácia: ${(result.finalAccuracy * 100).toFixed(2)}% | Vocab: ${result.vocabSize}\n`;
trainingLog.textContent += ` Modelo salvo no storage — ativo na próxima página preenchida.\n`;
}
const tabs = await chrome.tabs.query({});
await Promise.allSettled(
tabs.map((t) =>
t.id
? chrome.tabs
.sendMessage(t.id, { type: "RELOAD_CLASSIFIER" })
.catch(() => {})
: Promise.resolve(),
),
);
await loadModelStatus();
showToast(
t("toastModelTrained", [(result.finalAccuracy * 100).toFixed(1)]),
);
} else {
if (trainingLog)
trainingLog.textContent += `\n\u274C Error: ${result.error}\n`;
showToast(t("toastTrainingError", [result.error ?? ""]), "error");
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
if (trainingLog)
trainingLog.textContent += `\n\u274C Exception: ${msg}\n`;
showToast(t("toastError", [msg]), "error");
} finally {
trainBtn.disabled = false;
trainBtn.textContent = t("btnTrainModel");
}
});
}
Dependencies (Outgoing)
| Target | Type |
|---|---|
| loadDatasetList | calls |
| seedBuiltinDataset | calls |
| loadModelStatus | calls |
| input | dynamic_call |
| click | dynamic_call |
| change | dynamic_call |
Impact (Incoming)
| Source | Type |
|---|---|
| initDatasetTab | calls |