mirror of
https://github.com/complexcaresolutions/whatsapp-bot.git
synced 2026-03-17 15:04:07 +00:00
Phase 1 implementation with all core modules: - Fastify webhook server with Meta signature validation - WhatsApp Cloud API client (send text/template/interactive, mark as read) - LLM abstraction layer with Claude provider (Haiku for speed) - BullMQ message processing pipeline (dedup, rate limiting) - Bot routing (MessageRouter, ConversationManager, EscalationManager) - Payload CMS integration (InteractionWriter via direct DB, RulesLoader, TemplateResolver) - Healthcare-safe system prompt with medical keyword detection - PM2 ecosystem config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
2.3 KiB
TypeScript
81 lines
2.3 KiB
TypeScript
import { getLogger } from '../lib/logger.js'
|
|
import type { ConversationManager } from './ConversationManager.js'
|
|
import type { WhatsAppClient } from '../whatsapp/WhatsAppClient.js'
|
|
|
|
const log = getLogger('escalation-manager')
|
|
|
|
export interface EscalationReason {
|
|
type: 'medical' | 'explicit_request' | 'rule_match' | 'sentiment' | 'repeated_question'
|
|
detail: string
|
|
}
|
|
|
|
export class EscalationManager {
|
|
constructor(
|
|
private conversationManager: ConversationManager,
|
|
private whatsappClient: WhatsAppClient,
|
|
) {}
|
|
|
|
async shouldEscalate(
|
|
_phone: string,
|
|
text: string,
|
|
isMedicalQuestion: boolean,
|
|
): Promise<EscalationReason | null> {
|
|
// Medical questions → always escalate
|
|
if (isMedicalQuestion) {
|
|
return { type: 'medical', detail: 'Medical content detected' }
|
|
}
|
|
|
|
// Explicit escalation requests
|
|
const escalationPhrases = [
|
|
'mitarbeiter',
|
|
'mensch',
|
|
'echte person',
|
|
'berater',
|
|
'agent',
|
|
'human',
|
|
'real person',
|
|
'sprechen',
|
|
'anrufen',
|
|
'rückruf',
|
|
'beschwerde',
|
|
'complaint',
|
|
]
|
|
const lower = text.toLowerCase()
|
|
const matchedPhrase = escalationPhrases.find((phrase) =>
|
|
lower.includes(phrase),
|
|
)
|
|
if (matchedPhrase) {
|
|
return {
|
|
type: 'explicit_request',
|
|
detail: `User requested human: "${matchedPhrase}"`,
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
async escalate(
|
|
phone: string,
|
|
reason: EscalationReason,
|
|
): Promise<void> {
|
|
await this.conversationManager.escalate(phone)
|
|
|
|
let message: string
|
|
switch (reason.type) {
|
|
case 'medical':
|
|
message =
|
|
'Ich verstehe, dass Sie eine medizinische Frage haben. Ich leite Sie an einen unserer Mitarbeiter weiter, der Ihnen besser helfen kann. Bitte haben Sie einen Moment Geduld.\n\nBei Notfällen rufen Sie bitte den Notruf 112 an.'
|
|
break
|
|
case 'explicit_request':
|
|
message =
|
|
'Ich verbinde Sie gerne mit einem Mitarbeiter. Bitte haben Sie einen Moment Geduld — wir melden uns schnellstmöglich bei Ihnen.'
|
|
break
|
|
default:
|
|
message =
|
|
'Ich leite Ihre Anfrage an einen Mitarbeiter weiter. Bitte haben Sie einen Moment Geduld.'
|
|
}
|
|
|
|
await this.whatsappClient.sendTextMessage(phone, message)
|
|
log.info({ phone, reason }, 'Conversation escalated to human agent')
|
|
}
|
|
}
|