Refine Claude WhatsApp agent: add empathy, dynamic dates, and cancellation intent
Build Curio HMS / build-and-deploy (push) Successful in 1m8s
Details
Build Curio HMS / build-and-deploy (push) Successful in 1m8s
Details
This commit is contained in:
parent
2b7cea1df3
commit
c55467a068
|
|
@ -15,21 +15,37 @@ const anthropic = new Anthropic({
|
|||
const LLM_MODEL = process.env.LLM_MODEL || 'claude-3-haiku-20240307';
|
||||
|
||||
class ClinicAgent {
|
||||
constructor() {
|
||||
this.systemPrompt = `
|
||||
You are 'Curio AI', the assistant for Curio Health.
|
||||
Your goal is to help patients book appointments.
|
||||
Be extremely concise, friendly, and natural. Do not use markdown.
|
||||
To book an appointment, you MUST collect:
|
||||
1. Department (e.g. Cardiology, Neurology, General)
|
||||
2. Date (Format as YYYY-MM-DD or today/tomorrow)
|
||||
3. Time (Format as HH:MM AM/PM)
|
||||
|
||||
If any of these 3 pieces of information are missing, naturally ask the user for them.
|
||||
Do NOT output JSON until you have ALL THREE pieces of information.
|
||||
getSystemPrompt() {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
return `
|
||||
You are 'Curio AI', the highly empathetic and intelligent medical assistant for Curio Health.
|
||||
Today's date is ${today}.
|
||||
|
||||
If you have all three pieces of information, you MUST reply with ONLY a JSON block like this (no other text):
|
||||
{"action": "BOOK", "department": "Cardiology", "date": "2026-05-26", "time": "10:00"}
|
||||
Your goal is to help patients book, cancel, or reschedule appointments, and answer basic clinic questions.
|
||||
Be extremely concise, warm, empathetic, and natural. Do not use markdown formatting.
|
||||
|
||||
AVAILABLE CLINICS/DEPARTMENTS:
|
||||
- Cardiology (Dr. Sharma)
|
||||
- General Medicine (Apollo)
|
||||
- Pediatrics
|
||||
- Orthopedics
|
||||
|
||||
INTENT 1: BOOKING
|
||||
To book an appointment, you MUST collect:
|
||||
1. Department/Clinic
|
||||
2. Date (Format as YYYY-MM-DD)
|
||||
3. Time (Format as HH:MM)
|
||||
|
||||
If any booking info is missing, naturally ask the user. Do NOT output JSON until you have ALL THREE pieces.
|
||||
If you have all three, reply with ONLY JSON:
|
||||
{"action": "BOOK", "department": "Cardiology", "date": "${today}", "time": "10:00"}
|
||||
|
||||
INTENT 2: CANCEL
|
||||
If they want to cancel, ask them to confirm the date and time of the appointment they want to cancel. Once confirmed, reply with ONLY JSON:
|
||||
{"action": "CANCEL", "date": "${today}", "time": "10:00"}
|
||||
|
||||
INTENT 3: GENERAL QUERY
|
||||
If they ask general questions (e.g., location, hours), just answer naturally as the assistant. If they express pain or worry, respond with empathy before helping them.
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +57,7 @@ class ClinicAgent {
|
|||
model: LLM_MODEL,
|
||||
max_tokens: 300,
|
||||
temperature: 0.2,
|
||||
system: this.systemPrompt,
|
||||
system: this.getSystemPrompt(),
|
||||
messages: transcript
|
||||
});
|
||||
|
||||
|
|
@ -49,29 +65,36 @@ class ClinicAgent {
|
|||
|
||||
// Try to parse JSON intent
|
||||
try {
|
||||
// Remove potential markdown code blocks if the LLM wrapped it
|
||||
const cleanJson = replyContent.replace(/```json/g, '').replace(/```/g, '').trim();
|
||||
const intent = JSON.parse(cleanJson);
|
||||
|
||||
if (intent.action === 'BOOK') {
|
||||
// Extract HH:MM
|
||||
let timeVal = "10:00"; // fallback
|
||||
let timeVal = "10:00";
|
||||
const timeMatch = intent.time.match(/(\d{1,2}:\d{2})/);
|
||||
if (timeMatch) timeVal = timeMatch[1];
|
||||
|
||||
// Parse date
|
||||
let dateVal = new Date().toISOString().split('T')[0];
|
||||
if (intent.date && intent.date.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
||||
dateVal = intent.date;
|
||||
}
|
||||
|
||||
// Book the token using Dr. Sharma's Cardiology ("sharma-clinic")
|
||||
// In a real system, we'd map intent.department to tenantId
|
||||
const result = await queueManager.bookOnline(dateVal, timeVal, phone, 'sharma-clinic');
|
||||
let tenantId = 'sharma-clinic'; // Default
|
||||
if (intent.department && intent.department.toLowerCase().includes('general')) tenantId = 'apollo-hospitals';
|
||||
|
||||
const result = await queueManager.bookOnline(dateVal, timeVal, phone, tenantId);
|
||||
if (result.success) {
|
||||
return { reply: `Awesome! Your appointment for ${intent.department} is booked. Your token is ${result.token}. You should receive a confirmation message shortly.` };
|
||||
return { reply: `Awesome! Your appointment for ${intent.department} is booked for ${dateVal} at ${timeVal}. Your token is ${result.token}. We look forward to seeing you!` };
|
||||
} else {
|
||||
return { reply: `Sorry, ${result.message}` };
|
||||
return { reply: `I'm so sorry, but ${result.message.toLowerCase()} Would you like to try a different time or day?` };
|
||||
}
|
||||
} else if (intent.action === 'CANCEL') {
|
||||
let dateVal = intent.date || new Date().toISOString().split('T')[0];
|
||||
let timeVal = intent.time || "10:00";
|
||||
const result = await queueManager.cancelBooking(dateVal, timeVal, 'sharma-clinic');
|
||||
if (result.success) {
|
||||
return { reply: `Done. I've cancelled your appointment for ${dateVal} at ${timeVal}. Let me know if you need to book a new one!` };
|
||||
} else {
|
||||
return { reply: `Hmm, I couldn't find a booking for ${dateVal} at ${timeVal} to cancel. Could you double-check the time for me?` };
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue