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>
This commit is contained in:
@@ -45,6 +45,11 @@ export class ApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Post-análisis: la app lee toda la conversación del lead y extrae los datos clave de una pasada.
|
||||||
|
async analizarConversacion(leadId: string): Promise<boolean> {
|
||||||
|
return this.post(`/api/leads/${leadId}/analizar`, {});
|
||||||
|
}
|
||||||
|
|
||||||
async buscarLeadPorTelefono(telefono: string): Promise<string | null> {
|
async buscarLeadPorTelefono(telefono: string): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${this.baseUrl}/api/leads/by-phone`, {
|
const { data } = await axios.get(`${this.baseUrl}/api/leads/by-phone`, {
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export class WhatsappService implements OnModuleInit, OnModuleDestroy {
|
|||||||
private readonly jidToLeadId = new Map<string, string>();
|
private readonly jidToLeadId = new Map<string, string>();
|
||||||
// contexto de lead por leadId
|
// contexto de lead por leadId
|
||||||
private readonly leadCache = new Map<string, LeadContext>();
|
private readonly leadCache = new Map<string, LeadContext>();
|
||||||
|
// leads cuya conversación ya se mandó a post-análisis (para no repetir).
|
||||||
|
private readonly leadsAnalizados = new Set<string>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly leadsService: LeadsService,
|
private readonly leadsService: LeadsService,
|
||||||
@@ -449,6 +451,20 @@ export class WhatsappService implements OnModuleInit, OnModuleDestroy {
|
|||||||
this.logger.log(`Lead ${ctx.leadId} persistido — estado=${nuevoEstado || ctx.botStep}`);
|
this.logger.log(`Lead ${ctx.leadId} persistido — estado=${nuevoEstado || ctx.botStep}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Al cerrar la cualificación, dispara el post-análisis de toda la conversación (una sola vez).
|
||||||
|
// Por estado (errático) O porque Luisa anuncia el presupuesto en su mensaje.
|
||||||
|
const cierre = ['presupuesto', 'fin_viable', 'fin_no_viable'];
|
||||||
|
const anunciaPresupuesto =
|
||||||
|
/presupuesto/i.test(respuesta) &&
|
||||||
|
/prepar|recib|enseguida|en un momento|te lo env|lo env|aqu[ií] mismo/i.test(respuesta);
|
||||||
|
if ((cierre.includes(ctx.botStep) || anunciaPresupuesto) && !this.leadsAnalizados.has(ctx.leadId)) {
|
||||||
|
this.leadsAnalizados.add(ctx.leadId);
|
||||||
|
this.api
|
||||||
|
.analizarConversacion(ctx.leadId)
|
||||||
|
.then((ok) => this.logger.log(`[ANALISIS] lead ${ctx.leadId}: ${ok ? 'ok' : 'fallo'}`))
|
||||||
|
.catch((e: any) => this.logger.error(`[ANALISIS] ${e.message}`));
|
||||||
|
}
|
||||||
|
|
||||||
await this.conversacionService.guardarMensaje(ctx.leadId, 'assistant', respuesta, {
|
await this.conversacionService.guardarMensaje(ctx.leadId, 'assistant', respuesta, {
|
||||||
botStep: ctx.botStep,
|
botStep: ctx.botStep,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user