Lleva las preferencias del cliente (estilo, color, material) al render

Hasta ahora el render solo se condicionaba con tipo/m²/calidad + notas de texto
libre por zona; lo que el cliente decía hablando con Luisa o en la llamada
(estilo, colores, materiales) se guardaba en estilo/tasteText pero NO viajaba al
generador de imagen, así que el render no lo representaba.

- b2c (perfil.ts): el payload de PERFIL_WEBHOOK_URL incluye ahora
  preferencias:{estilo, gustos} (gustos = tasteText). Claves vacías se omiten.
- worker (webhook.dto): nuevo PreferenciasDto opcional.
- worker (prompt-builder): construirUserContent (función pura) inyecta el estilo
  y los gustos del cliente como bloque dedicado y omite el "modern" por defecto
  cuando hay preferencias; el system prompt prioriza colores/materiales del
  cliente sobre un estilo genérico.
- worker (pipeline): enhebra preferencias hasta generarPrompt.
- worker (sandbox): acepta estilo/gustos para poder probarlos.
- docs/arquitectura-integracion: documenta el campo preferencias.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Carlos Narro
2026-06-10 18:17:45 +02:00
parent f6e0347143
commit ad87e45892
7 changed files with 88 additions and 15 deletions

View File

@@ -31,7 +31,7 @@ export class PipelineService {
}
async procesarLead(dto: PerfilCompletoDto): Promise<void> {
const { leadId, reforma, zonas } = dto;
const { leadId, reforma, zonas, preferencias } = dto;
const zonasConFotos = zonas.filter((z) => z.fotos.antes.length > 0);
const zonasSaltadas = zonas.filter((z) => z.fotos.antes.length === 0);
@@ -45,7 +45,7 @@ export class PipelineService {
for (const zona of zonasConFotos) {
try {
const render = await this.procesarZona(leadId, zona.zona, reforma, zona.notas, zona.fotos.antes[0]);
const render = await this.procesarZona(leadId, zona.zona, reforma, zona.notas, zona.fotos.antes[0], preferencias);
renders.push(render);
} catch (err: any) {
this.logger.error(`[${leadId}] Zona ${zona.zona}: error fatal: ${err.message}`);
@@ -76,8 +76,9 @@ export class PipelineService {
reforma: PerfilCompletoDto['reforma'],
notas: string[],
fotoAntes: string,
preferencias?: PerfilCompletoDto['preferencias'],
): Promise<ZonaRender> {
const prompt = await this.promptBuilder.generarPrompt(reforma.tipo, reforma.m2Suelo, reforma.calidad, notas);
const prompt = await this.promptBuilder.generarPrompt(reforma.tipo, reforma.m2Suelo, reforma.calidad, notas, preferencias);
this.logger.log(`[${leadId}] Zona ${zona}: prompt generado`);
let ultimaImagen: string | null = null;