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>
This commit is contained in:
Carlos Narro
2026-06-09 17:28:56 +02:00
parent 0a00d42553
commit a8b6d62dd6
4 changed files with 69 additions and 1 deletions

View File

@@ -45,6 +45,20 @@ export class ApiClient {
}
}
async buscarLeadPorTelefono(telefono: string): Promise<string | null> {
try {
const { data } = await axios.get(`${this.baseUrl}/api/leads/by-phone`, {
headers: this.headers,
params: { telefono },
});
return data?.leadId ?? null;
} catch (err: any) {
if (err.response?.status === 404) return null;
this.logger.error(`buscarLeadPorTelefono error: ${err.message}`);
return null;
}
}
async guardarConversacion(
leadId: string,
rol: 'user' | 'assistant' | 'system',

View File

@@ -171,6 +171,14 @@ export class WebhookListener implements OnApplicationBootstrap {
}
}
// Re-registra una sesión recuperada de la BD (cuando no estaba en memoria, p. ej. tras reinicio).
ensureSession(telefono: string, leadId: string, nombre = '') {
const tel = this.normTel(telefono);
if (!this.leadSessions.has(tel)) {
this.leadSessions.set(tel, { leadId, telefono: tel, nombre, jid: null });
}
}
private async handleWhatsappPdf(payload: { leadId: string; telefono: string; pdfBase64: string; filename: string }) {
this.logger.log(`[PDF] leadId=${payload.leadId}, filename=${payload.filename}`);
const { pdfEmitter } = await import('../whatsapp/whatsapp.service');

View File

@@ -263,7 +263,16 @@ export class WhatsappService implements OnModuleInit, OnModuleDestroy {
}
private async getOrCreateContext(telefono: string, jid: string): Promise<LeadContext | null> {
const leadId = this.webhookListener.getLeadIdByTelefono(telefono);
let leadId = this.webhookListener.getLeadIdByTelefono(telefono);
// Fallback: si no está en memoria (reinicio del bot), recuperarlo de la BD por teléfono.
if (!leadId) {
leadId = await this.api.buscarLeadPorTelefono(telefono);
if (leadId) {
this.webhookListener.ensureSession(telefono, leadId);
this.logger.log(`Lead ${leadId} recuperado por teléfono ${telefono} (sin sesión en memoria).`);
}
}
if (!leadId) {
this.logger.log(`Mensaje ignorado de ${telefono}: lead no registrado. Debe iniciarse desde la web.`);