import OpenAI from 'openai'; import fs from 'fs/promises'; import path from 'path'; import dotenv from 'dotenv'; import crypto from 'crypto'; dotenv.config(); // Helper til at generere en konsistent hash af en prompt function hashPrompt(prompt) { return crypto.createHash('md5').update(prompt).digest('hex'); } // Cache struktur til at gemme prompts og deres resultater async function loadCache() { try { const cache = await fs.readFile('scripts/image-cache.json', 'utf8'); return JSON.parse(cache); } catch { return {}; } } async function saveCache(cache) { await fs.writeFile('scripts/image-cache.json', JSON.stringify(cache, null, 2)); } const openai = new OpenAI({ apiKey: process.env.OPENAI_KEY }); const prompts = [ { name: 'klassisk', prompt: `High-end food photography of an elegant plated dish: - Hot-smoked salmon with cream cheese, fresh dill, and thinly sliced radishes - Beautifully arranged on a modern white ceramic plate - Natural, directional lighting emphasizing textures - Shallow depth of field focusing on the salmon - Professional restaurant-quality presentation - Garnished with micro herbs and edible flowers - 4K quality, shot with a high-end camera` }, { name: 'veg', prompt: `Professional food photography of a colorful vegetarian main course: - Grilled asparagus arranged artfully - Creamy mushroom risotto with parmesan - Edible flowers and micro greens as garnish - Shot from above at a slight angle - Natural window lighting - White ceramic plate on a light wooden surface - Vibrant colors and appealing textures - High-resolution, restaurant quality presentation` }, { name: 'grill', prompt: `Dramatic food photography of grilled dishes: - Perfectly grilled medium-rare flank steak with visible grill marks - Colorful grilled vegetables alongside - Visible steam or smoke - Rich, warm lighting emphasizing caramelization - Shot at a 45-degree angle - Dark moody background - Professional food styling with herbs and sea salt - High-end restaurant presentation quality` }, { name: 'nordisk', prompt: `Nordic cuisine presentation: - Modern interpretation of traditional Nordic dishes - Cold-smoked salmon and pickled herring - Fresh rye bread and traditional accompaniments - Clean, minimal styling on matte black plates - Bright natural lighting - Garnished with fresh dill and edible flowers - Shot from above with some height - Professional restaurant quality presentation` }, { name: 'tapas', prompt: `Spanish tapas spread photography: - Beautifully arranged selection of Spanish tapas - Serrano ham, manchego cheese, and olives - Patatas bravas with vibrant sauce - Traditional ceramic plates and wooden boards - Warm, Mediterranean-inspired lighting - Garnished with fresh herbs and olive oil - Rustic yet elegant presentation - Shot from a 45-degree angle` }, { name: 'brunch', prompt: `Luxury brunch setting photography: - Elegant brunch spread with fresh pastries - Perfectly cooked scrambled eggs with herbs - Fresh fruits and berries - Artisanal bread selection - Bright, morning lighting - White linens and premium tableware - Fresh flowers as decoration - High-end restaurant quality presentation` }, { name: 'italiensk', prompt: `Italian cuisine photography: - Authentic Italian antipasti spread - Fresh bruschetta with vibrant tomatoes - Selection of Italian cured meats - Artfully arranged on rustic wooden board - Warm, directional lighting - Fresh basil and olive oil garnish - Rustic Italian restaurant atmosphere - Professional food styling` }, { name: 'gourmet', prompt: `High-end gourmet dish photography: - Elegant beef tenderloin dish with truffle - Modern plating on dark ceramic plate - Artistic sauce presentation - Micro herbs and edible flowers - Dramatic lighting emphasizing textures - Shallow depth of field - Michelin-star quality presentation - Shot with professional camera setup` }, { name: 'fransk', prompt: `French haute cuisine photography: - Elegant plating of foie gras and brioche - Duck confit with pommes sarladaises - Sophisticated sauce work and garnishes - Premium porcelain plate with gold rim - Professional studio lighting - Shallow depth of field - Michelin-star presentation style - Garnished with edible flowers and micro herbs` }, { name: 'jul', prompt: `Nordic Christmas dinner photography: - Elegant presentation of traditional Danish Christmas dishes - Beautifully arranged confited duck leg - Caramelized potatoes and red cabbage - Classic white porcelain plate - Warm, festive lighting with candle glow - Garnished with fresh herbs - Holiday atmosphere but modern presentation - Professional food photography style` }, { name: 'fusion', prompt: `Modern Asian fusion food photography: - Contemporary Asian fusion dish - Korean style short ribs with modern plating - Colorful Asian vegetables and garnishes - Dramatic black ceramic plate - Professional studio lighting - Garnished with micro herbs and sesame - Artistic sauce presentation - High-end restaurant quality styling` } ];async function generateImages() { const cache = await loadCache(); for (const { name, prompt } of prompts) { const promptHash = hashPrompt(prompt); const imagePath = path.join(process.cwd(), 'public', 'img', `${name}.jpg`); try { // Tjek om billedet allerede eksisterer try { await fs.access(imagePath); // Hvis billedet findes og prompten er cached, spring over if (cache[promptHash]) { console.log(`✓ Skipping ${name}.jpg (already exists with same prompt)`); continue; } } catch { // Billedet findes ikke, vi skal generere det } console.log(`Generating image for ${name}...`); const response = await openai.images.generate({ model: "dall-e-3", prompt: prompt, n: 1, size: "1024x1024", quality: "hd", style: "natural" }); const imageUrl = response.data[0].url; // Download billedet const imageResponse = await fetch(imageUrl); const buffer = await imageResponse.arrayBuffer(); // Gem billedet await fs.mkdir(path.join(process.cwd(), 'public', 'img'), { recursive: true }); await fs.writeFile(imagePath, Buffer.from(buffer)); // Gem prompt i cache cache[promptHash] = { name, timestamp: new Date().toISOString() }; await saveCache(cache); console.log(`✅ Generated and saved ${name}.jpg`); } catch (error) { console.error(`❌ Error generating ${name}:`, error); } } } // Håndter afbrydelse af scriptet async function cleanup() { console.log('\nSaving cache and cleaning up...'); try { await saveCache(await loadCache()); console.log('Cache saved successfully'); } catch (error) { console.error('Error saving cache:', error); } process.exit(0); } // Lyt efter SIGINT (Ctrl+C) process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup); // Run the script generateImages().then(() => { console.log('All done!'); process.exit(0); }).catch(error => { console.error('Error:', error); process.exit(1); });