Spaces:
Running
Running
| import Papa from "papaparse"; | |
| export async function loadStackOverflowCSV(path, fetchOptions = {}) { | |
| const url = path + (path.includes("?") ? "&" : "?") + "t=" + Date.now(); | |
| const res = await fetch(url, fetchOptions); | |
| if (!res.ok) | |
| throw new Error(`Failed to load CSV: ${res.status} ${res.statusText}`); | |
| const text = await res.text(); | |
| const { data } = Papa.parse(text, { | |
| header: true, | |
| skipEmptyLines: true, | |
| transformHeader: (header) => header.trim(), | |
| }); | |
| return { rows: data.map(normalizeRow) }; | |
| } | |
| function normalizeRow(r) { | |
| const clone = { ...r }; | |
| // Normalize numeric fields for Stack Overflow data | |
| clone.Age = safeNumber(r.Age); | |
| clone.YearsCode = safeNumber(r.YearsCode); | |
| clone.YearsCodePro = safeNumber(r.YearsCodePro); | |
| clone.ConvertedCompYearly = safeNumber(r.ConvertedCompYearly); | |
| clone.WorkWeekHrs = safeNumber(r.WorkWeekHrs); | |
| clone.CompTotal = safeNumber(r.CompTotal); | |
| // Keep string fields as is | |
| clone.Country = r.Country || ""; | |
| clone.Gender = r.Gender || ""; | |
| clone.EdLevel = r.EdLevel || ""; | |
| clone.DevType = r.DevType || ""; | |
| clone.RemoteWork = r.RemoteWork || ""; | |
| clone.JobSat = r.JobSat || ""; | |
| clone.LanguageHaveWorkedWith = r.LanguageHaveWorkedWith || ""; | |
| clone.LanguageWantToWorkWith = r.LanguageWantToWorkWith || ""; | |
| clone.DatabaseHaveWorkedWith = r.DatabaseHaveWorkedWith || ""; | |
| clone.DatabaseWantToWorkWith = r.DatabaseWantToWorkWith || ""; | |
| clone.PlatformHaveWorkedWith = r.PlatformHaveWorkedWith || ""; | |
| clone.PlatformWantToWorkWith = r.PlatformWantToWorkWith || ""; | |
| clone.OrgSize = r.OrgSize || ""; | |
| clone.LearnCode = r.LearnCode || ""; | |
| clone.AISelect = r.AISelect || ""; | |
| clone.AIAccompany = r.AIAccompany || ""; | |
| clone.AIWantToWorkWith = r.AIWantToWorkWith || ""; | |
| return clone; | |
| } | |
| function safeNumber(v) { | |
| if (v === null || v === undefined || v === "") return 0; | |
| const cleaned = String(v).replace(/,/g, "").replace(/\s+/g, "").trim(); | |
| // Handle K for thousands | |
| if (cleaned.endsWith("K")) { | |
| const num = parseFloat(cleaned.slice(0, -1)); | |
| return Number.isFinite(num) ? num * 1000 : 0; | |
| } | |
| const n = Number(cleaned); | |
| return Number.isFinite(n) ? n : 0; | |
| } | |