196 lines
8.3 KiB
JavaScript
196 lines
8.3 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const REPLICATE_API_TOKEN = process.env.REPLICATE_API_TOKEN || 'r8_UW1EJyKwZgE7V35kfpPzh4uRJbFcvCF48vVGT';
|
|
|
|
const IMAGES_TO_GENERATE = [
|
|
// ==========================================
|
|
// ROOFING & EXTERIOR CONTRACTING
|
|
// ==========================================
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/roofing/hero.jpg'),
|
|
prompt: 'Commercial photography of a professional certified roofer in safety harness inspecting a pristine architectural shingle roof on a luxury modern residential house, sunny sky, crisp detail, 8k commercial photography',
|
|
aspect_ratio: '16:9',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/roofing/shingle_replacement.jpg'),
|
|
prompt: 'Close-up commercial shot of master roofer hands installing premium charcoal architectural shingles with pneumatic nail gun on roof deck, clean straight lines, expert craftsmanship',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/roofing/drone_inspection.jpg'),
|
|
prompt: 'Commercial roof inspection drone hovering over luxury residential roof ridge, high-tech aerial survey camera, bright clear sky, precision inspection',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/roofing/gutter_install.jpg'),
|
|
prompt: 'Seamless modern black aluminum gutter system installation with downspout on clean residential roof fascia, crisp architectural detail',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
|
|
// ==========================================
|
|
// PLUMBING & DRAIN SERVICES
|
|
// ==========================================
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/plumbing/hero.jpg'),
|
|
prompt: 'Commercial photography of a friendly master plumber in clean branded navy uniform holding a pipe wrench beside a modern service van in front of an upscale suburban home, bright daylight, 8k commercial portrait',
|
|
aspect_ratio: '16:9',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/plumbing/tankless_heater.jpg'),
|
|
prompt: 'Modern high-efficiency wall-mounted tankless water heater installation, neat copper pipes, pressure valves, clean utility room wall, professional plumbing',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/plumbing/hydro_jetting.jpg'),
|
|
prompt: 'Commercial plumbing technician operating a high-pressure hydro-jetting rig and digital sewer camera monitor, high-tech drain diagnostic equipment',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/plumbing/pipe_repair.jpg'),
|
|
prompt: 'Plumber hands soldering copper water pipes with clean shiny joints and precision plumbing fittings under sink, expert craftsmanship, warm focused light',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
|
|
// ==========================================
|
|
// MEDICAL / DENTAL / AESTHETIC CLINIC
|
|
// ==========================================
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/medical-legal/hero.jpg'),
|
|
prompt: 'Luxurious modern concierge wellness clinic interior, marble reception desk, warm architectural lighting, minimalist tranquil spa-like aesthetic, 8k interior design photography',
|
|
aspect_ratio: '16:9',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/medical-legal/facial_rejuvenation.jpg'),
|
|
prompt: 'State-of-the-art aesthetic medical consultation treatment room, comfortable ergonomic procedure chair, clean modern medical equipment, elegant neutral tones',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/medical-legal/laser_treatment.jpg'),
|
|
prompt: 'Advanced modern dermatological aesthetic laser device in sleek clinic suite, high-tech wellness technology, immaculate clean environment',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/medical-legal/wellness_infusion.jpg'),
|
|
prompt: 'Serene luxury IV infusion lounge suite with plush leather armchair, soft warm lighting, calm private wellness sanctuary',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
|
|
// ==========================================
|
|
// ELECTRICAL & SMART HOME SYSTEMS
|
|
// ==========================================
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/electrical/hero.jpg'),
|
|
prompt: 'Commercial photography of a certified master electrician in uniform using a digital multimeter inspecting a clean modern electrical service panel, bright interior, 8k commercial photography',
|
|
aspect_ratio: '16:9',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/electrical/ev_charger.jpg'),
|
|
prompt: 'Sleek modern wall-mounted Level 2 EV car charger installed on clean garage wall charging an electric vehicle, illuminated LED indicator, premium installation',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/electrical/panel_upgrade.jpg'),
|
|
prompt: 'Clean modern 200-amp electrical breaker panel with neatly organized wiring, labeled circuit breakers, professional electrical craftsmanship',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
{
|
|
targetPath: path.resolve(__dirname, '../public/images/electrical/smart_lighting.jpg'),
|
|
prompt: 'Modern architectural interior with warm recessed smart LED ceiling lighting, under-cabinet ambient lighting glow, designer luxury home',
|
|
aspect_ratio: '4:3',
|
|
},
|
|
];
|
|
|
|
async function generateSingleImage(item) {
|
|
const dir = path.dirname(item.targetPath);
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
const filename = `${path.basename(dir)}/${path.basename(item.targetPath)}`;
|
|
console.log(`[START] -> ${filename}`);
|
|
const start = Date.now();
|
|
|
|
const createRes = await fetch('https://api.replicate.com/v1/models/black-forest-labs/flux-schnell/predictions', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${REPLICATE_API_TOKEN}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
input: {
|
|
prompt: item.prompt,
|
|
aspect_ratio: item.aspect_ratio,
|
|
output_format: 'jpg',
|
|
},
|
|
}),
|
|
});
|
|
|
|
if (!createRes.ok) {
|
|
const errText = await createRes.text();
|
|
throw new Error(`Replicate POST error (${createRes.status}): ${errText}`);
|
|
}
|
|
|
|
let prediction = await createRes.json();
|
|
const getUrl = prediction.urls.get;
|
|
|
|
let attempts = 0;
|
|
while (prediction.status !== 'succeeded' && prediction.status !== 'failed' && prediction.status !== 'canceled') {
|
|
attempts++;
|
|
await new Promise((r) => setTimeout(r, 1200));
|
|
const pollRes = await fetch(getUrl, {
|
|
headers: {
|
|
'Authorization': `Bearer ${REPLICATE_API_TOKEN}`,
|
|
},
|
|
});
|
|
if (pollRes.ok) {
|
|
prediction = await pollRes.json();
|
|
}
|
|
if (attempts > 30) {
|
|
throw new Error(`Timed out polling for ${filename}`);
|
|
}
|
|
}
|
|
|
|
if (prediction.status !== 'succeeded') {
|
|
throw new Error(`Prediction failed for ${filename}: ${JSON.stringify(prediction.error)}`);
|
|
}
|
|
|
|
const outputUrl = Array.isArray(prediction.output) ? prediction.output[0] : prediction.output;
|
|
const imgRes = await fetch(outputUrl);
|
|
if (!imgRes.ok) throw new Error(`Failed to download ${outputUrl}`);
|
|
const buffer = Buffer.from(await imgRes.arrayBuffer());
|
|
|
|
await fs.promises.writeFile(item.targetPath, buffer);
|
|
const elapsed = ((Date.now() - start) / 1000).toFixed(1);
|
|
console.log(`[DONE] -> ${filename} (${(buffer.length / 1024).toFixed(0)} KB in ${elapsed}s)`);
|
|
}
|
|
|
|
async function run() {
|
|
console.log(`🚀 Starting Replicate batch generation for ${IMAGES_TO_GENERATE.length} images across all service companies...`);
|
|
const concurrency = 4;
|
|
const queue = [...IMAGES_TO_GENERATE];
|
|
const workers = Array.from({ length: concurrency }, async (_, wId) => {
|
|
while (queue.length > 0) {
|
|
const item = queue.shift();
|
|
if (!item) break;
|
|
try {
|
|
await generateSingleImage(item);
|
|
} catch (err) {
|
|
console.error(`[FAIL] -> ${item.targetPath}:`, err.message);
|
|
}
|
|
}
|
|
});
|
|
|
|
await Promise.all(workers);
|
|
console.log('\n🎉 ALL service company images generated and saved successfully!');
|
|
}
|
|
|
|
run().catch((err) => {
|
|
console.error('Fatal error:', err);
|
|
process.exit(1);
|
|
});
|