handspew / pages /api /gemini.js
Tina Tarighian
initial
065d164
raw
history blame
3.79 kB
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, philosophical, 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: "πŸ€”"
});
}
}