curaflow/backend/clinicAgent.js

114 lines
5.1 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)
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.
`;
}
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();