Files
justvitamin/scripts/generate-top3-imagegen-prompt-pack.ts
Omair Saleh 056c47581f feat: editorial review dashboard + elite-grade pilot batch (5 SKUs)
Ships the second dashboard surface — a Pattern Library + Preview Theatre — that
presents the 4-section PDP pilot batch back to Umar, compliance, and the board
in an editorial format. Adds the full data layer that drives it: 5 source-backed
per-SKU drafts at QA 100/100, 15 competitor PDP semantic extracts, PubMed
evidence packs, EFSA claims library extension, JV brand voice guide, hand-curated
product FAQs, and the Matrixify-ready CSV exports for Lewis.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:50:09 +08:00

178 lines
12 KiB
TypeScript

#!/usr/bin/env bun
import { mkdirSync, readFileSync, writeFileSync } from 'fs'
import { join, dirname } from 'path'
const root = process.cwd()
const csvPath = join(root, '..', 'JV Migration to shopify', 'products_import_lewis_v4.csv')
const outRoot = join(root, 'data', 'generated-assets', 'top3-imagegen-briefs')
const originalRoot = join(root, 'data', 'generated-assets', 'top3-originals')
mkdirSync(outRoot, { recursive: true })
const top3 = [
'JV-TURMERIC500',
'JV-DEFF1000',
'JV-VISISOFT'
]
function parseCsv(text: string) {
const rows: string[][] = []
let row: string[] = []
let cell = ''
let quoted = false
for (let i = 0; i < text.length; i++) {
const char = text[i]
const next = text[i + 1]
if (char === '"') {
if (quoted && next === '"') { cell += '"'; i++ } else quoted = !quoted
} else if (char === ',' && !quoted) { row.push(cell); cell = '' }
else if ((char === '\n' || char === '\r') && !quoted) {
if (char === '\r' && next === '\n') i++
row.push(cell)
if (row.some(v => v !== '')) rows.push(row)
row = []; cell = ''
} else cell += char
}
row.push(cell)
if (row.some(v => v !== '')) rows.push(row)
const headers = rows.shift() || []
return rows.map(values => Object.fromEntries(headers.map((h, i) => [h, values[i] || ''])))
}
function baseSku(variant: string) { return variant.replace(/-\d+$/, '') }
function first<T>(arr: T[]) { return arr.find(Boolean) }
function readJson(path: string) { try { return JSON.parse(readFileSync(path, 'utf8')) } catch { return null } }
function clip(text: any, n = 900) { const v = String(text || '').replace(/\s+/g, ' ').trim(); return v.length > n ? `${v.slice(0, n)}...` : v }
const rows = parseCsv(readFileSync(csvPath, 'utf8').replace(/^\uFEFF/, ''))
const research = Object.fromEntries(top3.map(sku => [sku, readJson(join(root, 'data', 'research-profiles', `${sku}.json`))]))
const productFacts: Record<string, any> = {}
for (const sku of top3) {
const variants = rows.filter(row => baseSku(row['Variant SKU'] || '') === sku)
const master = variants.find(row => row.Title || row['Image Src']) || variants[0]
productFacts[sku] = {
sku,
title: master?.Title,
handle: master?.Handle,
liveImageUrl: master?.['Image Src'],
localOriginal: join(originalRoot, `${sku}-original.jpg`),
variants: variants.map(row => row['Variant SKU']).filter(Boolean),
strapline: master?.['Metafield: pdp.strapline [single_line_text_field]'],
format: master?.['Metafield: filter.format [single_line_text_field]'],
strength: master?.['Metafield: custom.strength [single_line_text_field]'] || master?.['Metafield: filter.strength [single_line_text_field]'],
ingredients: clip(master?.['Metafield: pdp.ingredients [rich_text_field]'], 700),
recommendedIntake: master?.['Metafield: pdp.recommended_intake [single_line_text_field]'],
warning: clip(master?.['Metafield: pdp.warning [multi_line_text_field]'], 500)
}
}
const promptFormats = [
{
key: '01-hero-outcome',
name: 'Hero Outcome Image',
role: 'The most important PDP image. It sells the desired outcome rather than just showing the product.',
evidenceField: (p: any) => p?.pdpGenerationBrief?.mainOfferAngle || p?.customerIntent?.primaryIntent,
onImage: (p: any, f: any) => p?.pdpGenerationBrief?.heroHeadline || f.title,
promptBody: `Create a premium, ultra high-definition DTC ecommerce hero image for this product.\nThe image should feel like a high-converting Shopify brand product page hero image used by elite modern ecommerce brands.\nFocus on the OUTCOME and transformation the customer desires, not just the product itself.\nThe product must be the clear focal point, beautifully lit, highly detailed, realistic, and naturally integrated into the scene.`
},
{
key: '02-offer-value-prop',
name: 'Offer / Value Proposition Image',
role: 'Instantly answers why someone should buy this product or format now.',
evidenceField: (p: any) => first(p?.offerArchitecture?.proofPoints || []) || p?.offerArchitecture?.mainOffer,
onImage: (_p: any, f: any) => f.strength || f.format || 'Clear daily support',
promptBody: `Create a high-converting ecommerce promotional image for this product in a premium DTC brand style.\nThe goal of this image is to instantly communicate a compelling offer or value proposition while maintaining a luxury ecommerce aesthetic.\nThe product must remain visually dominant while the offer feels bold, clear, and impossible to miss.`
},
{
key: '03-social-proof-trust',
name: 'Social Proof / Trust Image',
role: 'Builds credibility using exact product reviews where available, otherwise brand/category trust with clear context.',
evidenceField: (p: any) => first(p?.customerIntent?.publicReviewLanguage || [])?.evidence || first(p?.amazonMarketplaceIntelligence?.themes || [])?.evidence,
onImage: () => 'Trusted daily supplements',
promptBody: `Create a premium ecommerce trust-building image for this product designed for a high-converting Shopify product page carousel.\nThe goal is to make the brand feel credible, trusted, loved, and socially validated.\nThe image should feel authentic, human, and emotionally believable rather than overproduced.`
},
{
key: '04-product-clarity-feature',
name: 'Product Clarity / Feature Image',
role: 'Removes friction by making the product, format, ingredients, and key facts easy to understand.',
evidenceField: (p: any) => first(p?.productTruth?.ingredientsAndDose || []) || first(p?.productTruth?.nonNegotiableFacts || []),
onImage: (_p: any, f: any) => f.strength || f.format || 'Product facts made clear',
promptBody: `Create a premium ecommerce product feature image for this product designed to maximize product understanding and reduce purchase hesitation.\nThe goal is to make the product feel crystal clear, premium, easy to understand, and highly valuable.\nThe product must be beautifully displayed with strong emphasis on materials, features, craftsmanship, ingredients, texture, or included components.`
},
{
key: '05-problem-solution-transformation',
name: 'Problem / Solution Transformation Image',
role: 'Shows emotional movement from confusion/friction to a clearer routine, without medical before/after claims.',
evidenceField: (p: any) => first(p?.objectionAndAnxietyMap || [])?.objection + ': ' + first(p?.objectionAndAnxietyMap || [])?.evidence,
onImage: () => 'From confusion to clarity',
promptBody: `Create a high-converting ecommerce transformation image for this product designed around a clear problem-to-solution narrative.\nThe image should visually dramatize the difference between the customer's painful current state and their improved desired outcome after using the product.\nThe transformation should feel emotionally powerful, visually obvious, and believable.`
},
{
key: '06-lifestyle-identity',
name: 'Lifestyle / Identity Image',
role: 'Connects the product to the identity and routine the customer wants to associate with.',
evidenceField: (p: any) => p?.customerIntent?.archetype || p?.customerIntent?.primaryIntent,
onImage: () => 'Fits your daily routine',
promptBody: `Create a premium lifestyle ecommerce image for this product designed to build aspiration, identity, and emotional brand connection.\nThe image should feel like a luxury DTC campaign from a top-tier Shopify brand.\nThe product should be naturally integrated into an aspirational lifestyle scene that reflects the identity the customer wants to associate with.`
}
]
const shared = `Style requirements:\nPremium DTC aesthetic\nClean composition\nCinematic lighting\nSoft natural shadows\nHigh contrast\nMobile-first composition\nRealistic textures\nUltra sharp focus\nMinimal clutter\nModern luxury ecommerce feel\nHigh-end advertising photography\nShallow depth of field\nAspirational lifestyle vibe\n\nAdditional Shopify carousel optimization requirements:\nGenerate the image in an exact 1:1 square aspect ratio\nFinal image resolution must be exactly 2000x2000 pixels\nDesign specifically for Shopify product page image carousels\nEnsure all six carousel images maintain identical dimensions and composition consistency\nKeep all important visual elements centered for mobile-responsive cropping\nMaintain a single clear focal point per image\nEnsure the product remains instantly recognizable at thumbnail size\nOptimize for mobile-first ecommerce viewing\nPrioritize fast visual comprehension and conversion clarity\nUse premium DTC ecommerce composition standards\nAvoid excessive empty space or uneven framing\nMaintain consistent lighting, framing quality, realism, and visual polish across the full carousel set\nOptimize for sharp zoom functionality on Shopify product pages\nMaintain photorealistic ultra high-definition quality\nEnsure the image feels consistent with premium modern ecommerce brands.`
const hardInvariant = `CRITICAL PRODUCT IMAGE INVARIANT:\nUse the live Just Vitamins product image as the product reference and preserve the product pack 100% exactly. Do not redraw, redesign, relabel, recolor, retouch, crop, reinterpret, or hallucinate the packaging. The product label, logo, typography, tablets/tubes, colors, shape, and visible text must remain identical to the original source image. If generation/editing cannot preserve this, generate the campaign scene/background only and composite the original product image unchanged as the final product layer.`
const all: any[] = []
let md = ['# Top-3 Just Vitamins ImageGen Prompt Pack', '', `Generated: ${new Date().toISOString()}`, '', '## Source rule', '', hardInvariant, '']
for (const sku of top3) {
const f = productFacts[sku]
const p = research[sku]
md.push(`## ${sku}${f.title}`, '', `- Live image URL from database: ${f.liveImageUrl}`, `- Local verified original: ${f.localOriginal}`, `- Handle: ${f.handle}`, `- Variants: ${f.variants.join(', ')}`, '')
for (const format of promptFormats) {
const evidence = clip(format.evidenceField(p), 900)
const claimsToAvoid = clip([...(p?.pdpGenerationBrief?.claimsToAvoid || []), ...(p?.claimAndComplianceProfile?.claimsToAvoid || [])].join('; '), 900)
const facts = clip([f.title, f.format, f.strength, f.strapline, f.ingredients, f.recommendedIntake].filter(Boolean).join('\n'), 1200)
const prompt = [
`Use case: ads-marketing`,
`Asset type: Shopify PDP carousel image`,
`Image type: ${format.name}`,
`Product: ${f.title}`,
`SKU: ${sku}`,
`Live product image URL: ${f.liveImageUrl}`,
`Local original product image: ${f.localOriginal}`,
'',
hardInvariant,
'',
'Product truth to respect:',
facts,
'',
'Source-backed customer/PDP insight:',
evidence || 'Use product truth only; do not invent supporting claims.',
'',
'On-image text, keep short and compliant:',
clip(format.onImage(p, f), 80),
'',
format.promptBody,
'',
shared,
'',
'Avoid:',
'Generic stock photo feel\nBusy backgrounds\nFake-looking AI hands/faces\nCluttered props\nOverdesigned scenes\nMultiple focal points\nCheap salesy design\nFlashy discount stickers\nMedical-looking graphics\nDisease, cure, treatment, prevention, or guaranteed-result claims',
'',
'Claims/compliance guardrails:',
claimsToAvoid || 'No medical or guaranteed-result claims. Use product facts and routine language only.',
'',
'Output style:',
'Photorealistic, premium ecommerce campaign image, 8K quality, conversion-focused, suitable for a Shopify product image carousel.'
].join('\n')
const row = { sku, product: f.title, imageType: format.name, key: format.key, role: format.role, liveImageUrl: f.liveImageUrl, localOriginal: f.localOriginal, onImageText: clip(format.onImage(p, f), 80), evidence, prompt }
all.push(row)
const file = join(outRoot, sku, `${format.key}.txt`)
mkdirSync(dirname(file), { recursive: true })
writeFileSync(file, prompt + '\n', 'utf8')
md.push(`### ${format.name}`, '', `Role: ${format.role}`, '', '```text', prompt, '```', '')
}
}
writeFileSync(join(outRoot, 'top3-imagegen-prompts.json'), JSON.stringify({ generatedAt: new Date().toISOString(), sourceCsv: csvPath, prompts: all }, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'top3-imagegen-prompts.md'), md.join('\n'), 'utf8')
console.log(JSON.stringify({ outRoot, prompts: all.length, products: top3.length }, null, 2))