fix people

This commit is contained in:
2026-07-19 13:37:51 -05:00
parent 068debee16
commit 20960f97c0
3 changed files with 184 additions and 15 deletions

View File

@@ -51,6 +51,19 @@ const esc = (value) =>
"'": "'",
})[char]);
// Normalized person key from the vision-extracted buyer name: lowercase,
// punctuation stripped, name tokens sorted so "Zahoor Bilal" and
// "Bilal Zahoor" compare equal.
function personKey(group) {
const name = group.docs.map((d) => d.prospective_buyer).find((v) =>
typeof v === "string" && v.trim()
);
if (!name) return null;
const tokens = name.toLocaleLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ")
.trim().split(/\s+/).filter(Boolean).sort();
return tokens.length ? tokens.join(" ") : null;
}
function buildGroups(docs) {
const map = new Map();
docs.forEach((doc, index) => {
@@ -71,7 +84,33 @@ function buildGroups(docs) {
].filter(Boolean).join(" ");
map.set(key, group);
});
return [...map.values()].sort((a, b) => a.key.localeCompare(b.key));
// Second pass: merge filename-based groups that refer to the same person
// according to the extracted prospective_buyer. This catches typos in the
// scan filenames (e.g. "Zaboor, Bilal" vs "Zahoor, Bilal") which would
// otherwise show the same buyer twice. Groups without a prospective_buyer
// are never merged.
const byPerson = new Map();
const merged = [];
for (const group of map.values()) {
const pKey = personKey(group);
const target = pKey ? byPerson.get(pKey) : undefined;
if (target) {
target.docs.push(...group.docs);
target.text += " " + group.text;
continue;
}
if (pKey) byPerson.set(pKey, group);
merged.push(group);
}
for (const group of merged) {
group.docs.sort((a, b) => a.file_name.localeCompare(b.file_name));
const preferred = group.docs.find((d) =>
typeof d.prospective_buyer === "string" && d.prospective_buyer.trim()
);
if (preferred) group.displayName = preferred.prospective_buyer;
}
return merged.sort((a, b) => a.key.localeCompare(b.key));
}
function visibleGroups() {
@@ -298,4 +337,26 @@ async function load() {
}
}
void load();
void load();
// ---- Window size reporting ----
// The backend's native size APIs are unreliable (see main.ts), so the
// webview reports its own viewport size. The first report, sent shortly
// after startup, calibrates the decoration offset on the backend; later
// reports track user resizes.
let metricsTimer = null;
function reportWindowMetrics() {
fetch("/api/window-metrics", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
innerWidth: globalThis.innerWidth,
innerHeight: globalThis.innerHeight,
}),
}).catch(() => {});
}
globalThis.addEventListener("resize", () => {
clearTimeout(metricsTimer);
metricsTimer = setTimeout(reportWindowMetrics, 250);
});
setTimeout(reportWindowMetrics, 800); // calibration report