feat: Add layer-wise texture editing using Gemini AI
Build and Deploy / build-and-push (push) Failing after 54s
Build and Deploy / build-and-push (push) Failing after 54s
This commit is contained in:
@@ -647,6 +647,77 @@ CRITICAL INSTRUCTIONS:
|
||||
}
|
||||
});
|
||||
|
||||
// Edit Layer (Gemini Flash Image)
|
||||
app.post('/api/sparkplug/edit-layer', authenticate, async (req, res) => {
|
||||
const { prompt, imageBase64, mimeType } = req.body;
|
||||
if (!prompt || !imageBase64) return res.status(400).json({ error: 'Missing prompt or image' });
|
||||
|
||||
try {
|
||||
const keys = await getKeysFromProfile(req.user.id);
|
||||
const apiKey = keys.GEMINI_API_KEY || keys.NANO_BANANA_API_KEY;
|
||||
if (!apiKey) return res.status(400).json({ error: 'Gemini API key missing' });
|
||||
|
||||
const baseUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image:generateContent';
|
||||
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, "");
|
||||
|
||||
const payload = {
|
||||
contents: [
|
||||
{
|
||||
parts: [
|
||||
{ text: `You are an expert texture editor. Edit the following image based on this prompt: "${prompt}". \nCRITICAL INSTRUCTIONS:\n1. Output MUST be an image with the exact same aspect ratio as the input.\n2. Do NOT change the layout or mapping of the texture.\n3. Increase the resolution and quality of the visual elements as requested.` },
|
||||
{
|
||||
inlineData: {
|
||||
mimeType: mimeType || "image/png",
|
||||
data: base64Data
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
generationConfig: {
|
||||
responseModalities: ["IMAGE"]
|
||||
}
|
||||
};
|
||||
|
||||
const response = await axios.post(`${baseUrl}?key=${apiKey}`, payload, {
|
||||
headers: { 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip,deflate,compress' }
|
||||
});
|
||||
|
||||
let resultBase64 = null;
|
||||
let resultMime = 'image/jpeg';
|
||||
|
||||
const candidate = response.data?.candidates?.[0];
|
||||
if (candidate?.content?.parts) {
|
||||
for (const part of candidate.content.parts) {
|
||||
if (part.inlineData && part.inlineData.data) {
|
||||
resultBase64 = part.inlineData.data;
|
||||
resultMime = part.inlineData.mimeType || 'image/jpeg';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!resultBase64) {
|
||||
throw new Error(`Could not extract base64 image data from Gemini response`);
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(resultBase64, 'base64');
|
||||
const ext = resultMime === 'image/png' ? 'png' : 'jpg';
|
||||
const filename = `layer-edit-${req.user.id}-${Date.now()}.${ext}`;
|
||||
const filepath = path.join(uploadsDir, filename);
|
||||
fs.writeFileSync(filepath, buffer);
|
||||
|
||||
res.json({ imageUrl: \`/uploads/\${filename}\` });
|
||||
} catch (err) {
|
||||
let errorMsg = err.message;
|
||||
if (err.response && err.response.data) {
|
||||
errorMsg = typeof err.response.data === 'object' ? JSON.stringify(err.response.data) : err.response.data;
|
||||
}
|
||||
console.error("Gemini Edit Layer Error:", errorMsg);
|
||||
res.status(500).json({ error: errorMsg });
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Generate 3D (Meshy)
|
||||
app.post('/api/sparkplug/generate-3d', authenticate, async (req, res) => {
|
||||
const { imageUrls } = req.body;
|
||||
|
||||
Reference in New Issue
Block a user