Spaces:
Running
Running
File size: 5,481 Bytes
5f07a23 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
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
});
}
} |