118 lines
5.5 KiB
JavaScript
118 lines
5.5 KiB
JavaScript
/**
|
|
* ClinicAgent: An agentic orchestrator for Curio.
|
|
* It uses natural language understanding to map user requests to hospital tools.
|
|
*/
|
|
|
|
const patientManager = require('./patientManager');
|
|
const queueManager = require('./queueManager');
|
|
const pharmacyAgent = require('./pharmacyAgent');
|
|
const configManager = require('./configManager');
|
|
const Anthropic = require('@anthropic-ai/sdk');
|
|
|
|
const anthropic = new Anthropic({
|
|
apiKey: process.env.ANTHROPIC_API_KEY, // Defaults to process.env.ANTHROPIC_API_KEY
|
|
});
|
|
const LLM_MODEL = process.env.LLM_MODEL || 'claude-3-haiku-20240307';
|
|
|
|
class ClinicAgent {
|
|
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}.
|
|
|
|
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)
|
|
|
|
CRITICAL INSTRUCTIONS FOR ASKING:
|
|
- If the user hasn't specified a department, you MUST list the 4 available departments so they know what to choose. Do not make them guess!
|
|
- If they haven't specified a time, suggest common intervals (e.g. 10:00 AM, 11:00 AM, 6:00 PM).
|
|
|
|
If any booking info is missing, naturally ask the user using the instructions above. 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.
|
|
`;
|
|
}
|
|
|
|
async processMessage(phone, transcript) {
|
|
console.log(`[Agent] Processing for ${phone} via Claude`);
|
|
|
|
try {
|
|
const response = await anthropic.messages.create({
|
|
model: LLM_MODEL,
|
|
max_tokens: 300,
|
|
temperature: 0.2,
|
|
system: this.getSystemPrompt(),
|
|
messages: transcript
|
|
});
|
|
|
|
const replyContent = response.content[0].text.trim();
|
|
|
|
// Try to parse JSON intent
|
|
try {
|
|
const cleanJson = replyContent.replace(/```json/g, '').replace(/```/g, '').trim();
|
|
const intent = JSON.parse(cleanJson);
|
|
|
|
if (intent.action === 'BOOK') {
|
|
let timeVal = "10:00";
|
|
const timeMatch = intent.time.match(/(\d{1,2}:\d{2})/);
|
|
if (timeMatch) timeVal = timeMatch[1];
|
|
|
|
let dateVal = new Date().toISOString().split('T')[0];
|
|
if (intent.date && intent.date.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
dateVal = intent.date;
|
|
}
|
|
|
|
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 for ${dateVal} at ${timeVal}. Your token is ${result.token}. We look forward to seeing you!` };
|
|
} else {
|
|
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) {
|
|
// Not JSON, just regular conversational text
|
|
return { reply: replyContent };
|
|
}
|
|
|
|
return { reply: replyContent };
|
|
} catch (error) {
|
|
console.error('[ClinicAgent] LLM Error:', error.message);
|
|
return { reply: "I'm having trouble connecting to my AI brain right now. Please try again in a moment." };
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new ClinicAgent();
|