forked from innovacion/playground
Initial commit
This commit is contained in:
163
frontend/app/api/generate-video/route.ts
Normal file
163
frontend/app/api/generate-video/route.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user