forked from innovacion/playground
164 lines
5.4 KiB
TypeScript
164 lines
5.4 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { type VideoGenerationConfig } from '@/lib/google-ai';
|
|
import { projectId, location, credentials } from '@/lib/google-ai-server';
|
|
import { GoogleAuth } from 'google-auth-library';
|
|
|
|
export const runtime = 'nodejs';
|
|
export const maxDuration = 300; // Los videos pueden tardar más
|
|
|
|
export async function POST(req: NextRequest) {
|
|
try {
|
|
const body: VideoGenerationConfig = await req.json();
|
|
|
|
const {
|
|
model,
|
|
prompt,
|
|
aspectRatio = '16:9',
|
|
duration = 5,
|
|
negativePrompt,
|
|
} = body;
|
|
|
|
if (!prompt || !model) {
|
|
return NextResponse.json(
|
|
{ error: 'Prompt y modelo son requeridos' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
|
|
// Configurar autenticación
|
|
const auth = new GoogleAuth({
|
|
credentials: credentials,
|
|
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
|
|
});
|
|
|
|
const client = await auth.getClient();
|
|
const accessToken = await client.getAccessToken();
|
|
|
|
if (!accessToken.token) {
|
|
throw new Error('No se pudo obtener el token de acceso');
|
|
}
|
|
|
|
// Construir el endpoint de la API
|
|
const endpoint = `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${model}:predict`;
|
|
|
|
// Construir el prompt completo
|
|
let fullPrompt = prompt;
|
|
if (negativePrompt) {
|
|
fullPrompt += `\n\nNegative prompt: ${negativePrompt}`;
|
|
}
|
|
|
|
// Construir el payload
|
|
const payload = {
|
|
instances: [
|
|
{
|
|
prompt: fullPrompt,
|
|
},
|
|
],
|
|
parameters: {
|
|
aspectRatio: aspectRatio,
|
|
videoDuration: `${duration}s`,
|
|
},
|
|
};
|
|
|
|
console.log(`Endpoint: ${endpoint}`);
|
|
|
|
// Hacer la solicitud a la API de Vertex AI
|
|
const response = await fetch(endpoint, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${accessToken.token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
console.error('Error de la API:', data);
|
|
throw new Error(
|
|
data.error?.message ||
|
|
`Error ${response.status}: ${response.statusText}`
|
|
);
|
|
}
|
|
|
|
|
|
// Extraer video de la respuesta
|
|
let videoData: string | null = null;
|
|
|
|
if (data.predictions && data.predictions.length > 0) {
|
|
const prediction = data.predictions[0];
|
|
|
|
// Buscar el video en diferentes formatos posibles
|
|
if (prediction.bytesBase64Encoded) {
|
|
videoData = prediction.bytesBase64Encoded;
|
|
} else if (prediction.videoBase64) {
|
|
videoData = prediction.videoBase64;
|
|
} else if (prediction.video) {
|
|
videoData = prediction.video;
|
|
}
|
|
}
|
|
|
|
// Si no hay video, retornar error con más información
|
|
if (!videoData) {
|
|
console.error('No se encontró video en la respuesta');
|
|
|
|
return NextResponse.json(
|
|
{
|
|
error: 'El modelo no generó un video',
|
|
details: 'El modelo respondió pero no incluyó datos de video en el formato esperado',
|
|
response: data,
|
|
suggestion: 'Los modelos Veo pueden necesitar acceso especial o estar en preview. Verifica que tu proyecto tenga acceso a estos modelos.',
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
return NextResponse.json({
|
|
videoData: videoData,
|
|
model: model,
|
|
prompt: prompt,
|
|
aspectRatio: aspectRatio,
|
|
duration: duration,
|
|
});
|
|
|
|
} catch (error: any) {
|
|
console.error('Error generando video:', error);
|
|
|
|
// Manejar errores específicos de la API
|
|
let errorMessage = 'Error generando video';
|
|
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 exceeded') || error.message?.includes('quota')) {
|
|
errorMessage = 'Cuota de uso excedida';
|
|
errorDetails = 'Necesitas solicitar un aumento de cuota para los modelos Veo en Google Cloud Console. Ve a: https://console.cloud.google.com/iam-admin/quotas y busca "Online prediction requests per base model"';
|
|
} 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') || error.message?.includes('403')) {
|
|
errorMessage = 'Error de permisos';
|
|
errorDetails = 'El Service Account no tiene permisos para Vertex AI o los modelos Veo no están habilitados en tu proyecto';
|
|
} else if (error.message?.includes('not found') || error.message?.includes('404')) {
|
|
errorMessage = 'Modelo no encontrado';
|
|
errorDetails = 'El modelo Veo puede no estar disponible en tu región (us-central1). Prueba solicitar acceso a los modelos Veo en Google Cloud Console.';
|
|
} else if (error.message?.includes('Internal')) {
|
|
errorMessage = 'Error interno del servidor';
|
|
errorDetails = 'Los modelos Veo están en preview y pueden tener disponibilidad limitada. Intenta con otro modelo o más tarde.';
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{
|
|
error: errorMessage,
|
|
details: errorDetails,
|
|
fullError: error.message,
|
|
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined,
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|