Fix payment flexibility quote length and orphan word
- Shorten quote 03 from 'Can I split it across a few months?' to 'Can I pay monthly?' for column symmetry - Add nbsp between 'money' and 'arriving' to prevent orphan line break
This commit is contained in:
275
pledge-now-pay-later/scripts/generate-brand-photos-3.ts
Normal file
275
pledge-now-pay-later/scripts/generate-brand-photos-3.ts
Normal file
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
* Generate 30 MORE brand photography assets — Batch 3
|
||||
* Filling gaps: everyday life, seasons, work, sport, intergenerational, atmosphere
|
||||
* Run: npx tsx scripts/generate-brand-photos-3.ts
|
||||
*/
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const API_KEY = process.env.GEMINI_API_KEY;
|
||||
if (!API_KEY) { console.error("Missing GEMINI_API_KEY"); process.exit(1); }
|
||||
|
||||
const MODEL = "gemini-3-pro-image-preview";
|
||||
const ENDPOINT = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${API_KEY}`;
|
||||
const OUTPUT_DIR = path.join(process.cwd(), "public/images/brand");
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
const STYLE = `Photorealistic documentary photography. Sony A7III, shallow depth of field, available light. Candid fly-on-the-wall. Nobody looks at camera. No stock aesthetic. No staged poses. No alcohol or wine ever. No visible watermarks. Young modern British-Muslim community. South Asian and Arab features.`;
|
||||
|
||||
interface Photo { filename: string; prompt: string; }
|
||||
|
||||
const PHOTOS: Photo[] = [
|
||||
// ═══════════════════════════════════════════
|
||||
// EVERYDAY BRITISH LIFE (6 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "everyday-01-barbershop.jpg",
|
||||
prompt: `16:9 landscape. Interior of a Turkish/Arab barbershop on a British high street. A young British-Muslim barber in a black apron is carefully trimming a young man's beard with clippers. The client is draped in a black cape, eyes down at his phone. Mirror reflection shows shelves of hair products, a small TV on the wall showing football. Warm halogen spotlights. The barbershop as a gathering place — another man waits on a leather sofa reading a newspaper. 35mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "everyday-02-corner-shop.jpg",
|
||||
prompt: `16:9 landscape. Interior of a British-Asian corner shop. An older Bangladeshi shopkeeper behind the counter, grey stubble, reading glasses pushed up on his forehead, handing change to a customer. Behind him: shelves of sweets, crisps, lottery scratchcard display, a charity collection tin by the till. A young child is reaching for something on a low shelf. The shop door is open showing a wet pavement outside. Fluorescent strip light. The heart of a neighbourhood. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "everyday-03-school-gate.jpg",
|
||||
prompt: `16:9 landscape. School pick-up time outside a British primary school. A group of British-Muslim mothers in hijabs standing by the school gate, chatting while waiting. One is pushing a buggy, another holds a toddler on her hip. Children in school uniform are starting to stream out through the gate. Terraced houses across the road. Overcast afternoon. Yellow lollipop crossing sign visible. The daily ritual. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "everyday-04-nhs-nurse.jpg",
|
||||
prompt: `3:4 portrait. A young British-Muslim woman in NHS nurse scrubs and a hijab, sitting on a bench outside a hospital building during a break. She's holding a takeaway coffee cup with both hands, staring into the middle distance with tired but peaceful eyes. Her hospital ID badge hangs from a lanyard. An ambulance is blurred in the background. Overcast grey light. The quiet exhaustion of someone who serves in every part of life. 85mm f/1.4. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "everyday-05-taxi-driver.jpg",
|
||||
prompt: `16:9 landscape. A British-Muslim taxi driver, 40s, short beard, sitting in his parked black cab at night, filling in a logbook on the steering wheel. The dashboard is glowing green. Through the windshield: a rainy British high street with blurred neon shop signs and streetlights reflected in puddles. A prayer bead tasbih hangs from the rear-view mirror. The solitude of night-shift work. 35mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "everyday-06-graduation.jpg",
|
||||
prompt: `16:9 landscape. A young British-Muslim woman in graduation cap, gown, and hijab, walking across a university quad with her family. Her father in a suit is carrying her bouquet, her mother in a colourful hijab is wiping happy tears, a younger sibling is taking photos on a phone. The university's stone buildings behind them. Autumn light, scattered leaves. The pride of a whole family's sacrifice. 50mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// SPORT & FITNESS (4 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "sport-01-football.jpg",
|
||||
prompt: `16:9 landscape. A five-a-side football match on an outdoor artificial pitch with floodlights. A team of young British-Muslim men in matching bibs mid-game — one player is about to shoot, another defending. In the background behind the cage fence: a group of friends watching, some in thobes having come straight from the mosque. Evening, floodlit, breath visible in cold air. The universal language of a kick-about. 85mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sport-02-sisters-gym.jpg",
|
||||
prompt: `16:9 landscape. A sisters-only fitness class in a community centre hall. A young British-Muslim female instructor in a sports hijab and athletic wear leading a group of women in a circuits class. Some in hijabs, some without (private space). Gym mats on the wooden floor, a speaker playing music (small bluetooth speaker on the floor). Everyone mid-exercise, focused. Bright fluorescent hall light. The empowerment of movement. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sport-03-cricket-park.jpg",
|
||||
prompt: `16:9 landscape. A casual cricket game in a British public park on a summer afternoon. A young British-Muslim batsman in shalwar kameez hitting a tennis ball with a cricket bat. The bowler, in jeans and a t-shirt, mid-delivery. A few fielders spread across the grass, some in thobes. Families on picnic blankets in the background. Lush green grass, scattered clouds, warm summer light. Sunday afternoon perfection. 50mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sport-04-boxing-gym.jpg",
|
||||
prompt: `16:9 landscape. A gritty boxing gym. A young British-Muslim man, early 20s, hitting a heavy bag, sweat flying. His trainer, an older man in a tracksuit, stands behind the bag steadying it, shouting encouragement. Worn red boxing gloves. Concrete walls, peeling posters of old fighters, ropes hanging. Harsh overhead strip light. The discipline and escape of the boxing gym. 85mm f/1.4. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// SPIRITUAL & SACRED (5 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "sacred-01-wudu.jpg",
|
||||
prompt: `16:9 landscape. A mosque wudu (ablution) area. A row of men at stainless steel washing stations, performing wudu before prayer. Water running over hands and forearms. Tiled walls, a drain channel on the floor. One man's face in profile, eyes closed, water dripping from his beard. The meditative ritual of preparation for prayer. Bright overhead light reflecting off wet tiles. 50mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sacred-02-quran-recitation.jpg",
|
||||
prompt: `3:4 portrait. A young British-Muslim boy, about 10, sitting cross-legged on the floor of a mosque, a wooden Quran stand (rehal) in front of him, reciting from an open Quran. His finger follows the Arabic text. He's wearing a white topi. Soft natural light from a window falls across the page. Other children studying blurred in the background. The ancient discipline of learning. 85mm f/1.4. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sacred-03-dua-hands.jpg",
|
||||
prompt: `3:4 portrait. Close-up of two cupped hands raised in dua (supplication) — palms open, facing upward. The hands belong to a young man, visible from the wrists up only. Behind the hands, completely blurred: the warm interior of a mosque. Soft diffused light. The vulnerability and hope of asking. Minimal, powerful, iconic. 85mm macro f/1.4. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sacred-04-night-mosque.jpg",
|
||||
prompt: `16:9 landscape. Exterior of a British mosque at night. The building is modestly lit — warm light glowing through arched windows, a green neon crescent on the minaret. Wet pavement reflecting the lights. A couple of men walking toward the entrance for night prayer. Terraced houses dark on either side. A street lamp. The mosque as a beacon in the night. 24mm f/2.8 long exposure feel. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "sacred-05-calligraphy.jpg",
|
||||
prompt: `3:4 portrait. Close-up of a young British-Muslim woman's hand practising Arabic calligraphy with a bamboo reed pen and black ink. She's writing bismillah on cream-coloured paper. Ink pot to the side. The lettering is beautiful, flowing. Her other hand steadies the paper. Shot from above at an angle. A desk lamp illuminating the work. The art of sacred writing. 50mm macro f/2.8. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// SEASONS & WEATHER (4 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "season-01-winter-coats.jpg",
|
||||
prompt: `16:9 landscape. A charity winter coat drive in a community centre. Racks of donated coats and jackets sorted by size. A young British-Muslim volunteer helping an older woman try on a warm parka. Children's coats hung low on a separate rail. A sign says "Free — Take What You Need" (handwritten). Other people browsing the racks. Fluorescent light, community hall feel. Practical compassion in January. 35mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "season-02-rainy-commute.jpg",
|
||||
prompt: `16:9 landscape. A rainy Monday morning on a British high street. A young British-Muslim woman in hijab and a trench coat walking briskly under an umbrella, splashing through puddles. She's carrying a laptop bag. Red double-decker bus passing behind her, headlights on. Other commuters with umbrellas. Wet reflections everywhere. The atmosphere of a British autumn morning. Shot through rain. 85mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "season-03-park-summer.jpg",
|
||||
prompt: `16:9 landscape. A British-Muslim family picnic in a London park on a warm summer day. A family of five on a large blanket — mother in a floral hijab unpacking tupperware containers, father pouring juice, three children running nearby on the grass. Samosas and fruit visible in the tupperware. Other park-goers in the background. Dappled sunlight through trees. The contentment of a simple day out. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "season-04-snow-mosque.jpg",
|
||||
prompt: `16:9 landscape. A British mosque covered in fresh snow. The dome and minaret dusted white. A single set of footprints leads through the snow to the entrance. Early morning blue light before sunrise. The mosque's warm golden light glows through the windows. Terraced rooftops with snow. Chimney smoke rising. The serenity of a winter fajr. 24mm f/4.0. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// CHARITY LOGISTICS (3 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "logistics-01-warehouse.jpg",
|
||||
prompt: `16:9 landscape. Inside a charity aid warehouse. Metal shelving stacked high with cardboard boxes of donations. A young British-Muslim volunteer in a high-vis vest using a pallet truck to move a stack of boxes. Another volunteer with a clipboard checking inventory. Industrial strip lighting. Concrete floor. The scale of organised giving. 24mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "logistics-02-loading-van.jpg",
|
||||
prompt: `16:9 landscape. A white charity van with its back doors open in a community centre car park. Three young British-Muslim volunteers forming a chain, passing boxes from a doorway into the van. One inside the van stacking, one at the door passing, one carrying from inside. Early morning light, breath visible. A sense of purpose and teamwork. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "logistics-03-sorting-clothes.jpg",
|
||||
prompt: `16:9 landscape. A clothing donation sorting session in a mosque basement. Long trestle tables covered in donated clothes being sorted into piles by size and condition. Five or six British-Muslim volunteers — mix of ages, women in hijabs and men — folding and sorting methodically. Black bin bags of unsorted donations on the floor. Overhead strip light. The labour of generosity. 35mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// INTERGENERATIONAL (4 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "intergen-01-grandma-cooking.jpg",
|
||||
prompt: `16:9 landscape. A British-Pakistani grandmother in a traditional shalwar kameez and dupatta teaching her teenage granddaughter to make roti in a home kitchen. The grandmother's wrinkled hands are pressing and shaping the dough, the granddaughter watches closely, floury hands hovering. A tawa (flat pan) on the stove with a roti cooking. The kitchen is modest — patterned tiles, spice rack, Islamic calendar on the wall. Warm pendant light. Knowledge passed through hands. 50mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "intergen-02-walking-together.jpg",
|
||||
prompt: `16:9 landscape. An elderly British-Muslim man in a long coat and topi walking slowly along a suburban pavement, his young grandson (about 7) holding his hand. Shot from behind. The boy is looking up at his grandfather. Autumn leaves on the ground. Semi-detached houses with bay windows on either side. Weak afternoon sun. The tenderness of a small hand in a large one. 85mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "intergen-03-tech-help.jpg",
|
||||
prompt: `16:9 landscape. A teenage British-Muslim girl in hijab sitting beside her grandfather on a sofa, helping him with something on a tablet (screen not visible). She's pointing at the screen, explaining patiently. He's squinting through reading glasses, leaning in. A cup of chai on the coffee table, an Urdu newspaper folded beside it. The living room has a prayer mat rolled in the corner and family photos on a shelf. Warm lamp light. Patience across generations. 50mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "intergen-04-mosque-elders.jpg",
|
||||
prompt: `16:9 landscape. The social area of a mosque after Friday prayer. A circle of elderly British-Muslim men sitting on plastic chairs, drinking tea from paper cups, deep in conversation. One man is gesturing emphatically, another is laughing. In the background, young men in hoodies are leaving, heading out the door. Two worlds, one space. The mosque as living room. Fluorescent light, simple décor. 35mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// ATMOSPHERE & CINEMATIC (4 photos)
|
||||
// ═══════════════════════════════════════════
|
||||
{
|
||||
filename: "atmos-01-whitechapel-night.jpg",
|
||||
prompt: `16:9 landscape. Whitechapel Road, East London at night. The neon signs of curry houses, fabric shops, and sweet shops glowing in Bengali and English. A few pedestrians — a man in a thobe, a woman with shopping bags, teenagers on bikes. Wet pavement reflecting the colours. The East London Mosque just visible in the distance. The electric energy of a British-Muslim high street after dark. 35mm f/1.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "atmos-02-dawn-call.jpg",
|
||||
prompt: `16:9 landscape. Pre-dawn blue hour in a British city. Silhouette of a mosque minaret against a deep blue sky with the first pink glow on the horizon. Terraced rooftop chimneys in silhouette. A few lit windows in the houses below — people waking for fajr. A single bird on a wire. The stillness of a city between sleep and prayer. 50mm f/2.8 with deep color. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "atmos-03-market-day.jpg",
|
||||
prompt: `16:9 landscape. A bustling outdoor market in a British-Muslim neighbourhood. Stalls selling fruit, vegetables, fabric, and household goods. A young British-Muslim woman in hijab examining mangoes at a fruit stall. The stallholder, an older man in a woollen hat, is weighing something on a hanging scale. Colourful awnings, handwritten price signs. Other shoppers with bags. Overcast daylight. The sensory richness of community commerce. 35mm f/2.8. ${STYLE}`,
|
||||
},
|
||||
{
|
||||
filename: "atmos-04-library-study.jpg",
|
||||
prompt: `16:9 landscape. A British public library. A young British-Muslim woman in hijab studying at a table piled with textbooks and notebooks. She's resting her chin on her hand, deep in thought, pen poised. Beside her, a non-Muslim student also studying — diverse but natural, not posed. Floor-to-ceiling bookshelves behind them. Warm reading lamp on the table mixed with overhead fluorescent. The democracy of a public library. 50mm f/2.0. ${STYLE}`,
|
||||
},
|
||||
];
|
||||
|
||||
// ─── CONCURRENT GENERATION ENGINE ──────────────────────────
|
||||
|
||||
async function generateOne(spec: Photo): Promise<boolean> {
|
||||
const outPath = path.join(OUTPUT_DIR, spec.filename);
|
||||
const t0 = Date.now();
|
||||
|
||||
try {
|
||||
const res = await fetch(ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
contents: [{ parts: [{ text: `Generate a photorealistic photograph. ${spec.prompt}` }] }],
|
||||
generationConfig: { responseModalities: ["IMAGE", "TEXT"] },
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.text();
|
||||
console.error(` ❌ ${spec.filename} — API ${res.status}: ${err.slice(0, 150)}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const data: any = await res.json();
|
||||
const parts = data.candidates?.[0]?.content?.parts;
|
||||
const imgPart = parts?.find((p: any) => p.inlineData?.mimeType?.startsWith("image/"));
|
||||
|
||||
if (!imgPart) {
|
||||
const textPart = parts?.find((p: any) => p.text);
|
||||
console.error(` ❌ ${spec.filename} — No image${textPart ? ": " + textPart.text.slice(0, 100) : ""}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const buf = Buffer.from(imgPart.inlineData.data, "base64");
|
||||
fs.writeFileSync(outPath, buf);
|
||||
const ms = Date.now() - t0;
|
||||
console.log(` ✅ ${spec.filename} — ${(buf.length / 1024).toFixed(0)}KB (${(ms / 1000).toFixed(1)}s)`);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.error(` ❌ ${spec.filename} — ${e.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const BATCH_SIZE = 5; // smaller batches to avoid 429s
|
||||
const batches: Photo[][] = [];
|
||||
|
||||
for (let i = 0; i < PHOTOS.length; i += BATCH_SIZE) {
|
||||
batches.push(PHOTOS.slice(i, i + BATCH_SIZE));
|
||||
}
|
||||
|
||||
console.log("═══════════════════════════════════════════════════════");
|
||||
console.log(" PNPL Brand Photography — Batch 3 (30 more)");
|
||||
console.log(` Model: ${MODEL}`);
|
||||
console.log(` Strategy: ${batches.length} batches × ${BATCH_SIZE} concurrent`);
|
||||
console.log(` Output: ${OUTPUT_DIR}`);
|
||||
console.log("═══════════════════════════════════════════════════════");
|
||||
|
||||
const t0 = Date.now();
|
||||
let success = 0;
|
||||
let failed: Photo[] = [];
|
||||
|
||||
for (let i = 0; i < batches.length; i++) {
|
||||
console.log(`\n⚡ Batch ${i + 1}/${batches.length} — firing ${batches[i].length} requests...`);
|
||||
const results = await Promise.allSettled(batches[i].map(p => generateOne(p)));
|
||||
const batchSuccess = results.filter(r => r.status === "fulfilled" && r.value).length;
|
||||
success += batchSuccess;
|
||||
|
||||
for (const spec of batches[i]) {
|
||||
if (!fs.existsSync(path.join(OUTPUT_DIR, spec.filename))) {
|
||||
failed.push(spec);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < batches.length - 1) {
|
||||
console.log(` ⏳ 3s cooldown...`);
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
}
|
||||
}
|
||||
|
||||
// Retry failures with longer delays
|
||||
if (failed.length > 0) {
|
||||
console.log(`\n🔄 Retrying ${failed.length} failures (5s between each)...`);
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
for (const spec of failed) {
|
||||
const ok = await generateOne(spec);
|
||||
if (ok) success++;
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
}
|
||||
}
|
||||
|
||||
const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
|
||||
|
||||
console.log("\n═══════════════════════════════════════════════════════");
|
||||
console.log(` Done: ${success}/${PHOTOS.length} photos in ${elapsed}s`);
|
||||
console.log(` Total brand library: 90 photos`);
|
||||
console.log(` Output: ${OUTPUT_DIR}`);
|
||||
console.log("═══════════════════════════════════════════════════════");
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user