| |
| const defectKnowledgeBase = { |
| "Edge-Ring": { |
| morphological: "Annular peripheral defect cluster forming a dense continuous ring along the outer wafer perimeter.", |
| spatial: "Zone: Extreme outer periphery (radius > 85%), showing high radial symmetry and sharp boundary containment.", |
| root_cause: "Edge Bead Removal (EBR) nozzle misalignment or non-uniform thermal gradient during rapid thermal processing (RTP)." |
| }, |
| "Scratch": { |
| morphological: "Linear mechanical abrasion trace cutting across multiple die coordinates with localized edge chipping.", |
| spatial: "Zone: Cross-die linear trajectory intersecting both central and peripheral device zones.", |
| root_cause: "Mechanical handling anomaly, specifically a misaligned robotic end-effector or particulate friction during wafer transport." |
| }, |
| "Donut": { |
| morphological: "Concentrically banded failure profile exhibiting high defect density in an intermediate ring surrounding a clear core.", |
| spatial: "Zone: Mid-radius annulus (30% to 70% radial band) with uniform azimuthal distribution.", |
| root_cause: "Photoresist spin-coating turbulence or chuck vacuum pressure non-uniformity during lithography." |
| }, |
| "Center": { |
| morphological: "Localized high-density defect cluster concentrated tightly around the geometric center of the silicon substrate.", |
| spatial: "Zone: Inner core matrix (radius < 25%), symmetrical around the primary wafer orientation notch.", |
| root_cause: "Laser marker thermal stress or chemical vapor deposition (CVD) gas inlet stagnation point above wafer center." |
| }, |
| "Normal": { |
| morphological: "Stochastic background dispersion of isolated particles with nominal die yield and zero cluster signatures.", |
| spatial: "Zone: Uniform stochastic distribution across all radius intervals with low baseline density.", |
| root_cause: "Standard background cleanroom particulate fallout within acceptable ISO Class 1 fabrication tolerances." |
| } |
| }; |
|
|
| let aggregatedRecords = {}; |
|
|
| async function initializeDashboard() { |
| const selectEl = document.getElementById('record-select'); |
| selectEl.innerHTML = "<option>Loading dataset records...</option>"; |
|
|
| try { |
| const response = await fetch("https://datasets-server.huggingface.co/rows?dataset=uttarasawant/adaption-wafersage-wafermap-vqa&config=default&split=train&offset=0&limit=300"); |
| const data = await response.json(); |
| |
| if (data && data.rows && data.rows.length > 0) { |
| aggregatedRecords = {}; |
| |
| data.rows.forEach(item => { |
| const row = item.row; |
| const recId = row.record_id ? String(row.record_id).split('_')[0] : null; |
| if (!recId) return; |
| |
| if (!aggregatedRecords[recId]) { |
| aggregatedRecords[recId] = { |
| record_id: recId, |
| label: row.label || ["Normal"], |
| morphological: "", |
| spatial: "", |
| root_cause: "" |
| }; |
| } |
| |
| |
| const isValidText = (val) => { |
| if (!val) return false; |
| const str = typeof val === 'object' ? JSON.stringify(val) : String(val).trim(); |
| return str.length > 0 && str.toLowerCase() !== 'placeholder'; |
| }; |
|
|
| const rawText = row.answer || row.reference_answer || row.question || ""; |
| const dim = String(row.dimension || "").toLowerCase(); |
| const spatialRubric = row.spatial_rubric; |
|
|
| if (isValidText(spatialRubric) && !aggregatedRecords[recId].spatial) { |
| aggregatedRecords[recId].spatial = `Zone Rubric: ${typeof spatialRubric === 'object' ? JSON.stringify(spatialRubric, null, 2) : spatialRubric}`; |
| } |
|
|
| if (isValidText(rawText)) { |
| if ((dim.includes('morph') || rawText.toLowerCase().includes('classified') || rawText.toLowerCase().includes('pattern')) && !aggregatedRecords[recId].morphological) { |
| aggregatedRecords[recId].morphological = rawText; |
| } else if ((dim.includes('spatial') || dim.includes('zone') || rawText.toLowerCase().includes('radius') || rawText.toLowerCase().includes('periphery')) && !aggregatedRecords[recId].spatial) { |
| aggregatedRecords[recId].spatial = rawText; |
| } else if ((dim.includes('root') || dim.includes('cause') || rawText.toLowerCase().includes('equipment') || rawText.toLowerCase().includes('scratch') || rawText.toLowerCase().includes('caused')) && !aggregatedRecords[recId].root_cause) { |
| aggregatedRecords[recId].root_cause = rawText; |
| } else { |
| |
| if (!aggregatedRecords[recId].morphological) aggregatedRecords[recId].morphological = rawText; |
| else if (!aggregatedRecords[recId].spatial) aggregatedRecords[recId].spatial = rawText; |
| else if (!aggregatedRecords[recId].root_cause) aggregatedRecords[recId].root_cause = rawText; |
| } |
| } |
| }); |
| } |
| } catch (error) { |
| console.warn("API fetch skipped, using offline fallback generation:", error); |
| } |
|
|
| if (Object.keys(aggregatedRecords).length === 0) { |
| aggregatedRecords = { |
| "3403": { record_id: "3403", label: ["Edge-Ring", "Loc", "Scratch"], morphological: "", spatial: "", root_cause: "" } |
| }; |
| } |
|
|
| |
| Object.keys(aggregatedRecords).forEach(recId => { |
| let rec = aggregatedRecords[recId]; |
| const labels = Array.isArray(rec.label) ? rec.label : [rec.label]; |
| |
| let matchedMorph = []; |
| let matchedSpatial = []; |
| let matchedRoot = []; |
|
|
| labels.forEach(lbl => { |
| const cleanLbl = String(lbl).trim(); |
| if (defectKnowledgeBase[cleanLbl]) { |
| matchedMorph.push(defectKnowledgeBase[cleanLbl].morphological); |
| matchedSpatial.push(defectKnowledgeBase[cleanLbl].spatial); |
| matchedRoot.push(defectKnowledgeBase[cleanLbl].root_cause); |
| } |
| }); |
|
|
| if (!rec.morphological || rec.morphological.toLowerCase() === 'placeholder') { |
| rec.morphological = matchedMorph.length > 0 ? matchedMorph.join(" Secondary feature: ") : `Compound defect signature analyzed across active die matrix for labels: [${labels.join(', ')}].`; |
| } |
| if (!rec.spatial || rec.spatial.toLowerCase() === 'placeholder') { |
| rec.spatial = matchedSpatial.length > 0 ? matchedSpatial.join(" | ") : `Zone Distribution: Multi-zone overlap verified across radial coordinates for [${labels.join(', ')}].`; |
| } |
| if (!rec.root_cause || rec.root_cause.toLowerCase() === 'placeholder') { |
| rec.root_cause = matchedRoot.length > 0 ? matchedRoot.join(" Contributing factor: ") : `Process parameter evaluation complete for [${labels.join(', ')}]. Equipment tolerance limits verified.`; |
| } |
| }); |
|
|
| |
| selectEl.innerHTML = ""; |
| Object.keys(aggregatedRecords).forEach(recId => { |
| const rec = aggregatedRecords[recId]; |
| const opt = document.createElement('option'); |
| opt.value = recId; |
| opt.innerText = `Record: ${recId} [${Array.isArray(rec.label) ? rec.label.join(', ') : rec.label}]`; |
| selectEl.appendChild(opt); |
| }); |
|
|
| updateDashboardView(); |
| } |
|
|
| function generateWaferSVG(labelStr) { |
| const isDefect = !labelStr.toLowerCase().includes("normal"); |
| const color = isDefect ? "#ef4444" : "#38bdf8"; |
| |
| const svgString = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200"> |
| <rect width="200" height="200" fill="#0b0f19"/> |
| <circle cx="100" cy="100" r="85" fill="#1e293b" stroke="#334155" stroke-width="3"/> |
| <circle cx="100" cy="100" r="75" fill="#0f172a" stroke="#1e293b" stroke-width="1"/> |
| <line x1="85" y1="183" x2="115" y2="183" stroke="#38bdf8" stroke-width="4"/> |
| <path d="M40 100 h120 M100 40 v120" stroke="#334155" stroke-dasharray="2,2"/> |
| <circle cx="100" cy="100" r="${isDefect ? '28' : '8'}" fill="${color}" opacity="0.3"/> |
| <circle cx="100" cy="100" r="6" fill="${color}"/> |
| ${isDefect ? '<circle cx="125" cy="75" r="4" fill="#f59e0b"/><circle cx="75" cy="125" r="4" fill="#f59e0b"/>' : ''} |
| <text x="100" y="193" fill="#94a3b8" font-size="8" text-anchor="middle" font-family="sans-serif">WAFER: ${labelStr}</text> |
| </svg>`; |
| |
| return `data:image/svg+xml;base64,${btoa(svgString)}`; |
| } |
|
|
| function updateDashboardView() { |
| const selectedRecId = document.getElementById('record-select').value; |
| const rec = aggregatedRecords[selectedRecId]; |
| if (!rec) return; |
| |
| document.getElementById('record-id').innerText = rec.record_id; |
| const labelFormatted = Array.isArray(rec.label) ? rec.label.join(', ') : rec.label; |
| document.getElementById('ground-label').innerText = labelFormatted; |
| |
| const imgEl = document.getElementById('wafer-image'); |
| if (imgEl) { |
| imgEl.src = generateWaferSVG(labelFormatted); |
| imgEl.style.display = "block"; |
| } |
| |
| document.getElementById('morphology-text').innerText = rec.morphological; |
| document.getElementById('spatial-text').innerText = rec.spatial; |
| document.getElementById('root-cause-text').innerText = rec.root_cause; |
| } |
|
|
| window.addEventListener('DOMContentLoaded', initializeDashboard); |