147 lines
4.9 KiB
TypeScript
147 lines
4.9 KiB
TypeScript
export type DetailReplacementGenerationInputRole =
|
|
| "product"
|
|
| "model"
|
|
| "supplement"
|
|
| "layout";
|
|
|
|
export function selectDetailReplacementGenerationInputs(params: {
|
|
productImageUrls: string[];
|
|
modelImageUrl?: string | null;
|
|
includeModelImage?: boolean;
|
|
templateReferenceImageUrls?: string[];
|
|
rerunReferenceImageUrls?: string[];
|
|
referenceImageUrl: string;
|
|
maxImages?: number;
|
|
}) {
|
|
const normalizeUrls = (values: Array<string | null | undefined>) =>
|
|
Array.from(
|
|
new Set(
|
|
values
|
|
.map((value) => String(value || "").trim())
|
|
.filter((value) => /^https?:\/\//i.test(value)),
|
|
),
|
|
);
|
|
const referenceImageUrl = String(params.referenceImageUrl || "").trim();
|
|
const productImageUrls = normalizeUrls(params.productImageUrls).filter(
|
|
(url) => url !== referenceImageUrl,
|
|
);
|
|
const modelImageUrl = params.includeModelImage
|
|
? normalizeUrls([params.modelImageUrl]).find((url) => url !== referenceImageUrl) || null
|
|
: null;
|
|
const rerunReferenceImageUrls = normalizeUrls(
|
|
params.rerunReferenceImageUrls || [],
|
|
).filter((url) => url !== referenceImageUrl);
|
|
const templateReferenceImageUrls = normalizeUrls(
|
|
params.templateReferenceImageUrls || [],
|
|
).filter((url) => url !== referenceImageUrl);
|
|
const maxImages = Math.max(2, Math.floor(params.maxImages || 3));
|
|
const contentCapacity = maxImages - 1;
|
|
const selectedProductImageUrls: string[] = [];
|
|
const selectedTemplateImageUrls: string[] = [];
|
|
const selectedRerunImageUrls: string[] = [];
|
|
let selectedModelImageUrl: string | null = null;
|
|
|
|
if (productImageUrls[0]) selectedProductImageUrls.push(productImageUrls[0]);
|
|
if (modelImageUrl && selectedProductImageUrls.length < contentCapacity) {
|
|
selectedModelImageUrl = modelImageUrl;
|
|
}
|
|
|
|
const usedCount = () =>
|
|
selectedProductImageUrls.length +
|
|
selectedTemplateImageUrls.length +
|
|
selectedRerunImageUrls.length +
|
|
(selectedModelImageUrl ? 1 : 0);
|
|
const addSupplement = (url: string | undefined, kind: "template" | "rerun") => {
|
|
if (!url || usedCount() >= contentCapacity) return;
|
|
const selectedSupplementImageUrls = [
|
|
...selectedTemplateImageUrls,
|
|
...selectedRerunImageUrls,
|
|
];
|
|
if (
|
|
selectedProductImageUrls.includes(url) ||
|
|
selectedSupplementImageUrls.includes(url) ||
|
|
selectedModelImageUrl === url
|
|
) {
|
|
return;
|
|
}
|
|
if (kind === "template") selectedTemplateImageUrls.push(url);
|
|
else selectedRerunImageUrls.push(url);
|
|
};
|
|
|
|
if (!selectedModelImageUrl) {
|
|
addSupplement(rerunReferenceImageUrls[0], "rerun");
|
|
if (usedCount() < contentCapacity && productImageUrls[1]) {
|
|
selectedProductImageUrls.push(productImageUrls[1]);
|
|
}
|
|
addSupplement(templateReferenceImageUrls[0], "template");
|
|
} else if (selectedProductImageUrls.length === 0) {
|
|
addSupplement(rerunReferenceImageUrls[0], "rerun");
|
|
addSupplement(templateReferenceImageUrls[0], "template");
|
|
}
|
|
|
|
while (usedCount() < contentCapacity) {
|
|
const nextProduct = productImageUrls.find(
|
|
(url) => !selectedProductImageUrls.includes(url),
|
|
);
|
|
if (nextProduct) {
|
|
selectedProductImageUrls.push(nextProduct);
|
|
continue;
|
|
}
|
|
const nextRerun = rerunReferenceImageUrls.find(
|
|
(url) =>
|
|
!selectedRerunImageUrls.includes(url) &&
|
|
!selectedTemplateImageUrls.includes(url) &&
|
|
!selectedProductImageUrls.includes(url) &&
|
|
selectedModelImageUrl !== url,
|
|
);
|
|
if (nextRerun) {
|
|
selectedRerunImageUrls.push(nextRerun);
|
|
continue;
|
|
}
|
|
const nextTemplate = templateReferenceImageUrls.find(
|
|
(url) =>
|
|
!selectedTemplateImageUrls.includes(url) &&
|
|
!selectedRerunImageUrls.includes(url) &&
|
|
!selectedProductImageUrls.includes(url) &&
|
|
selectedModelImageUrl !== url,
|
|
);
|
|
if (!nextTemplate) break;
|
|
selectedTemplateImageUrls.push(nextTemplate);
|
|
}
|
|
|
|
const entries: Array<{
|
|
url: string;
|
|
role: DetailReplacementGenerationInputRole;
|
|
}> = [
|
|
...selectedProductImageUrls.map((url) => ({ url, role: "product" as const })),
|
|
...(selectedModelImageUrl
|
|
? [{ url: selectedModelImageUrl, role: "model" as const }]
|
|
: []),
|
|
...selectedTemplateImageUrls.map((url) => ({
|
|
url,
|
|
role: "supplement" as const,
|
|
})),
|
|
...selectedRerunImageUrls.map((url) => ({
|
|
url,
|
|
role: "supplement" as const,
|
|
})),
|
|
{ url: referenceImageUrl, role: "layout" as const },
|
|
].filter((entry) => /^https?:\/\//i.test(entry.url));
|
|
|
|
return {
|
|
entries,
|
|
imageUrls: entries.map((entry) => entry.url),
|
|
inputImageRoleByUrl: Object.fromEntries(
|
|
entries.map((entry) => [entry.url, entry.role]),
|
|
) as Record<string, DetailReplacementGenerationInputRole>,
|
|
productImageUrls: selectedProductImageUrls,
|
|
modelImageUrl: selectedModelImageUrl,
|
|
supplementImageUrls: [
|
|
...selectedTemplateImageUrls,
|
|
...selectedRerunImageUrls,
|
|
],
|
|
templateImageUrls: selectedTemplateImageUrls,
|
|
rerunImageUrls: selectedRerunImageUrls,
|
|
};
|
|
}
|