feat: Add Vision Agents (RxVision and DocumentIntelligence)
Build Curio HMS / build-and-deploy (push) Successful in 1m6s
Details
Build Curio HMS / build-and-deploy (push) Successful in 1m6s
Details
This commit is contained in:
parent
8619ddbdcf
commit
7f27c206b5
|
|
@ -4,6 +4,8 @@ const TriageAgent = require('./TriageAgent');
|
||||||
const FollowUpAgent = require('./FollowUpAgent');
|
const FollowUpAgent = require('./FollowUpAgent');
|
||||||
const InventoryAgent = require('./InventoryAgent');
|
const InventoryAgent = require('./InventoryAgent');
|
||||||
const CDSSAgent = require('./CDSSAgent');
|
const CDSSAgent = require('./CDSSAgent');
|
||||||
|
const RxVisionAgent = require('./RxVisionAgent');
|
||||||
|
const DocumentIntelligenceAgent = require('./DocumentIntelligenceAgent');
|
||||||
|
|
||||||
class AgentManager {
|
class AgentManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -13,6 +15,8 @@ class AgentManager {
|
||||||
this.registerAgent('FOLLOWUP', FollowUpAgent);
|
this.registerAgent('FOLLOWUP', FollowUpAgent);
|
||||||
this.registerAgent('INVENTORY', InventoryAgent);
|
this.registerAgent('INVENTORY', InventoryAgent);
|
||||||
this.registerAgent('CDSS', CDSSAgent);
|
this.registerAgent('CDSS', CDSSAgent);
|
||||||
|
this.registerAgent('RX_VISION', RxVisionAgent);
|
||||||
|
this.registerAgent('DOC_INTELLIGENCE', DocumentIntelligenceAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
const BaseAgent = require('./BaseAgent');
|
||||||
|
|
||||||
|
class DocumentIntelligenceAgent extends BaseAgent {
|
||||||
|
constructor() {
|
||||||
|
super('DocumentIntelligenceAgent');
|
||||||
|
this.responseMocks = {
|
||||||
|
'default': JSON.stringify({
|
||||||
|
documentType: 'LAB_REPORT',
|
||||||
|
patientName: 'Jane Doe',
|
||||||
|
date: '2026-05-26',
|
||||||
|
metrics: [
|
||||||
|
{ name: 'Fasting Blood Sugar', value: '110 mg/dL', status: 'BORDERLINE' },
|
||||||
|
{ name: 'Total Cholesterol', value: '240 mg/dL', status: 'HIGH' }
|
||||||
|
],
|
||||||
|
summary: 'Elevated cholesterol levels detected.'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(config, payload) {
|
||||||
|
const { documentUrl, documentTypeHint } = payload;
|
||||||
|
|
||||||
|
console.log(`[DocumentIntelligenceAgent] Processing document image/pdf: ${documentUrl}`);
|
||||||
|
|
||||||
|
const prompt = `
|
||||||
|
Act as an expert medical document intelligence system. Analyze the provided image or PDF.
|
||||||
|
Hint: This is likely a ${documentTypeHint}.
|
||||||
|
Extract the document type, patient name, date, and key metrics/values.
|
||||||
|
Flag any metrics that are out of normal ranges.
|
||||||
|
Return a JSON object: { "documentType": "...", "patientName": "...", "date": "...", "metrics": [{ "name", "value", "status" }], "summary": "..." }
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Simulate sending image to Vision API
|
||||||
|
const llmResponse = await this.mockLLMCall(prompt, this.responseMocks);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = JSON.parse(llmResponse);
|
||||||
|
console.log(`[DocumentIntelligenceAgent] Extracted ${result.metrics?.length || 0} metrics from ${result.documentType}.`);
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[DocumentIntelligenceAgent] Failed to parse Vision LLM response', e);
|
||||||
|
return { documentType: 'UNKNOWN', metrics: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new DocumentIntelligenceAgent();
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
const BaseAgent = require('./BaseAgent');
|
||||||
|
|
||||||
|
class RxVisionAgent extends BaseAgent {
|
||||||
|
constructor() {
|
||||||
|
super('RxVisionAgent');
|
||||||
|
this.responseMocks = {
|
||||||
|
'default': JSON.stringify({
|
||||||
|
medications: [
|
||||||
|
{ name: 'Amoxicillin', dosage: '500mg', frequency: '1-0-1', duration: '5 days' },
|
||||||
|
{ name: 'Paracetamol', dosage: '650mg', frequency: '1-1-1', duration: '3 days' }
|
||||||
|
],
|
||||||
|
doctorNotes: 'Drink plenty of fluids. Rest for 3 days.',
|
||||||
|
nextFollowUp: '2026-06-02'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(config, payload) {
|
||||||
|
const { imageUrl } = payload;
|
||||||
|
|
||||||
|
console.log(`[RxVisionAgent] Processing prescription image: ${imageUrl}`);
|
||||||
|
|
||||||
|
const prompt = `
|
||||||
|
Act as an expert medical OCR system. Analyze the provided image of a handwritten prescription.
|
||||||
|
Extract the medications, dosages, frequencies, and duration.
|
||||||
|
Also extract any general doctor notes and the next follow-up date.
|
||||||
|
Return a JSON object: { "medications": [{ "name", "dosage", "frequency", "duration" }], "doctorNotes": "...", "nextFollowUp": "YYYY-MM-DD" }
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Simulate sending image to Vision API
|
||||||
|
const llmResponse = await this.mockLLMCall(prompt, this.responseMocks);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = JSON.parse(llmResponse);
|
||||||
|
console.log(`[RxVisionAgent] Successfully extracted ${result.medications.length} medications.`);
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[RxVisionAgent] Failed to parse Vision LLM response', e);
|
||||||
|
return { medications: [], doctorNotes: '', nextFollowUp: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new RxVisionAgent();
|
||||||
|
|
@ -77,7 +77,7 @@ CREATE TABLE IF NOT EXISTS transactions (
|
||||||
CREATE TABLE IF NOT EXISTS agent_configs (
|
CREATE TABLE IF NOT EXISTS agent_configs (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
tenant_id TEXT REFERENCES tenants(id) ON DELETE CASCADE,
|
tenant_id TEXT REFERENCES tenants(id) ON DELETE CASCADE,
|
||||||
agent_type TEXT NOT NULL CHECK (agent_type IN ('BILLING', 'TRIAGE', 'FOLLOWUP', 'INVENTORY', 'CDSS')),
|
agent_type TEXT NOT NULL CHECK (agent_type IN ('BILLING', 'TRIAGE', 'FOLLOWUP', 'INVENTORY', 'CDSS', 'RX_VISION', 'DOC_INTELLIGENCE')),
|
||||||
is_active BOOLEAN DEFAULT false,
|
is_active BOOLEAN DEFAULT false,
|
||||||
config JSONB DEFAULT '{}',
|
config JSONB DEFAULT '{}',
|
||||||
created_at TIMESTAMPTZ DEFAULT now(),
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
|
@ -98,6 +98,8 @@ ALTER TABLE users ADD COLUMN IF NOT EXISTS q_and_a JSONB DEFAULT '[]';
|
||||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS blocked_dates JSONB DEFAULT '[]';
|
ALTER TABLE users ADD COLUMN IF NOT EXISTS blocked_dates JSONB DEFAULT '[]';
|
||||||
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_role_check;
|
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_role_check;
|
||||||
ALTER TABLE users ADD CONSTRAINT users_role_check CHECK (role IN ('SUPER_ADMIN','OWNER','DOCTOR','RECEPTIONIST','PHARMACIST','LAB_TECH','PATIENT'));
|
ALTER TABLE users ADD CONSTRAINT users_role_check CHECK (role IN ('SUPER_ADMIN','OWNER','DOCTOR','RECEPTIONIST','PHARMACIST','LAB_TECH','PATIENT'));
|
||||||
|
ALTER TABLE agent_configs DROP CONSTRAINT IF EXISTS agent_configs_agent_type_check;
|
||||||
|
ALTER TABLE agent_configs ADD CONSTRAINT agent_configs_agent_type_check CHECK (agent_type IN ('BILLING', 'TRIAGE', 'FOLLOWUP', 'INVENTORY', 'CDSS', 'RX_VISION', 'DOC_INTELLIGENCE'));
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// ── Seed super admin ─────────────────────────────────────────────────────────
|
// ── Seed super admin ─────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,28 @@
|
||||||
</div>
|
</div>
|
||||||
<p class="text-muted" style="font-size:0.875rem;">Analyzes prescriptions against patient history to warn doctors of drug-drug interactions.</p>
|
<p class="text-muted" style="font-size:0.875rem;">Analyzes prescriptions against patient history to warn doctors of drug-drug interactions.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="bill-card" style="flex-direction:column; align-items:flex-start;">
|
||||||
|
<div style="display:flex; justify-content:space-between; width:100%; margin-bottom:0.5rem;">
|
||||||
|
<strong>📷 Prescription Vision Parser</strong>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="agent-RX_VISION" onchange="toggleAgent('RX_VISION', this.checked)">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted" style="font-size:0.875rem;">Automatically converts handwritten prescription photos into digital, structured medication lists.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bill-card" style="flex-direction:column; align-items:flex-start;">
|
||||||
|
<div style="display:flex; justify-content:space-between; width:100%; margin-bottom:0.5rem;">
|
||||||
|
<strong>📄 Document Intelligence</strong>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="agent-DOC_INTELLIGENCE" onchange="toggleAgent('DOC_INTELLIGENCE', this.checked)">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted" style="font-size:0.875rem;">Extracts data from uploaded lab reports and medical documents into structured records.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue