Commit Graph

23 Commits

Author SHA1 Message Date
Carlos Narro
f6e0347143 Hace a Luisa cálida y servicial y elimina el rechazo de leads
El bot rechazaba leads con presupuesto bajo y sonaba frío/repetitivo. Ahora
Luisa nunca rechaza (el cierre siempre es positivo; la rentabilidad la valora
el reformista en el panel, no el agente) y tiene el tono del agente de voz:
simpática, variada y dispuesta a ayudar con referencias.

- leads.service: getSiguienteEstado tras presupuesto siempre fin_viable;
  evaluarViabilidad ya no filtra (informa viable=true).
- claude.service: relaja las reglas de la pasada de corrección (permite calidez,
  conectores, emoji suave, 2-3 líneas, variación) y quita el guard que tomaba
  "en qué puedo ayudarte" como frase de IA.
- prompts: reescribe el guion de Luisa (mensajes como ejemplos variables, ayuda
  con referencias de tamaño/materiales, sin rechazo) y elimina el bloque
  <DATOS_EXTRAIDOS>, que era código muerto contradictorio con el generador.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 17:20:52 +02:00
Carlos Narro
b0871b733c Paso de fotos + flujo cross-canal llamada→WhatsApp para el render
Bot: al cerrar la cualificación, Luisa pide una foto y entra en modo recogida;
al llegar la foto la sube como "antes" con perfilCompleto:true → dispara render +
presupuesto + entrega del PDF. Nuevo webhook /whatsapp-fotos para que, tras una
llamada, Luisa escriba al lead, referencie lo hablado y le pida las fotos
(reutiliza el mismo modo).

App: el webhook de Retell, tras el análisis de la llamada, llama a pedirFotosWhatsapp
(WHATSAPP_FOTOS_WEBHOOK_URL) con el contexto de la reforma.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 12:50:33 +02:00
Carlos Narro
166d52f46d Bot: dispara el post-análisis al cerrar la cualificación
Cuando la conversación llega al cierre (estado presupuesto/fin_*, o Luisa anuncia
que prepara/envía el presupuesto), el bot llama una vez a POST /api/leads/:id/analizar
para que la app capture todos los datos clave de la conversación de una pasada.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 11:56:05 +02:00
Carlos Narro
5004575768 Bot: markOnlineOnConnect=true para recibir mensajes tras reconectar
Con false, al reanudar la sesión guardada el dispositivo quedaba "no disponible"
y WhatsApp no le entregaba los mensajes entrantes (socket open pero inbound=0).
Con un escaneo fresco sí recibía (por el sync de emparejamiento). Marcando online
al conectar, WhatsApp entrega los mensajes también tras reconectar/redeploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:58:06 +02:00
Carlos Narro
e5be1220d8 Bot: resolver @lid al número real para casar el lead (mensajes entrantes)
Confirmado vía /debug: WhatsApp entrega los mensajes desde una dirección @lid
(p.ej. 239225534443615@lid), no desde el número. El bot tomaba el id del lid
como teléfono -> no casaba con ningún lead -> ignoraba el mensaje. Ahora
resolverTelefono() resuelve el @lid a número vía msg.key.remoteJidAlt o el mapa
LID->PN de Baileys antes de buscar el lead. Debug captura también remoteJidAlt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:44:00 +02:00
Carlos Narro
78079e9455 Bot: carpeta de sesión Baileys configurable + /debug captura todos los eventos
BAILEYS_AUTH_DIR permite arrancar una sesión limpia (QR fresco) sin perder la
persistencia (subcarpeta del volumen) — para re-vincular cuando WhatsApp deja
muerto el dispositivo tras varios reinicios. Y messages.upsert ahora registra
en /debug todos los eventos (incluido type != notify) antes de filtrar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:00:14 +02:00
Carlos Narro
8d565e5fb0 Bot: endpoint /debug para diagnosticar entrantes + estado de conexión
GET /debug (Basic auth, QR_TOKEN) devuelve el estado de la conexión de WhatsApp
y un anillo de los últimos mensajes entrantes (remoteJid real, fromMe, tipo) y
el resultado del matching lead↔teléfono. Para diagnosticar por qué el bot no
responde (conexión zombi vs formato de jid @lid vs no llega el mensaje).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:51:10 +02:00
Carlos Narro
a8b6d62dd6 Bot responde a mensajes entrantes: recupera lead por teléfono + fix matching
El bot no respondía a las réplicas del cliente: la sesión lead↔teléfono vivía
solo en memoria y no casaba (se pierde al reiniciar el contenedor). Ahora si no
está en memoria, getOrCreateContext busca el lead en la BD por teléfono vía un
EP nuevo GET /api/leads/by-phone (match por últimos 9 dígitos) y re-registra la
sesión. Aparte, los ids de modelo de Claude del bot estaban mal (-4-5 vs 4.5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:28:56 +02:00
Carlos Narro
0a00d42553 Bot: enviar apertura proactiva al recibir /whatsapp-start + fix clave teléfono
El funnel promete "te escribimos por WhatsApp" pero el bot solo registraba la
sesión y esperaba a que el cliente escribiera primero → no llegaba nada. Ahora
WhatsappService escucha un startEmitter y manda el mensaje de apertura de Luisa
al teléfono (verifica el número con onWhatsApp), persiste estadoWa/botStep y el
intento. Además normaliza la clave de teléfono a solo-dígitos en leadSessions
(antes "+34..." no casaba con los dígitos del jid entrante → ignoraba al cliente).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:18:10 +02:00
Carlos Narro
a740d08863 Seguridad /qr: HTTP Basic Auth con QR_TOKEN dedicado (no secreto en la URL)
Review de seguridad: autenticar por query string filtra el secreto (logs,
historial, Referer) y usaba la misma FUNNEL_API_KEY que autoriza la API.
Ahora /qr usa HTTP Basic (credencial en cabecera), un QR_TOKEN dedicado
distinto de FUNNEL_API_KEY, comparación en tiempo constante (timingSafeEqual
sobre hashes) y Referrer-Policy: no-referrer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:51:46 +02:00
Carlos Narro
a43e7a77be Bot: página /qr para vincular WhatsApp con QR escaneable
El QR de Baileys solo salía como ASCII en los logs (ilegible en Dokploy). Ahora
el WhatsappService empuja el QR al WebhookListener, que sirve GET /qr?key=
<FUNNEL_API_KEY> con el código como imagen (lib qrcode), autorrefresco y estado
"ya conectado". Añade dependencia qrcode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:46:06 +02:00
Carlos Narro
062a34c144 Sandbox de renders en el image-worker + fixes del pipeline
Sandbox web (/sandbox) servido por el worker, reusando los mismos servicios del
pipeline, para iterar prompts/modelos con una imagen y ver variaciones+score, y
guardar la config ganadora (aplica al worker al instante, persistida en volumen):
- SettingsService: store de config (system prompts + modelos) con defaults de
  prompts/*.txt + env y override persistido en /app/data (sobrevive a redeploys).
- /sandbox (HTML), GET /sandbox/config, POST /sandbox/render, POST /sandbox/save
  (auth Bearer FUNNEL_API_KEY). DOM seguro, sin innerHTML de contenido externo.
- prompt-builder/supervisor/image-generator aceptan overrides y leen de Settings.

Fixes del pipeline de generación:
- image-generator: pide modalities ['image','text'] y extrae la imagen de
  message.images[] (forma real de OpenRouter), no solo de content.
- main.ts: sube el límite de body a 30mb (las fotos en data URI rompían el 100kb).

Deja de versionar artefactos de build (dist/ + *.tsbuildinfo); .gitignore en
image-worker y Whatsapp-bot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:32:11 +02:00
Carlos Narro
d34925cd7f Prepara deploy de Luisa + image-worker: Dockerfiles + GET endpoints
- Dockerfiles multistage (node:20-alpine) + .dockerignore para mvp/Whatsapp-bot
  (expone 3000+3001, persiste prompts) y mvp/image-worker (expone 3001).
- Añade los 2 GET que el bot necesita y faltaban en la API:
  GET /api/leads/:id (estado del lead) y GET /api/leads/:id/conversacion (historial).
- Limpia el package.json/lock de la raíz (baileys colado por error; no es workspace).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 10:36:14 +02:00
unknown
25669f3008 configuracion de arquitectura y manejo de herramientas 2026-06-07 18:30:29 -04:00
unknown
fec365bb57 Configuracion de agente de whastapp paratrabajar con la estructura propuesta 2026-06-07 17:51:53 -04:00
unknown
aee82267d0 Configuracion de reglas de typescript 2026-06-03 23:14:53 -04:00
unknown
f082351b43 actualizacion de readme agente Luisa 2026-06-03 23:09:37 -04:00
unknown
e5c8956b64 Configuracion para guardar en base de datos 2026-06-02 23:11:46 -04:00
unknown
fc6a7044b0 Configurcion de personalidad 2026-06-02 23:07:34 -04:00
unknown
9c5e6bc7fa Configuracion de prompt Luisa 2026-06-02 22:48:59 -04:00
unknown
9a8f84ff37 Configuracion de prompts PENDIENTE 2026-06-02 10:24:02 -04:00
unknown
b1b2451429 Configuracion de prueba 2026-06-01 23:24:43 -04:00
unknown
ef78d9a14c Logia de agente de Whatsapp 2026-05-31 22:02:58 -04:00