File size: 3,588 Bytes
065d164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bc4db62
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 ||     "이 이미지λ₯Ό 보고 (보일 μˆ˜λ„ μžˆλŠ” μ†μ΄λ‚˜ 손가락은 λ¬΄μ‹œν•œ 채) μ˜€λ‘œμ§€ playing cards만 μ‹λ³„ν•˜μ„Έμš”. μ‹λ³„λœ μΉ΄λ“œμ˜ μ •ν™•ν•œ μ •λ³΄λ§Œ 좜λ ₯ν•˜μ„Έμš”(예, A μŠ€νŽ˜μ΄λ“œ, 10 ν•˜νŠΈ, J 닀이아λͺ¬λ“œ";
    
    // 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: "πŸ€”"
    });
  }
}