Spaces:
Running
Running
import { GoogleGenerativeAI } from '@google/generative-ai'; | |
import fs from 'fs'; | |
import path from 'path'; | |
// Define a fallback shape in case no reference image is provided and the file doesn't exist | |
// This is a simple white circle on black background encoded as base64 | |
const DEFAULT_SHAPE_DATA_URL = 'data:image/png;base64,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'; | |
// Helper function to read the image file | |
const loadImageData = (filePath) => { | |
try { | |
const absolutePath = path.resolve('./public', filePath); // Adjust if your public dir is elsewhere | |
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)); | |
// Initialize the model | |
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, | |
} | |
}); | |
// Get the base image data (either from request or default) | |
const baseImageData = referenceImageData || DEFAULT_SHAPE_DATA_URL; | |
console.log('Using reference image:', referenceImageData ? 'Custom' : 'Default'); | |
// Construct the prompt for the image model | |
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)); | |
// Prepare generation content | |
const generationContent = [ | |
{ text: imageGenerationPrompt }, | |
{ | |
inlineData: { | |
data: baseImageData, | |
mimeType: "image/png" | |
} | |
}, | |
]; | |
console.log('Calling Gemini API for image generation...'); | |
// Generate content | |
const result = await model.generateContent(generationContent); | |
const response = await result.response; | |
console.log('Received response from Gemini API'); | |
// Process response | |
let generatedImageData = null; | |
// Safely access parts | |
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' | |
}); | |
} | |
} |