patient / services /warningService.js
aliroohan179's picture
first
5266fc5
import { generateResponse } from './llmClient.js';
import Warning, { WarningType, WarningSeverity } from '../models/Warning.js';
import Patient from '../models/Patient.js';
import dotenv from 'dotenv';
dotenv.config();
// Re-export enums for backward compatibility
export { WarningType, WarningSeverity };
class WarningService {
/**
* Get all warnings for a patient
*/
async getPatientWarnings(patientId, includeAcknowledged = false) {
const warnings = await Warning.findByPatient(patientId, includeAcknowledged);
return warnings.map(w => w.toResponse());
}
/**
* Get all unacknowledged warnings across all patients
*/
async getAllUnacknowledgedWarnings(limit = 50) {
const warnings = await Warning.findUnacknowledged(limit);
return warnings.map(w => w.toResponse());
}
/**
* Acknowledge a clinical warning
*/
async acknowledgeWarning(warningId, userId, notes = null) {
try {
const warning = await Warning.findById(warningId);
if (!warning) {
return null;
}
await warning.acknowledge(userId, notes);
return warning.toResponse();
} catch {
return null;
}
}
/**
* Create a new clinical warning
*/
async createWarning(warningData) {
const warning = new Warning(warningData);
await warning.save();
return warning.toResponse();
}
/**
* Delete all warnings for a patient
*/
async deletePatientWarnings(patientId) {
const result = await Warning.deleteMany({ patient_id: patientId });
return result.deletedCount;
}
/**
* Use AI to analyze patient data and generate clinical warnings
*/
async analyzePatientForWarnings(patientId, newMedication = null, newCondition = null) {
const patient = await Patient.findById(patientId);
if (!patient) {
return [];
}
// Build the analysis prompt
const medications = patient.medications || [];
const medNames = medications
.filter(m => typeof m === 'object')
.map(m => m.name || '');
let conditions = patient.medical_history || [];
if (newMedication) {
medNames.push(`${newMedication} (NEW)`);
}
if (newCondition) {
conditions = [...conditions, `${newCondition} (NEW)`];
}
const conditionsText = conditions.map(c => {
if (typeof c === 'string') return c;
return c.condition || 'Unknown';
}).join(', ');
const prompt = `You are a clinical decision support AI. Analyze this patient's data for potential clinical warnings.
PATIENT INFORMATION:
- Age: ${patient.age || 'Unknown'}
- Gender: ${patient.gender || 'Unknown'}
- Medical Conditions: ${conditionsText || 'None recorded'}
- Current Medications: ${medNames.join(', ') || 'None recorded'}
Analyze for:
1. DRUG INTERACTIONS - Check if any medications interact negatively with each other
2. CONTRAINDICATIONS - Check if any medications are contraindicated given the patient's conditions
3. ALLERGY RISKS - Common allergy cross-reactions
4. DOSAGE CONCERNS - Age-related dosage considerations
5. DUPLICATE THERAPY - Multiple drugs for the same purpose
Return a JSON array of warnings. Each warning should have:
- warning_type: one of "drug_interaction", "allergy", "contraindication", "abnormal_pattern", "dosage_alert", "duplicate_therapy"
- severity: one of "low", "medium", "high", "critical"
- title: short title (max 50 chars)
- description: detailed explanation
- related_medications: array of medication names involved
- related_conditions: array of conditions involved
- recommendation: suggested action
If there are no warnings, return an empty array [].
Return ONLY valid JSON, no markdown or other text.`;
try {
let responseText = await generateResponse(prompt);
responseText = responseText.trim();
// Remove markdown code blocks if present
if (responseText.startsWith('```')) {
responseText = responseText.split('```')[1];
if (responseText.startsWith('json')) {
responseText = responseText.substring(4);
}
}
responseText = responseText.trim();
const warningsData = JSON.parse(responseText);
if (!Array.isArray(warningsData)) {
return [];
}
// Create warnings in database
const createdWarnings = [];
for (const warningData of warningsData) {
try {
const warning = new Warning({
patient_id: patientId,
warning_type: warningData.warning_type || 'general',
severity: warningData.severity || 'medium',
title: (warningData.title || 'Clinical Warning').substring(0, 100),
description: warningData.description || '',
related_medications: warningData.related_medications || [],
related_conditions: warningData.related_conditions || [],
recommendations: warningData.recommendation ? [warningData.recommendation] : [],
source: 'ai_analysis'
});
await warning.save();
createdWarnings.push(warning.toResponse());
} catch (error) {
console.log(`Error creating warning: ${error.message}`);
continue;
}
}
return createdWarnings;
} catch (error) {
if (error instanceof SyntaxError) {
console.log(`JSON parse error: ${error.message}`);
} else {
console.log(`Error analyzing patient: ${error.message}`);
}
return [];
}
}
/**
* Get warning statistics
*/
async getWarningStats() {
return await Warning.getStats();
}
}
// Singleton instance
export const warningService = new WarningService();