|
import { GoogleGenerativeAI } from '@google/generative-ai'; |
|
import fs from 'fs'; |
|
import path from 'path'; |
|
|
|
|
|
|
|
const DEFAULT_SHAPE_DATA_URL = 'data:image/png;base64,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'; |
|
|
|
|
|
const loadImageData = (filePath) => { |
|
try { |
|
const absolutePath = path.resolve('./public', filePath); |
|
console.log(`Loading reference image from: ${absolutePath}`); |
|
if (fs.existsSync(absolutePath)) { |
|
const imageBuffer = fs.readFileSync(absolutePath); |
|
return imageBuffer.toString('base64'); |
|
} else { |
|
console.error(`Reference image not found at: ${absolutePath}`); |
|
return null; |
|
} |
|
} catch (error) { |
|
console.error('Error loading reference image:', error); |
|
return null; |
|
} |
|
}; |
|
|
|
export default async function handler(req, res) { |
|
if (req.method !== 'POST') { |
|
return res.status(405).json({ error: 'Method not allowed' }); |
|
} |
|
|
|
console.log('Starting thumbnail generation request'); |
|
|
|
try { |
|
const { prompt, referenceImageData } = req.body; |
|
|
|
if (!prompt) { |
|
console.error('Missing prompt in request'); |
|
return res.status(400).json({ error: 'Prompt is required' }); |
|
} |
|
|
|
console.log('Received prompt:', prompt.substring(0, 100)); |
|
|
|
|
|
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); |
|
const model = genAI.getGenerativeModel({ |
|
model: "gemini-2.0-flash-exp-image-generation", |
|
generationConfig: { |
|
temperature: 0.8, |
|
topP: 0.9, |
|
topK: 40, |
|
maxOutputTokens: 8192, |
|
} |
|
}); |
|
|
|
|
|
const baseImageData = referenceImageData || DEFAULT_SHAPE_DATA_URL; |
|
console.log('Using reference image:', referenceImageData ? 'Custom' : 'Default'); |
|
|
|
|
|
const imageGenerationPrompt = `Treat the object shown in the reference image (the white circle) as a simple 3D sphere. Apply the following material description or style directly onto this sphere...`; |
|
|
|
console.log('Generated image prompt:', imageGenerationPrompt.substring(0, 100)); |
|
|
|
|
|
const generationContent = [ |
|
{ text: imageGenerationPrompt }, |
|
{ |
|
inlineData: { |
|
data: baseImageData, |
|
mimeType: "image/png" |
|
} |
|
}, |
|
]; |
|
|
|
console.log('Calling Gemini API for image generation...'); |
|
|
|
|
|
const result = await model.generateContent(generationContent); |
|
const response = await result.response; |
|
|
|
console.log('Received response from Gemini API'); |
|
|
|
|
|
let generatedImageData = null; |
|
|
|
const parts = response?.candidates?.[0]?.content?.parts; |
|
|
|
if (!parts) { |
|
console.error('No parts in response:', JSON.stringify(response)); |
|
throw new Error('No parts in response from Gemini API'); |
|
} |
|
|
|
console.log('Processing response parts:', parts.length); |
|
|
|
if (Array.isArray(parts)) { |
|
for (const part of parts) { |
|
if (part.inlineData && part.inlineData.mimeType?.startsWith('image/')) { |
|
generatedImageData = part.inlineData.data; |
|
console.log('Found image data in response'); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (!generatedImageData) { |
|
console.error('No image data in response parts:', JSON.stringify(parts)); |
|
throw new Error('No image data found in response parts'); |
|
} |
|
|
|
console.log('Successfully generated thumbnail'); |
|
return res.status(200).json({ |
|
success: true, |
|
imageData: generatedImageData |
|
}); |
|
|
|
} catch (error) { |
|
console.error('Error in thumbnail generation:', error); |
|
return res.status(500).json({ |
|
success: false, |
|
error: error.message || 'An error occurred during thumbnail generation' |
|
}); |
|
} |
|
} |