CARDS / pages /api /gemini.js
ginipick's picture
Update pages/api/gemini.js
bc4db62 verified
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: "πŸ€”"
});
}
}