1. Proveedores de IA
Nvito implementa un sistema multi-proveedor con seleccion automática y fallback. Ambos proveedores se gestiónan a traves de la interfaz común AIProvider y estan protegidos por circuit breakers individuales (libreria opossum).
1.1 Proveedores Disponibles
| Proveedor | Modelo por defecto | SDK | Timeout | Uso principal |
|---|---|---|---|---|
| OpenAI | gpt-4o | openai | 30s | Generación de textos, extracción de colores (Vision) |
| Anthropic | claude-sonnet-4-5-20250929 | @anthropic-ai/sdk | 120s | Generación de textos, analisis de diseño (Vision) |
1.2 Interfaz Comun (AIProvider)
Ambos proveedores implementan la interfaz AIProvider definida en providers/ai-provider.interface.ts:
interface AIProvider {
generate(options: GenerationOptions): Promise<GenerationResult>;
extractColors(imageUrl: string): Promise<ColorExtractionResult>;
getModelName(): string;
getProviderName(): string;
isAvailable(): boolean;
}
El resultado de cada generación (GenerationResult) incluye:
| Campo | Tipo | Descripción |
|---|---|---|
content | string | JSON con los textos generados |
tokensUsed | number | Total de tokens consumidos (input + output) |
model | string | Modelo exacto utilizado |
latencyMs | number | Tiempo de respuesta en milisegundos |
1.3 Sistema de Fallback
La seleccion de proveedor sigue está lógica implementada en selectProvider():
- Si el usuario elige
openaiy está disponible, se usa OpenAI. - Si el usuario elige
claudey está disponible, se usa Claude. - Si el modo es
auto(por defecto), se prefiere OpenAI; si no está disponible, se usa Claude. - Si ningún proveedor está disponible, se lanza
BadRequestException.
La disponibilidad se verifica con isAvailable(), que comprueba la existencia del API key configurado.
1.4 Circuit Breaker
Cada proveedor implementa un circuit breaker con la siguiente configuración:
| Parametro | OpenAI | Claude |
|---|---|---|
| Timeout | 30,000 ms | 120,000 ms |
| Error Threshold | 50% | 50% |
| Reset Timeout | 60,000 ms | 60,000 ms |
| Volume Threshold | 5 requests | 5 requests |
Cuando el circuit breaker se abre (más del 50% de errores en las ultimas 5 peticiones), todas las llamadas fallan inmediatamente durante 60 segundos, permitiendo la recuperacion del servicio.
2. Flujo de Generación
El flujo principal de generación se ejecuta a traves del endpoint POST /ai-generation/generate. La IA genera exclusivamente textos emotivos (v2: text-only). Estos textos se combinan con datos reales del evento para construir un InvitationSchemaV2 que los templates artesanales consumen.
2.1 Diagrama de Secuencia
Flujo de Generacion con IA (desde Prompt)
2.2 Enriquecimiento de Prompt
El servicio EnrichPromptService inyecta contexto del evento antes de enviar el prompt al proveedor de IA. La información enriquecida incluye:
- Datos del evento: nombre, tipo, fecha, hora, descripción, código de vestimenta, ubicación.
- Conteo de invitados: total de guests registrados o
maxCapacity. - Secciones a generar: determinadas dinámicamente según los servicios habilitados en
serviceConfig.enabledServices. - Secciones opcionales: gallery, itinerary, accommodation, registry, sponsors, prayer, thankYou, dressCode.
- Secciones por tipo de evento: story (bodas, XV), faq (eventos grandes o formales).
El prompt enriquecido incluye instrucciones estrictas:
- Generar solo textos emotivos en español (Mexico/Latinoamerica).
- No generar colores, fuentes ni aspectos de diseño.
- Para
hero, generar solo subtitle (el título es el nombre real del evento). - Para
event_detailsylocation, generar solo título de sección (datos reales se inyectan automáticamente).
2.3 Validación y Construcción del Schema
Después de recibir la respuesta de la IA:
- Validación:
ValidationService.validateTextsJSON()valida la estructura del JSON generado usando schemas Zod (invitation-schema.zod.ts). - Construcción:
buildSchemaV2()combina los textos generados con datos reales del evento para crear elInvitationSchemaV2final. - Persistencia: El schema se guarda en la invitación y se crea un registro de versión via
VersiónManagerService.
2.4 Calculo de Costo
Los costos se calculan por millon de tokens según la tabla de precios:
| Modelo | Input (USD/1M tokens) | Output (USD/1M tokens) |
|---|---|---|
gpt-4o | $2.50 | $10.00 |
gpt-4o-mini | $0.15 | $0.60 |
claude-sonnet-4-5-20250929 | $3.00 | $15.00 |
3. Analisis de Vision
El sistema permite generar invitaciones a partir de imagenes de referencia. El usuario sube un archivo (imagen o PDF) y el sistema extrae colores, estilos y elementos de diseño para enriquecer la generación.
3.1 Proveedores de Vision
El módulo de Vision opera independientemente del módulo de generación de texto, con tres proveedores:
| Proveedor | Tipo | Modelo | Uso |
|---|---|---|---|
| OpenAI Vision | IA | gpt-4o | Extracción de colores y analisis de diseño |
| Claude Vision | IA | claude-sonnet-4-5-20250929 | Extracción de colores y analisis de diseño |
| Local | Libreria | node-vibrant / sharp | Extracción básica de colores sin IA |
El VisionProviderService gestióna la seleccion y el fallback entre proveedores de vision:
- Modo auto: cascada según el orden configurado (
openai -> claude -> local). - Modo explicito: el usuario selecciona un proveedor específico.
- Fallback automático: si un proveedor falla y el modo no es explicito, se intenta el siguiente en la lista.
3.2 Diagrama de Secuencia - Analisis de Vision
Analisis de Vision — Generacion desde Diseno
3.3 Pipeline de Procesamiento de Imagen
El DesignExtractionService ejecuta el siguiente pipeline:
- Validación: formato permitido (
JPEG,PNG,WebP,GIF), tamano máximo 20 MB. - Optimizacion: redimensionamiento a 1920x1920 max (sin ampliacion) y compresion JPEG al 85% usando
sharp. - Extracción de colores: retorna
ColorPaletteconcolors[],dominantColor, ypalette(primary, secondary, accent, background, text). - Analisis de diseño: retorna
DesignAnalysisconcolorScheme(vibrant/muted/monochrome/pastel),styleHints[](modern, elegant, romantic, etc.) ytypography. - Analisis de esquema de color: determina tipo (monocromatico, analogo, complementario, triadico), armonia, contraste y temperatura (calido/frio/neutro).
- Sugerencia de fuentes: mapeo de estilos a familias tipograficas:
| Estilo detectado | Heading | Body | Accent |
|---|---|---|---|
| Elegant / Formal | Playfair Display | Lora | Great Vibes |
| Modern / Minimalist | Montserrat | Inter | Raleway |
| Playful / Fun | Quicksand | Nunito | Pacifico |
| Romantic | Dancing Script | Crimson Text | Tangerine |
| Default | Poppins | Open Sans | Satisfy |
- Prompt enriquecido: se construye con la paleta exacta, esquema de color, hints de estilo y tipografia sugerida.
4. Cuotas por Plan
El sistema de cuotas (QuotaService) controla la cantidad de generaciones permitidas por organización, con limites mensuales y diarios según el plan contratado.
4.1 Limites por Plan
| Plan | Generaciones/mes | Generaciones/día | Notas |
|---|---|---|---|
| Free | 5 | 2 | Ideal para prueba |
| Starter | 20 | 10 | Eventos pequeños |
| Pro | 100 | 30 | Eventos frecuentes |
| VIP | Ilimitado (-1) | Ilimitado (-1) | Sin restricciones |
4.2 Mecanismo de Control
El flujo de verificacion de cuotas es:
- Verificacion:
checkQuotaOrThrow(organizationId)consulta el registroAIQuotade la organización. - Reset automático: si el mes o día cambio respecto al registro, los contadores se reinician a cero (medianoche UTC).
- Validación de limites: se compara
monthlyUsed < monthlyLimitydailyUsed < dailyLimit. - Excepcion controlada: si se excede el limite diario, se lanza
ForbiddenExceptioncon mensaje indicando que se reinicia a medianoche UTC. Si se excede el mensual, se sugiere actualizar el plan. - Ambiente de desarrollo: en
NODE_ENV=development, la verificacion de cuotas se omite para fácilitar pruebas. - Super Admins: las organizaciones sin
organizationId(Super Admins) no tienen restriccion de cuota.
4.3 Incremento de Uso
Después de cada generación exitosa:
await quotaService.incrementUsage(organizationId, costUsd);
Esto incrementa monthlyUsed, dailyUsed, totalCostUsd y monthCostUsd de forma atomica en la base de datos.
4.4 Endpoint de Consulta
El endpoint GET /ai-generation/quota retorna la información completa de cuota:
interface QuotaInfo {
canGenerate: boolean;
monthlyLimit: number;
monthlyUsed: number;
monthlyRemaining: number;
dailyLimit: number;
dailyUsed: number;
dailyRemaining: number;
totalCostUsd: number;
monthCostUsd: number;
}
5. Tracking de Generaciones
Cada generación se registra en el modelo AIGeneration de Prisma, proporcionando un historial completo de uso, costos y rendimiento.
5.1 Modelo AIGeneration
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador único |
organizationId | string? | Organización que género (null para Super Admins) |
userId | string | Usuario que solicito la generación |
invitationId | string? | Invitación asociada |
provider | string | Proveedor usado (openai, claude, cache) |
model | string | Modelo exacto (gpt-4o, claude-sonnet-4-5-20250929, cached) |
prompt | string | Prompt original del usuario |
designInput | JSON? | Input de diseño (colores, URL de referencia, estilo) |
generatedSchema | JSON? | Schema generado (InvitationSchemaV2 o textos) |
status | string | Estado: pending, completed, failed |
tokensUsed | number? | Total de tokens consumidos |
costUsd | Decimal? | Costo en USD de la generación |
latencyMs | number? | Tiempo de respuesta en milisegundos |
errorMessage | string? | Mensaje de error si fallo |
startedAt | DateTime | Timestamp de inicio |
completedAt | DateTime? | Timestamp de finalizacion |
5.2 Ciclo de Vida del Registro
- Creación: al iniciar la generación, se crea con
status: pending. - Exito: se actualiza con
status: completed, el schema generado, tokens, costo y latencia. - Fallo: se actualiza con
status: failedy elerrorMessage. - Cache: si se sirve desde cache, se registra con
provider: cache,model: cached,costUsd: 0,tokensUsed: 0.
5.3 Endpoints de Consulta
| Metodo | Endpoint | Descripción |
|---|---|---|
GET | /ai-generation/generations/:id | Obtener detalle de una generación |
GET | /ai-generation/generations?limit=20&offset=0 | Listar generaciones de la organización (páginado) |
6. Cache
El servicio AiCacheService implementa un cache en Redis para evitar llamadas repetidas a los proveedores de IA cuando se reciben prompts similares.
6.1 Funcionamiento
- Clave de cache: hash SHA-256 del JSON compuesto por
{ prompt, designInput }. - Prefijo:
ai:generation:. - TTL: 3600 segundos (1 hora) por defecto, configurable via
AI_CACHE_TTL. - Almacenamiento: Redis con
SETEXpara TTL automático.
6.2 Flujo de Cache
- Consulta: antes de llamar al proveedor de IA, se busca en cache con
cacheService.get(prompt, designInput). - Cache hit: se valida el JSON cacheado, se construye el schema, se crea registro con
provider: cachey costo $0. - Cache miss: se procede con la generación normal y al completarse, se almacena con
cacheService.set(prompt, content, designInput). - Invalidación: disponible via
invalidate(prompt, designInput)para forzar regeneración. - Limpieza total:
clearAll()elimina todas las claves con prefijoai:generation:*.
6.3 Configuración
| Variable de entorno | Descripción | Default |
|---|---|---|
AI_CACHE_ENABLED | Habilitar/deshabilitar cache | true |
AI_CACHE_TTL | Tiempo de vida en segundos | 3600 (1 hora) |
Si Redis no está disponible, el cache se deshabilita automáticamente y todas las peticiones se procesan directamente contra los proveedores de IA.
7. Configuración
Toda la configuración del módulo de IA se centraliza en src/config/ai.config.ts y se inyecta via ConfigService de NestJS.
7.1 Variables de Entorno - Proveedores de Generación
| Variable | Descripción | Default |
|---|---|---|
OPENAI_API_KEY | API key de OpenAI | Requerido |
OPENAI_DEFAULT_MODEL | Modelo de generación OpenAI | gpt-4o |
OPENAI_MAX_TOKENS | Tokens máximos de respuesta OpenAI | 4000 |
OPENAI_TEMPERATURE | Temperatura de generación OpenAI | 0.7 |
ANTHROPIC_API_KEY | API key de Anthropic | Requerido |
CLAUDE_DEFAULT_MODEL | Modelo de generación Claude | claude-sonnet-4-5-20250929 |
CLAUDE_MAX_TOKENS | Tokens máximos de respuesta Claude | 4000 |
CLAUDE_TEMPERATURE | Temperatura de generación Claude | 0.7 |
7.2 Variables de Entorno - Vision
| Variable | Descripción | Default |
|---|---|---|
VISION_PROVIDER_DEFAULT | Provider de vision por defecto | auto |
VISION_AUTO_FALLBACK | Habilitar fallback automático | true |
VISION_FALLBACK_ORDER | Orden de fallback (separado por comas) | openai,claude,local |
VISION_MAX_IMAGE_SIZE_MB | Tamano máximo de imagen en MB | 10 |
VISION_OPENAI_ENABLED | Habilitar OpenAI Vision | true |
OPENAI_VISION_MODEL | Modelo de vision OpenAI | gpt-4o |
VISION_CLAUDE_ENABLED | Habilitar Claude Vision | true |
CLAUDE_VISION_MODEL | Modelo de vision Claude | claude-sonnet-4-5-20250929 |
VISION_LOCAL_ENABLED | Habilitar procesamiento local | true |
VISION_LOCAL_QUALITY | Calidad de extracción local | 5 |
VISION_LOCAL_COLOR_COUNT | Cantidad de colores a extraer (local) | 64 |
VISION_LOCAL_MAX_IMAGE_SIZE | Tamano max imagen local (px) | 800 |
7.3 Variables de Entorno - Cache y Cuotas
| Variable | Descripción | Default |
|---|---|---|
AI_CACHE_ENABLED | Habilitar cache de generación | true |
AI_CACHE_TTL | TTL del cache en segundos | 3600 |
Las cuotas se configuran directamente en ai.config.ts bajo la clave quotas (ver sección 4.1).
7.4 Estructura del Modulo
src/modules/ai-generation/
ai-generation.module.ts # Modulo NestJS
ai-generation.controller.ts # Endpoints REST
ai-generation.service.ts # Servicio principal de generación
cache.service.ts # Cache Redis para generaciones
quota.service.ts # Control de cuotas por plan
dto/
generate-from-prompt.dto.ts # DTO para generación desde prompt
generate-from-design.dto.ts # DTO para generación desde diseño
modify-invitation.dto.ts # DTO para modificación conversacional
generation-result.dto.ts # DTO de respuesta
interfaces/
vision-provider.interface.ts # Interfaz para proveedores de vision
providers/
ai-provider.interface.ts # Interfaz común de proveedores IA
openai.provider.ts # Proveedor OpenAI (generación + colores)
claude.provider.ts # Proveedor Claude (generación + colores)
openai-vision.provider.ts # Proveedor OpenAI Vision
claude-vision.provider.ts # Proveedor Claude Vision
local-vision.provider.ts # Proveedor local (node-vibrant)
prompts/
invitation-system-prompt.ts # System prompt para generación
schemas/
invitation-schema.zod.ts # Schema Zod de validación
validation.service.ts # Servicio de validación de respuestas
services/
design-extraction.service.ts # Extracción de contexto de diseño
enrich-prompt.service.ts # Enriquecimiento de prompt con evento
vision-provider.service.ts # Orquestador de proveedores de vision
7.5 Endpoints Disponibles
| Metodo | Endpoint | Descripción | Auth |
|---|---|---|---|
POST | /ai-generation/generate | Generar invitación desde prompt | ClerkAuth |
POST | /ai-generation/generate-from-design | Generar desde imagen de referencia | ClerkAuth |
POST | /ai-generation/modify | Modificar invitación existente con IA | ClerkAuth |
GET | /ai-generation/generations/:id | Obtener detalle de generación | ClerkAuth |
GET | /ai-generation/generations | Listar generaciones (páginado) | ClerkAuth |
GET | /ai-generation/quota | Consultar cuota de la organización | ClerkAuth |