gemini-3d-drawing / pages /api /analyze-image.js
Trudy's picture
Initial commit with proper LFS tracking
5f07a23
import { GoogleGenerativeAI } from '@google/generative-ai';
// Initialize Gemini API with error handling
const initializeGeminiAI = () => {
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error('GEMINI_API_KEY is not set in environment variables');
}
return new GoogleGenerativeAI(apiKey);
};
// Configure API route options
export const config = {
api: {
bodyParser: {
sizeLimit: '10mb' // Increase the body size limit to 10MB for larger images
}
}
};
export default async function handler(req, res) {
// Only allow POST requests
if (req.method !== 'POST') {
res.setHeader('Allow', ['POST']);
return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
}
try {
const { image, customApiKey } = req.body;
if (!image) {
return res.status(400).json({ error: 'Image is required' });
}
// Extract base64 data
const base64Data = image.split(',')[1];
if (!base64Data) {
return res.status(400).json({ error: 'Invalid image format' });
}
// Initialize Gemini with the appropriate API key
const apiKey = customApiKey || process.env.GEMINI_API_KEY;
const genAI = new GoogleGenerativeAI(apiKey);
const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
// Prepare the image parts
const imageParts = [
{
inlineData: {
data: base64Data,
mimeType: "image/jpeg"
}
}
];
// Create the prompt - Updated for clarity and better results
const prompt = `Analyze this reference image/moodboard and create a detailed material prompt for a 3D rendering that captures its essence and visual qualities.
The prompt should follow this format and style, but be unique and creative:
Example 1: "Recreate this doodle as a physical chrome sculpture made of chromium metal tubes or pipes in a professional studio setting. If it is typography, render it accordingly, but always have a black background and studio lighting. Render it in Cinema 4D with Octane, using studio lighting against a pure black background. Make it look like a high-end product rendering of a sculptural piece."
Example 2: "Convert this drawing / text into a soft body physics render. Render it as if made of a soft, jelly-like material that responds to gravity and motion. Add realistic deformation, bounce, and squash effects typical of soft body dynamics. Use dramatic lighting against a black background to emphasize the material's translucency and surface properties. Make it look like a high-end 3D animation frame"
Create a new, unique prompt based on the visual qualities of the uploaded image that follows a similar style but is completely different from the examples.
Focus on:
1. Material properties (metallic, glass, fabric, liquid, etc.)
2. Lighting and environment (studio, dramatic, moody, etc.)
3. Visual style (high-end, realistic, stylized, etc.)
4. Rendering technique (Cinema 4D, Octane, etc.)
Also suggest a short, memorable name for this material style (1-2 words) based on the key visual characteristics.
Format the response as JSON with 'prompt' and 'suggestedName' fields.`;
console.log('Calling Gemini Vision API for image analysis...');
// Generate content
const result = await model.generateContent([prompt, ...imageParts]);
const response = result.response;
const responseText = response.text();
console.log('Received response from Gemini');
// Try to parse as JSON, fallback to text if needed
try {
// First try direct parse
const jsonResponse = JSON.parse(responseText);
return res.status(200).json(jsonResponse);
} catch (e) {
console.log('Response not in JSON format, attempting to extract JSON');
// Try to extract JSON from text response
try {
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const extractedJson = JSON.parse(jsonMatch[0]);
return res.status(200).json(extractedJson);
}
} catch (extractError) {
console.error('Failed to extract JSON from response:', extractError);
}
// If all parsing attempts fail, create structured response from text
const lines = responseText.split('\n');
let suggestedName = 'Custom Material';
// Try to find a name in the response
for (const line of lines) {
if (line.toLowerCase().includes('name:') || line.toLowerCase().includes('suggested name:')) {
const namePart = line.split(':')[1];
if (namePart && namePart.trim()) {
suggestedName = namePart.trim();
// Remove quotes if present
suggestedName = suggestedName.replace(/^["'](.*)["']$/, '$1');
break;
}
}
}
return res.status(200).json({
prompt: responseText,
suggestedName
});
}
} catch (error) {
console.error('Error in analyze-image:', error);
// Check for quota exceeded errors
if (error.message?.includes('quota') || error.message?.includes('Resource has been exhausted')) {
return res.status(429).json({
error: 'API quota exceeded. Please try again later or use your own API key.'
});
}
return res.status(500).json({
error: 'Failed to analyze image',
details: error.message
});
}
}