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 
    });
  }
}