import { ThumbnailGenerator } from "@mintel/thumbnail-generator"; import * as path from "node:path"; import * as fs from "node:fs/promises"; async function run() { const apiKey = process.env.REPLICATE_API_TOKEN || process.env.REPLICATE_API_KEY; if (!apiKey) { console.error("❌ Missing REPLICATE_API_TOKEN in environment."); process.exit(1); } const targetFile = process.argv[2]; if (!targetFile) { console.error( "❌ Usage: npx tsx scripts/generate-thumbnail.ts ", ); process.exit(1); } let topic = targetFile; let filename = "thumbnail.png"; // Try to parse the topic from the MDX frontmatter if a file is provided if (targetFile.endsWith(".mdx")) { try { const content = await fs.readFile(targetFile, "utf8"); const titleMatch = content.match(/title:\s*"?([^"\n]+)"?/); topic = titleMatch ? titleMatch[1] : path.basename(targetFile, ".mdx"); filename = `${path.basename(targetFile, ".mdx")}.png`; } catch (e) { console.warn( `⚠️ Could not read ${targetFile} as a file. Using literal argument as topic.`, ); topic = targetFile; } } console.log(`Generating abstract thumbnail for topic: "${topic}"`); const generator = new ThumbnailGenerator({ replicateApiKey: apiKey }); const isRoot = process.cwd().endsWith("mintel.me"); const baseDir = isRoot ? path.join(process.cwd(), "apps", "web") : process.cwd(); const outputPath = path.join(baseDir, "public", "blog", filename); // Check if thumbnail already exists to avoid redundant generation try { await fs.access(outputPath); console.log(`⏭️ Thumbnail already exists, skipping: ${filename}`); return; } catch { // File does not exist, proceed with generation } const inspirationPath = path.join( baseDir, "public", "blog", "inspiration.png", ); let hasInspiration = false; try { await fs.access(inspirationPath); hasInspiration = true; } catch { hasInspiration = false; } const customPrompt = `Extremely clean, flat, abstract geometric illustration. Use the provided image prompt ONLY as a STRICT style, color, and texture reference. Do not copy the image content, just the aesthetic. Characteristics: Flat vector design, 2D only (no 3D), tech/startup/agency aesthetics, highly professional, abstract data representations, extensive use of whitespace. No text, no chaotic lines, no humans.`; await generator.generateImage(topic, outputPath, { systemPrompt: customPrompt, imagePrompt: hasInspiration ? inspirationPath : undefined, }); } run().catch((e) => { console.error("❌ Thumbnail generation failed:", e); process.exit(1); });