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) => 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, productImageUrls: selectedProductImageUrls, modelImageUrl: selectedModelImageUrl, supplementImageUrls: [ ...selectedTemplateImageUrls, ...selectedRerunImageUrls, ], templateImageUrls: selectedTemplateImageUrls, rerunImageUrls: selectedRerunImageUrls, }; }