|
import { GoogleGenerativeAI } from "@google/generative-ai"; |
|
|
|
|
|
const apiKey = process.env.GEMINI_API_KEY; |
|
const genAI = new GoogleGenerativeAI(apiKey); |
|
|
|
|
|
const MAX_RETRIES = 3; |
|
|
|
const RETRY_DELAY = 1000; |
|
|
|
|
|
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' }); |
|
} |
|
|
|
|
|
const base64Image = image.replace(/^data:image\/(png|jpeg|jpg);base64,/, ''); |
|
|
|
|
|
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" }); |
|
|
|
|
|
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."; |
|
|
|
|
|
const imagePart = { |
|
inlineData: { |
|
data: base64Image, |
|
mimeType: "image/jpeg", |
|
}, |
|
}; |
|
|
|
|
|
let lastError = null; |
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { |
|
try { |
|
|
|
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; |
|
|
|
|
|
if (error.message.includes('503 Service Unavailable') || |
|
error.message.includes('THROTTLED') || |
|
error.message.includes('overloaded')) { |
|
|
|
await sleep(RETRY_DELAY * Math.pow(2, attempt)); |
|
continue; |
|
} else { |
|
|
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
console.error('All attempts failed or non-retryable error:', lastError); |
|
|
|
|
|
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: "π€" |
|
}); |
|
} |
|
} |