platform-marketing-content/orchestration/directivas/DIRECTIVA-GENERACION-IA-PMC.md
rckrdmrd 74b5ed7f38 feat: Complete documentation update and orchestration configuration
- Update vision, architecture and technical documentation
- Update module definitions (PMC-001 to PMC-008)
- Update requirements documentation
- Add CONTEXT-MAP.yml and ENVIRONMENT-INVENTORY.yml
- Add orchestration guidelines and references

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:38:31 -06:00

14 KiB

Directiva: Generacion de Contenido IA - PMC

Version: 1.0.0 Fecha: 2025-12-08 Estado: Activa Modulo: PMC-004 Generation


Proposito

Define los patrones, convenciones y flujos para implementar el motor de generacion de contenido IA en PMC, incluyendo integracion con ComfyUI, gestion de workflows, modelos personalizados y colas de procesamiento.


Stack de Generacion

Imagenes:
  Motor: ComfyUI
  Modelo base: SDXL 1.0
  Extensiones:
    - ControlNet (poses, depth)
    - IP-Adapter (consistencia)
    - LoRA (personalizacion)
  Formato salida: PNG, WebP

Texto:
  API: OpenAI GPT-4 / Claude API
  Uso: Copys, hashtags, adaptacion de tono

Colas:
  Sistema: BullMQ + Redis
  Colas definidas:
    - generation:image (concurrency: 2)
    - generation:text (concurrency: 10)
    - generation:training (concurrency: 1)

WebSocket:
  Framework: Socket.io
  Eventos: progress, completed, failed

Arquitectura

┌─────────────────────────────────────────────────────────────┐
│                      Client (React)                          │
│                                                              │
│  1. Usuario configura generacion                             │
│  2. Submit POST /api/v1/generation/jobs                      │
│  3. Suscribe a WebSocket job:{jobId}                         │
│  4. Recibe eventos de progreso                               │
│  5. Muestra resultado al completar                           │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│                    Backend (NestJS)                          │
│                                                              │
│  GenerationController:                                       │
│    - Valida permisos (tenant, usuario)                       │
│    - Verifica quota del tenant                               │
│    - Valida inputs contra schema del workflow                │
│    - Crea registro GenerationJob                             │
│    - Encola en BullMQ                                        │
│    - Retorna jobId                                           │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│                Bull Processor (Worker)                       │
│                                                              │
│  ImageGenerationProcessor:                                   │
│    1. Actualiza status a "processing"                        │
│    2. Carga workflow template                                │
│    3. Inyecta parametros del usuario                         │
│    4. Carga LoRA de marca si aplica                          │
│    5. Envia a ComfyUI API                                    │
│    6. Escucha progreso via WebSocket                         │
│    7. Emite eventos al cliente                               │
│    8. Descarga imagenes resultado                            │
│    9. Crea Assets en storage                                 │
│   10. Actualiza job a "completed"                            │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│                    ComfyUI Server                            │
│                                                              │
│  Hardware: GPU NVIDIA 12-24GB VRAM                           │
│  Modelos cargados:                                           │
│    - sd_xl_base_1.0.safetensors                              │
│    - sd_xl_refiner_1.0.safetensors                           │
│    - ControlNets (canny, depth, openpose)                    │
│    - IP-Adapter                                              │
│    - LoRAs del tenant (cargados dinamicamente)               │
└─────────────────────────────────────────────────────────────┘

Workflows Predefinidos

WF-001: Product Photo Synthetic

ID: product_photo_synthetic
Proposito: Fotos de producto en contexto comercial
Tiempo estimado: 30-60 segundos

Inputs:
  - product_description: string (REQUERIDO)
  - reference_image: file (opcional)
  - background: enum [white, lifestyle, custom]
  - style: enum [minimalist, premium, casual]
  - lora_id: UUID (opcional, o autodetectar de marca)
  - seed: number (opcional)

Outputs:
  - 5 variaciones
  - 1024x1024 PNG
  - Fondo transparente disponible

Nodos ComfyUI:
  - CheckpointLoaderSimple (SDXL)
  - LoraLoader (si lora_id)
  - CLIPTextEncode (positive + negative)
  - KSampler
  - VAEDecode
  - RemoveBackground (si fondo transparente)
  - SaveImage

WF-002: Social Media Post

ID: social_media_post
Proposito: Imagen + copy para redes sociales
Tiempo estimado: 45-90 segundos

Inputs:
  - brief: object {objetivo, audiencia, tono}
  - product_id: UUID (opcional)
  - channel: enum [instagram, facebook, linkedin, tiktok]
  - format: enum [post, story, carousel]
  - brand_id: UUID

Outputs:
  - 3-5 variaciones de imagen
  - Copy sugerido por variacion
  - Hashtags recomendados

Proceso especial:
  1. Generar imagen con ComfyUI
  2. Llamar LLM para copy basado en imagen + brief
  3. Llamar LLM para hashtags

WF-003: Ad Variations

ID: ad_variations
Proposito: Variaciones para A/B testing
Tiempo estimado: Variable

Inputs:
  - base_image: asset_id o URL
  - variations_count: number (2-10)
  - variation_type: enum [color, background, composition]

Outputs:
  - N variaciones
  - Metadata de diferencias

WF-004: Virtual Avatar

ID: virtual_avatar
Proposito: Avatar/influencer virtual consistente
Tiempo estimado: 60-120 segundos

Inputs:
  - character_lora_id: UUID (REQUERIDO)
  - pose: enum [standing, sitting, walking, custom]
  - outfit: string
  - background: string
  - expression: enum [happy, serious, surprised, neutral]

Outputs:
  - Imagen del avatar
  - Consistencia facial garantizada

Nodos especiales:
  - IP-Adapter para consistencia
  - ControlNet OpenPose para pose

Flujos de Trabajo

Flujo: Crear Job de Generacion

// 1. Validar permisos
const canGenerate = await this.checkPermissions(user, tenant);
if (!canGenerate) throw new ForbiddenException();

// 2. Verificar quota
const hasQuota = await this.quotaService.check(tenant.id, 'generations');
if (!hasQuota) throw new PaymentRequiredException('Quota exceeded');

// 3. Cargar y validar workflow
const workflow = await this.workflowService.findById(dto.workflow_id);
this.validateInputs(dto.inputs, workflow.input_schema);

// 4. Inyectar contexto de marca si aplica
if (dto.brand_id) {
  dto.inputs = await this.injectBrandContext(dto.brand_id, dto.inputs);
}

// 5. Crear job en BD
const job = await this.jobRepository.save({
  tenant_id: tenant.id,
  user_id: user.id,
  workflow_id: workflow.id,
  status: 'queued',
  priority: this.calculatePriority(tenant),
  input_params: dto.inputs,
});

// 6. Encolar en Bull
await this.generationQueue.add('generate', {
  jobId: job.id,
  tenantId: tenant.id,
  workflowId: workflow.id,
  params: dto.inputs,
}, {
  priority: job.priority,
  attempts: 3,
  backoff: { type: 'exponential', delay: 5000 },
});

// 7. Incrementar uso
await this.quotaService.increment(tenant.id, 'generations');

return job;

Flujo: Procesar Job (Worker)

@Process('generate')
async handleGeneration(bullJob: Job<JobData>): Promise<void> {
  const { jobId, tenantId, workflowId, params } = bullJob.data;

  try {
    // 1. Marcar como procesando
    await this.updateStatus(jobId, 'processing');
    this.gateway.emit(jobId, 'started');

    // 2. Construir workflow ComfyUI
    const workflow = await this.buildComfyWorkflow(workflowId, params);

    // 3. Enviar a ComfyUI
    const promptId = await this.comfyUI.queuePrompt(workflow);

    // 4. Monitorear progreso
    await this.monitorProgress(promptId, jobId);

    // 5. Descargar resultados
    const images = await this.downloadResults(promptId);

    // 6. Crear assets
    const assetIds = await this.createAssets(tenantId, jobId, images);

    // 7. Completar job
    await this.completeJob(jobId, assetIds);
    this.gateway.emit(jobId, 'completed', { assets: assetIds });

  } catch (error) {
    await this.failJob(jobId, error.message);
    this.gateway.emit(jobId, 'failed', { error: error.message });
    throw error;
  }
}

Rate Limiting

Limites por Plan

Starter:
  generaciones_hora: 10
  generaciones_mes: 100
  entrenamiento_mes: 0
  modelos_custom: 0

Pro:
  generaciones_hora: 50
  generaciones_mes: 1000
  entrenamiento_mes: 5
  modelos_custom: 10

Business:
  generaciones_hora: 200
  generaciones_mes: 10000
  entrenamiento_mes: 20
  modelos_custom: 50

Enterprise:
  generaciones_hora: unlimited
  generaciones_mes: unlimited
  entrenamiento_mes: unlimited
  modelos_custom: unlimited

Implementacion

// Usar @CATALOG_RATELIMIT
@UseGuards(TenantThrottlerGuard)
@Throttle({ default: { ttl: 3600, limit: 50 } }) // Por defecto, ajustado por plan
@Post('jobs')
async createJob(...) { ... }

Modelos Personalizados (LoRAs)

Estructura de Almacenamiento

storage/
└── {tenant_slug}/
    └── models/
        ├── loras/
        │   └── {lora_name}.safetensors
        ├── checkpoints/
        └── embeddings/

Registro de Modelo

interface RegisterModelDto {
  name: string;
  type: 'lora' | 'checkpoint' | 'embedding';
  file: Express.Multer.File;
  trigger_word: string; // Para LoRAs
  brand_id?: string;
  preview_images?: Express.Multer.File[];
}

// Validaciones
- Tamano maximo: 2GB
- Formatos: .safetensors, .ckpt (solo checkpoint)
- Nombre unico por tenant

Carga Dinamica en ComfyUI

// Al construir workflow, si hay lora_id
if (params.lora_id) {
  const model = await this.modelService.findById(params.lora_id);

  // Agregar nodo LoraLoader al workflow
  workflow['lora_loader'] = {
    class_type: 'LoraLoader',
    inputs: {
      model: ['checkpoint', 0],
      clip: ['checkpoint', 1],
      lora_name: model.file_path,
      strength_model: params.lora_strength || 0.8,
      strength_clip: params.lora_strength || 0.8,
    }
  };

  // Redirigir conexiones
  workflow['sampler'].inputs.model = ['lora_loader', 0];
}

Eventos WebSocket

Eventos Emitidos

// Suscripcion
socket.emit('subscribe:job', jobId);

// Eventos recibidos
socket.on('generation:started', ({ jobId }) => {});
socket.on('generation:progress', ({ jobId, progress, step, total }) => {});
socket.on('generation:completed', ({ jobId, assets }) => {});
socket.on('generation:failed', ({ jobId, error }) => {});

Formato de Eventos

interface ProgressEvent {
  jobId: string;
  progress: number; // 0-100
  step: number;
  total: number;
  message?: string; // "Loading model...", "Sampling...", etc
}

interface CompletedEvent {
  jobId: string;
  assets: string[]; // Asset IDs
  duration: number; // milliseconds
}

interface FailedEvent {
  jobId: string;
  error: string;
  retryable: boolean;
}

Manejo de Errores

Errores Comunes

Error Causa Accion
QUOTA_EXCEEDED Limite mensual alcanzado Mostrar mensaje, sugerir upgrade
COMFYUI_UNAVAILABLE Servidor no responde Reintentar 3 veces, luego fallar
MODEL_NOT_FOUND LoRA no existe Verificar modelo antes de enviar
INVALID_WORKFLOW Workflow corrupto Notificar admin
OUT_OF_MEMORY GPU sin memoria Reducir batch o esperar

Estrategia de Reintentos

// Configuracion Bull
{
  attempts: 3,
  backoff: {
    type: 'exponential',
    delay: 5000, // 5s, 10s, 20s
  },
  removeOnComplete: 100,
  removeOnFail: 50,
}

Validaciones Obligatorias

Antes de Crear Job

  • Usuario autenticado
  • Usuario pertenece al tenant
  • Tenant tiene quota disponible
  • Workflow existe y esta activo
  • Inputs validos segun schema
  • LoRA existe si se especifica
  • Brand existe si se especifica

Despues de Completar Job

  • Imagenes descargadas correctamente
  • Assets creados en storage
  • Assets registrados en BD
  • Job actualizado a "completed"
  • Evento emitido via WebSocket
  • Quota incrementada

Referencias

  • Definicion modulo: docs/02-definicion-modulos/PMC-004-GENERATION.md
  • Requerimientos: docs/03-requerimientos/RF-PMC-004-GENERATION.md
  • User Stories: docs/05-user-stories/EPIC-004-GENERATION.md
  • ADR Motor: docs/97-adr/ADR-003-motor-generacion.md
  • ADR Cola: docs/97-adr/ADR-004-cola-tareas.md
  • Prompt Agente: orchestration/prompts/PROMPT-GENERATION-PMC.md
  • Catalogo RateLimit: shared/catalog/rate-limiting/
  • Catalogo WebSocket: shared/catalog/websocket/

Generado por: Requirements-Analyst Fecha: 2025-12-08