forked from innovacion/playground
Initial commit
This commit is contained in:
154
frontend/app/api/generate-image/route.ts
Normal file
154
frontend/app/api/generate-image/route.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { type ImageGenerationConfig, getSafetySettings } from '@/lib/google-ai';
|
||||
import { vertexAI } from '@/lib/google-ai-server';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
export const maxDuration = 60;
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body: ImageGenerationConfig = await req.json();
|
||||
|
||||
const {
|
||||
model,
|
||||
prompt,
|
||||
aspectRatio = '1:1',
|
||||
numberOfImages = 1,
|
||||
negativePrompt,
|
||||
temperature = 1,
|
||||
safetyFilterLevel = 'block_some',
|
||||
referenceImages,
|
||||
} = body;
|
||||
|
||||
if (!prompt || !model) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Prompt y modelo son requeridos' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Obtener el modelo generativo de Vertex AI
|
||||
const generativeModel = vertexAI.getGenerativeModel({
|
||||
model: model,
|
||||
safetySettings: getSafetySettings(safetyFilterLevel) as any,
|
||||
generationConfig: {
|
||||
temperature: temperature,
|
||||
maxOutputTokens: 8192,
|
||||
},
|
||||
});
|
||||
|
||||
// Construir el prompt completo
|
||||
let fullPrompt = prompt;
|
||||
if (negativePrompt) {
|
||||
fullPrompt += `\n\nNo incluir: ${negativePrompt}`;
|
||||
}
|
||||
|
||||
// Agregar instrucciones de aspect ratio si no es 1:1
|
||||
if (aspectRatio !== '1:1') {
|
||||
fullPrompt += `\n\nGenera la imagen en formato ${aspectRatio}.`;
|
||||
}
|
||||
|
||||
// Construir parts con imágenes de referencia si existen
|
||||
const parts: any[] = [];
|
||||
|
||||
// Agregar imágenes de referencia primero
|
||||
if (referenceImages && referenceImages.length > 0) {
|
||||
for (const refImg of referenceImages) {
|
||||
parts.push({
|
||||
inlineData: {
|
||||
data: refImg.data,
|
||||
mimeType: refImg.mimeType,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Agregar el prompt de texto
|
||||
parts.push({ text: fullPrompt });
|
||||
|
||||
// Generar contenido
|
||||
const result = await generativeModel.generateContent({
|
||||
contents: [
|
||||
{
|
||||
role: 'user',
|
||||
parts: parts,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const response = result.response;
|
||||
|
||||
// Extraer imágenes de la respuesta
|
||||
const images: string[] = [];
|
||||
|
||||
if (response.candidates && response.candidates.length > 0) {
|
||||
for (const candidate of response.candidates) {
|
||||
if (candidate.content?.parts) {
|
||||
for (const part of candidate.content.parts) {
|
||||
// Verificar si la parte contiene datos inline (imagen)
|
||||
if ('inlineData' in part && part.inlineData) {
|
||||
const imageData = part.inlineData.data;
|
||||
if (imageData) {
|
||||
images.push(imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si no hay imágenes, intentar generar más información de debug
|
||||
if (images.length === 0) {
|
||||
console.error('No se encontraron imágenes en la respuesta');
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'El modelo no generó imágenes',
|
||||
details: 'El modelo respondió pero no incluyó datos de imagen',
|
||||
response: response,
|
||||
suggestion: 'Prueba con un prompt más descriptivo o cambia el modelo',
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
images: images,
|
||||
model: model,
|
||||
prompt: prompt,
|
||||
aspectRatio: aspectRatio,
|
||||
count: images.length,
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error generando imagen:', error);
|
||||
|
||||
// Manejar errores específicos de la API
|
||||
let errorMessage = 'Error generando imagen';
|
||||
let errorDetails = error.message;
|
||||
|
||||
if (error.message?.includes('credentials') || error.message?.includes('authentication')) {
|
||||
errorMessage = 'Error de autenticación';
|
||||
errorDetails = 'Verifica las credenciales del Service Account';
|
||||
} else if (error.message?.includes('quota')) {
|
||||
errorMessage = 'Límite de cuota excedido';
|
||||
errorDetails = 'Has alcanzado el límite de uso de la API';
|
||||
} else if (error.message?.includes('safety')) {
|
||||
errorMessage = 'Contenido bloqueado por seguridad';
|
||||
errorDetails = 'El prompt fue bloqueado por políticas de seguridad';
|
||||
} else if (error.message?.includes('permission')) {
|
||||
errorMessage = 'Error de permisos';
|
||||
errorDetails = 'El Service Account no tiene permisos para Vertex AI';
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: errorMessage,
|
||||
details: errorDetails,
|
||||
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined,
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user