Store selected picture candidates in scrape DB
This commit is contained in:
+145
-6
@@ -928,23 +928,74 @@ function renderSourceCandidates(items) {
|
||||
|
||||
function renderPictureCandidates(items) {
|
||||
const rows = [];
|
||||
let position = 0;
|
||||
for (const item of items) {
|
||||
for (const candidate of item.candidates || []) {
|
||||
for (const picture of candidate.pictures || []) {
|
||||
const row = document.createElement("a");
|
||||
position += 1;
|
||||
const target = buildPictureTargetInfo();
|
||||
const row = document.createElement("div");
|
||||
row.className = "picture-candidate";
|
||||
row.href = picture;
|
||||
row.target = "_blank";
|
||||
row.rel = "noreferrer";
|
||||
|
||||
const preview = document.createElement("a");
|
||||
preview.href = picture;
|
||||
preview.target = "_blank";
|
||||
preview.rel = "noreferrer";
|
||||
preview.className = "picture-candidate-preview";
|
||||
|
||||
const image = document.createElement("img");
|
||||
image.src = picture;
|
||||
image.alt = candidate.rawTitle || item.source?.name || "Product picture";
|
||||
image.loading = "lazy";
|
||||
preview.append(image);
|
||||
|
||||
const details = document.createElement("div");
|
||||
details.className = "picture-candidate-meta";
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.textContent = item.source?.name || item.source?.key || "Source";
|
||||
row.append(image, label);
|
||||
label.className = "picture-candidate-title";
|
||||
label.textContent = `${item.source?.name || item.source?.key || "Source"} picture #${position}`;
|
||||
|
||||
const dimensions = document.createElement("span");
|
||||
dimensions.className = "picture-candidate-dimensions";
|
||||
dimensions.textContent = "Size: loading...";
|
||||
image.addEventListener("load", () => {
|
||||
dimensions.textContent = image.naturalWidth && image.naturalHeight
|
||||
? `Size: ${image.naturalWidth} x ${image.naturalHeight}px`
|
||||
: "Size: unknown";
|
||||
});
|
||||
image.addEventListener("error", () => {
|
||||
dimensions.textContent = "Size: image preview failed";
|
||||
});
|
||||
|
||||
const assignment = document.createElement("span");
|
||||
assignment.className = "picture-candidate-target";
|
||||
assignment.textContent = target.label;
|
||||
|
||||
const duplicateHint = document.createElement("span");
|
||||
duplicateHint.className = "picture-candidate-duplicate";
|
||||
duplicateHint.textContent = "DB: not saved";
|
||||
|
||||
details.append(label, dimensions, assignment, duplicateHint);
|
||||
|
||||
const action = document.createElement("button");
|
||||
action.type = "button";
|
||||
action.className = "source-picture-action picture-candidate-save";
|
||||
action.textContent = "Save to DB";
|
||||
action.addEventListener("click", () =>
|
||||
savePictureCandidateToDb({
|
||||
picture,
|
||||
item,
|
||||
candidate,
|
||||
image,
|
||||
position,
|
||||
target,
|
||||
action,
|
||||
duplicateHint,
|
||||
}),
|
||||
);
|
||||
|
||||
row.append(preview, details, action);
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
@@ -960,6 +1011,94 @@ function renderPictureCandidates(items) {
|
||||
sourceList.replaceChildren(...rows);
|
||||
}
|
||||
|
||||
function buildPictureTargetInfo() {
|
||||
const supplierColorGroup = getFirstSupplierColorGroup();
|
||||
const firstSupplierRow = supplierColorGroup?.supplierRows?.[0] || currentCombinations[0] || {};
|
||||
const color = supplierColorGroup?.color || formatValue(firstSupplierRow.color);
|
||||
const ean13 = supplierColorGroup?.supplierEan || firstSupplierRow.ean13 || "";
|
||||
|
||||
if (color) {
|
||||
return {
|
||||
strategy: "color",
|
||||
color,
|
||||
sizeValue: "",
|
||||
combi: "",
|
||||
ean13,
|
||||
idProductCatalog: firstSupplierRow.idProductCatalog || currentProduct?.idProductCatalog || "",
|
||||
label: `Target: color ${color}${ean13 ? ` / EAN ${ean13}` : ""}`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
strategy: "unknown",
|
||||
color: "",
|
||||
sizeValue: "",
|
||||
combi: "",
|
||||
ean13,
|
||||
idProductCatalog: firstSupplierRow.idProductCatalog || currentProduct?.idProductCatalog || "",
|
||||
label: ean13 ? `Target: unknown / EAN ${ean13}` : "Target: needs manual assignment",
|
||||
};
|
||||
}
|
||||
|
||||
async function savePictureCandidateToDb({
|
||||
picture,
|
||||
item,
|
||||
candidate,
|
||||
image,
|
||||
position,
|
||||
target,
|
||||
action,
|
||||
duplicateHint,
|
||||
}) {
|
||||
action.disabled = true;
|
||||
action.textContent = "Saving...";
|
||||
duplicateHint.textContent = "DB: saving...";
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
sourceKey: item.source?.key || "",
|
||||
sourceName: item.source?.name || "",
|
||||
sourceType: item.source?.type || "",
|
||||
imageUrl: picture,
|
||||
pageUrl: candidate.url || item.searchUrl || "",
|
||||
sourcePosition: position,
|
||||
manufacturerId: manufacturerSelect.value,
|
||||
idProductCatalog: currentProduct?.idProductCatalog || target.idProductCatalog || "",
|
||||
idProduct: currentProduct?.idProduct || "",
|
||||
supplierReference: currentProduct?.supplierReference || "",
|
||||
ean13: target.ean13 || "",
|
||||
color: target.color || "",
|
||||
sizeValue: target.sizeValue || "",
|
||||
combi: target.combi || "",
|
||||
targetStrategy: target.strategy,
|
||||
targetColor: target.color || "",
|
||||
targetSize: target.sizeValue || "",
|
||||
targetCombi: target.combi || "",
|
||||
targetEan13: target.ean13 || "",
|
||||
targetIdProductCatalog: target.idProductCatalog || currentProduct?.idProductCatalog || "",
|
||||
matchConfidence: target.strategy === "color" ? 70 : 0,
|
||||
width: image.naturalWidth || "",
|
||||
height: image.naturalHeight || "",
|
||||
};
|
||||
const response = await fetch("/api/catalog-maker/save-picture", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.message || "Picture save failed.");
|
||||
|
||||
action.textContent = "Saved";
|
||||
duplicateHint.textContent = data.duplicateStatus === "exact_duplicate"
|
||||
? `DB: duplicate of #${data.duplicateOfCandidateId || "known"}`
|
||||
: `DB: saved #${data.candidateId}`;
|
||||
} catch (error) {
|
||||
action.disabled = false;
|
||||
action.textContent = "Save to DB";
|
||||
duplicateHint.textContent = `DB: ${error.message || "save failed"}`;
|
||||
}
|
||||
}
|
||||
|
||||
function collectPictureUrls(items) {
|
||||
return items.flatMap((item) =>
|
||||
(item.candidates || []).flatMap((candidate) => candidate.pictures || []),
|
||||
|
||||
Reference in New Issue
Block a user