Initial commit

This commit is contained in:
Sebastian
2025-11-26 19:00:04 +00:00
commit 0ba05b6483
27 changed files with 2517 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
// Servidor: Configuración de Vertex AI con autenticación
// Este archivo SOLO debe importarse en API routes (server-side)
import { VertexAI } from '@google-cloud/vertexai';
// Leer credenciales desde variables de entorno
export const projectId = process.env.GOOGLE_PROJECT_ID!;
export const location = process.env.GOOGLE_LOCATION || 'us-central1';
// Construir objeto de credenciales desde variables de entorno
export const credentials = {
type: 'service_account',
project_id: process.env.GOOGLE_PROJECT_ID,
client_email: process.env.GOOGLE_CLIENT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
};
console.log(`Configurando Vertex AI - Proyecto: ${projectId}, Location: ${location}`);
// Crear instancia de Vertex AI
export const vertexAI = new VertexAI({
project: projectId,
location: location,
googleAuthOptions: {
credentials: credentials,
},
});
console.log('Cliente de Vertex AI creado correctamente');

180
frontend/lib/google-ai.ts Normal file
View File

@@ -0,0 +1,180 @@
// Cliente: Solo tipos y constantes (sin módulos de Node.js)
// Modelos disponibles para generación de imágenes con Gemini
export const geminiImageModels = [
{
id: 'gemini-2.5-flash-image',
name: 'Gemini 2.5 Flash Image',
description: 'Modelo optimizado para generación de imágenes',
supportsImages: true,
capabilities: ['text-to-image', 'image-generation'],
},
{
id: 'gemini-2.0-flash-exp',
name: 'Gemini 2.0 Flash Experimental',
description: 'Modelo experimental con generación de imágenes rápida',
supportsImages: true,
capabilities: ['text-to-image', 'image-editing'],
},
{
id: 'gemini-exp-1206',
name: 'Gemini Experimental 1206',
description: 'Versión experimental con capacidades mejoradas',
supportsImages: true,
capabilities: ['text-to-image', 'multimodal'],
},
{
id: 'gemini-3-pro-image-preview',
name: 'Gemini 3 Pro Image Preview',
description: 'Vista previa de Gemini 3 Pro para generación de imágenes',
supportsImages: true,
capabilities: ['text-to-image', 'image-generation', 'high-quality'],
},
{
id: 'gemini-1.5-pro',
name: 'Gemini 1.5 Pro',
description: 'Modelo más capaz para tareas complejas',
supportsImages: true,
capabilities: ['multimodal', 'long-context'],
},
{
id: 'gemini-1.5-flash',
name: 'Gemini 1.5 Flash',
description: 'Modelo rápido y eficiente',
supportsImages: true,
capabilities: ['multimodal', 'fast'],
},
] as const;
export type GeminiImageModel = typeof geminiImageModels[number];
// Modelos disponibles para generación de videos con Veo
export const veoVideoModels = [
{
id: 'veo-2.0-generate-001',
name: 'Veo 2.0 Generate',
description: 'Modelo base para generación de videos',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation'],
},
{
id: 'veo-2.0-generate-exp',
name: 'Veo 2.0 Generate Experimental',
description: 'Versión experimental de Veo 2.0',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation'],
},
{
id: 'veo-2.0-generate-preview',
name: 'Veo 2.0 Generate Preview',
description: 'Vista previa de Veo 2.0',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation'],
},
{
id: 'veo-3.0-generate-001',
name: 'Veo 3.0 Generate',
description: 'Modelo de última generación para videos',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation', 'high-quality'],
},
{
id: 'veo-3.0-fast-generate-001',
name: 'Veo 3.0 Fast Generate',
description: 'Generación rápida de videos con Veo 3.0',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation', 'fast'],
},
{
id: 'veo-3.1-generate-preview',
name: 'Veo 3.1 Generate Preview',
description: 'Vista previa de Veo 3.1',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation', 'latest'],
},
{
id: 'veo-3.1-fast-generate-preview',
name: 'Veo 3.1 Fast Generate Preview',
description: 'Generación rápida con Veo 3.1 preview',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation', 'fast', 'latest'],
},
{
id: 'test',
name: 'Vtest',
description: 'Test para probar la api de gemini',
supportsVideo: true,
capabilities: ['text-to-video', 'video-generation', 'fast', 'latest'],
},
] as const;
export type VeoVideoModel = typeof veoVideoModels[number];
// Configuración de dimensiones por aspect ratio
export const aspectRatioSizes: Record<string, { width: number; height: number }> = {
'1:1': { width: 1024, height: 1024 },
'3:4': { width: 768, height: 1024 },
'4:3': { width: 1024, height: 768 },
'9:16': { width: 576, height: 1024 },
'16:9': { width: 1024, height: 576 },
};
// Configuración de duración de videos
export const videoDurations = [
{ value: 5, label: '5 segundos' },
{ value: 8, label: '8 segundos' },
{ value: 10, label: '10 segundos' },
] as const;
// Tipos para la configuración
export interface ImageGenerationConfig {
model: string;
prompt: string;
aspectRatio?: string;
numberOfImages?: number;
negativePrompt?: string;
seed?: number;
guidanceScale?: number;
temperature?: number;
safetyFilterLevel?: 'block_none' | 'block_some' | 'block_most';
referenceImages?: Array<{
data: string; // Base64
mimeType: string;
}>;
}
export interface VideoGenerationConfig {
model: string;
prompt: string;
aspectRatio?: string;
duration?: number; // en segundos
negativePrompt?: string;
seed?: number;
temperature?: number;
safetyFilterLevel?: 'block_none' | 'block_some' | 'block_most';
}
// Helper para obtener información del modelo
export function getModelInfo(modelId: string) {
return geminiImageModels.find(m => m.id === modelId);
}
// Helper para validar aspect ratio
export function isValidAspectRatio(modelId: string, aspectRatio: string): boolean {
return true; // Gemini acepta cualquier aspect ratio
}
// Safety settings helpers
export function getSafetySettings(level: 'block_none' | 'block_some' | 'block_most') {
const threshold =
level === 'block_none' ? 'BLOCK_NONE' :
level === 'block_some' ? 'BLOCK_ONLY_HIGH' :
'BLOCK_MEDIUM_AND_ABOVE';
return [
{ category: 'HARM_CATEGORY_HATE_SPEECH', threshold },
{ category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold },
{ category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', threshold },
{ category: 'HARM_CATEGORY_HARASSMENT', threshold },
];
}

26
frontend/lib/utils.ts Normal file
View File

@@ -0,0 +1,26 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// Helper para descargar imagen
export function downloadImage(base64Data: string, filename: string) {
const link = document.createElement('a');
link.href = `data:image/png;base64,${base64Data}`;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Helper para generar nombre de archivo único
export function generateImageFilename(prompt: string): string {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const safePrompt = prompt
.slice(0, 30)
.replace(/[^a-z0-9]/gi, '_')
.toLowerCase();
return `image_${safePrompt}_${timestamp}.png`;
}