File size: 3,782 Bytes
065d164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103fcd2
065d164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { GoogleGenerativeAI } from "@google/generative-ai";

// Initialize the Gemini API with the API key
const apiKey = process.env.GEMINI_API_KEY;
const genAI = new GoogleGenerativeAI(apiKey);

// Maximum number of retries for API calls
const MAX_RETRIES = 3;
// Delay between retries (in milliseconds)
const RETRY_DELAY = 1000;

// Helper function to wait between retries
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const { image, prompt } = req.body;
    
    if (!image) {
      return res.status(400).json({ error: 'Image data is required' });
    }

    // Remove the data URL prefix
    const base64Image = image.replace(/^data:image\/(png|jpeg|jpg);base64,/, '');
    
    // Initialize the Gemini 2.0 Flash model
    const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
    
    // Use the custom prompt if provided, otherwise use the default
    const promptText = prompt || "Look at this image and identify the main object or scene (ignoring any hands or fingers that might be visible). Generate a single, short, insightful thought (maximum 5 words) about this object or scene. Focus on something interesting, fun, or unexpected about it. DO NOT mention hands, fingers, pose estimation, motion tracking, or any computer vision technology in your response. Respond with just the thought, no additional text.";
    
    // Prepare the image part for the model
    const imagePart = {
      inlineData: {
        data: base64Image,
        mimeType: "image/jpeg",
      },
    };

    // Implement retry logic with exponential backoff
    let lastError = null;
    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
      try {
        // Generate content with the image
        const result = await model.generateContent([promptText, imagePart]);
        const response = await result.response;
        const text = response.text();
        
        return res.status(200).json({ thought: text });
      } catch (error) {
        console.error(`Attempt ${attempt + 1} failed:`, error.message);
        lastError = error;
        
        // Check if error is related to throttling or service unavailability
        if (error.message.includes('503 Service Unavailable') || 
            error.message.includes('THROTTLED') || 
            error.message.includes('overloaded')) {
          // Wait before retrying with exponential backoff
          await sleep(RETRY_DELAY * Math.pow(2, attempt));
          continue;
        } else {
          // For other errors, don't retry
          break;
        }
      }
    }
    
    // If we've exhausted all retries or encountered a non-retryable error
    console.error('All attempts failed or non-retryable error:', lastError);
    
    // Provide a user-friendly error message based on the error type
    if (lastError.message.includes('THROTTLED') || lastError.message.includes('overloaded')) {
      return res.status(503).json({ 
        error: 'The AI service is currently busy. Please try again in a moment.',
        fallbackThought: "πŸ€”"
      });
    } else if (lastError.message.includes('quota')) {
      return res.status(429).json({ 
        error: 'API quota exceeded. Please try again later.',
        fallbackThought: "πŸ€”"
      });
    } else {
      return res.status(500).json({ 
        error: 'Something went wrong while analyzing your image.',
        fallbackThought: "πŸ€”"
      });
    }
  } catch (error) {
    console.error('Unexpected error:', error);
    return res.status(500).json({ 
      error: 'An unexpected error occurred',
      fallbackThought: "πŸ€”"
    });
  }
}