Spaces:
Runtime error
Runtime error
| const elements = { | |
| scanButton: document.getElementById("scan-button"), | |
| clearButton: document.getElementById("clear-button"), | |
| status: document.getElementById("status"), | |
| summary: document.getElementById("summary"), | |
| scannedCount: document.getElementById("scanned-count"), | |
| flaggedCount: document.getElementById("flagged-count"), | |
| minimumScore: document.getElementById("minimum-score"), | |
| pageLabel: document.getElementById("page-label"), | |
| results: document.getElementById("results"), | |
| apiUrl: document.getElementById("api-url"), | |
| minimumScoreInput: document.getElementById("minimum-score-input"), | |
| maxItems: document.getElementById("max-items"), | |
| saveSettings: document.getElementById("save-settings"), | |
| testConnection: document.getElementById("test-connection"), | |
| }; | |
| function setStatus(message, tone = "neutral") { | |
| elements.status.textContent = message; | |
| elements.status.dataset.tone = tone; | |
| } | |
| function setBusy(busy) { | |
| elements.scanButton.disabled = busy; | |
| elements.clearButton.disabled = busy; | |
| elements.scanButton.textContent = busy ? "Scanning page..." : "Scan current page"; | |
| } | |
| function sendMessage(message) { | |
| return chrome.runtime.sendMessage(message); | |
| } | |
| function createFinding(result) { | |
| const card = document.createElement("article"); | |
| card.className = "finding"; | |
| card.dataset.severity = result.severity || "medium"; | |
| const header = document.createElement("div"); | |
| header.className = "finding-header"; | |
| const type = document.createElement("span"); | |
| type.className = "finding-type"; | |
| type.textContent = result.prediction; | |
| const score = document.createElement("span"); | |
| score.className = "score"; | |
| score.textContent = `${result.confidence}% ${result.confidenceBand}`; | |
| header.append(type, score); | |
| const evidence = document.createElement("p"); | |
| evidence.className = "evidence"; | |
| evidence.textContent = result.text; | |
| const phrases = document.createElement("div"); | |
| phrases.className = "phrases"; | |
| const phraseText = (result.explanation || []) | |
| .map((item) => item.phrase) | |
| .join(", "); | |
| phrases.textContent = phraseText | |
| ? `Trigger phrases: ${phraseText}` | |
| : "No stable word-level explanation available."; | |
| const locate = document.createElement("button"); | |
| locate.className = "locate"; | |
| locate.textContent = "Locate on page"; | |
| locate.addEventListener("click", async () => { | |
| const response = await sendMessage({ | |
| type: "FOCUS_RESULT", | |
| elementId: result.id, | |
| }); | |
| if (!response?.ok) { | |
| setStatus(response?.error || "Could not locate the element.", "error"); | |
| } | |
| }); | |
| card.append(header, evidence, phrases, locate); | |
| return card; | |
| } | |
| function renderScan(response) { | |
| elements.summary.hidden = false; | |
| elements.scannedCount.textContent = response.scanned; | |
| elements.flaggedCount.textContent = response.flagged; | |
| elements.minimumScore.textContent = `${response.minimumScore || 0}%`; | |
| elements.pageLabel.textContent = response.page?.title || ""; | |
| elements.results.replaceChildren(); | |
| if (!response.results?.length) { | |
| const empty = document.createElement("p"); | |
| empty.className = "empty"; | |
| empty.textContent = "No visible text exceeded the current review threshold."; | |
| elements.results.appendChild(empty); | |
| return; | |
| } | |
| for (const result of response.results) { | |
| elements.results.appendChild(createFinding(result)); | |
| } | |
| } | |
| async function runScan() { | |
| setBusy(true); | |
| setStatus("Collecting visible interface text and running the NLP model..."); | |
| try { | |
| const response = await sendMessage({ type: "RUN_SCAN" }); | |
| if (!response?.ok) { | |
| throw new Error(response?.error || "Scan failed."); | |
| } | |
| renderScan(response); | |
| setStatus( | |
| `Audit complete. ${response.flagged} of ${response.scanned} texts require review.`, | |
| "success", | |
| ); | |
| } catch (error) { | |
| setStatus(error.message, "error"); | |
| } finally { | |
| setBusy(false); | |
| } | |
| } | |
| async function clearHighlights() { | |
| const response = await sendMessage({ type: "CLEAR_HIGHLIGHTS" }); | |
| if (!response?.ok) { | |
| setStatus(response?.error || "Could not clear highlights.", "error"); | |
| return; | |
| } | |
| setStatus("Page highlights cleared.", "success"); | |
| } | |
| async function loadSettings() { | |
| const response = await sendMessage({ type: "GET_SETTINGS" }); | |
| if (!response?.ok) { | |
| setStatus(response?.error || "Could not load settings.", "error"); | |
| return; | |
| } | |
| elements.apiUrl.value = response.apiUrl; | |
| elements.minimumScoreInput.value = response.minimumScore; | |
| elements.maxItems.value = response.maxItems; | |
| } | |
| async function saveSettings() { | |
| const response = await sendMessage({ | |
| type: "SAVE_SETTINGS", | |
| settings: { | |
| apiUrl: elements.apiUrl.value, | |
| minimumScore: elements.minimumScoreInput.value, | |
| maxItems: elements.maxItems.value, | |
| }, | |
| }); | |
| if (!response?.ok) { | |
| setStatus(response?.error || "Could not save settings.", "error"); | |
| return; | |
| } | |
| setStatus("Settings saved.", "success"); | |
| } | |
| async function testConnection() { | |
| setStatus("Testing local API connection..."); | |
| const response = await sendMessage({ type: "TEST_CONNECTION" }); | |
| if (!response?.ok) { | |
| setStatus(response?.error || "API connection failed.", "error"); | |
| return; | |
| } | |
| setStatus("Local NLP API is ready and calibrated.", "success"); | |
| } | |
| elements.scanButton.addEventListener("click", runScan); | |
| elements.clearButton.addEventListener("click", clearHighlights); | |
| elements.saveSettings.addEventListener("click", saveSettings); | |
| elements.testConnection.addEventListener("click", testConnection); | |
| loadSettings(); | |