From 6e1b6ca3d788625f554311aca5b87f5de374fc09 Mon Sep 17 00:00:00 2001 From: Daniel Onyejesi Date: Wed, 25 Mar 2026 17:35:30 -0400 Subject: [PATCH] Wire physician memories/templates into all AI generation routes Previously only well-visit and sick-visit used saved physician templates. Now HPI encounter, HPI dictation, SOAP, and hospital course all fetch getUserMemoryContext() and pass physicianMemories to the backend so the AI learns from saved templates/preferences. --- public/js/hospitalCourse.js | 39 +++++++++++++++++------------- public/js/liveEncounter.js | 25 +++++++++++-------- public/js/soap.js | 27 ++++++++++++--------- public/js/voiceDictation.js | 47 ++++++++++++++++++++---------------- src/routes/hospitalCourse.js | 5 +++- src/routes/hpi.js | 14 ++++++++--- src/routes/soap.js | 7 ++++-- 7 files changed, 98 insertions(+), 66 deletions(-) diff --git a/public/js/hospitalCourse.js b/public/js/hospitalCourse.js index d6e0829..46e3541 100644 --- a/public/js/hospitalCourse.js +++ b/public/js/hospitalCourse.js @@ -134,23 +134,28 @@ showLoading('Generating hospital course...'); - fetch('/api/generate-hospital-course', { - method: 'POST', - headers: getAuthHeaders(), - body: JSON.stringify({ - notes: notes, - edNote: edNote, - hAndP: hAndP, - labs: labs, - patientAge: document.getElementById('hc-age').value, - patientGender: document.getElementById('hc-gender').value, - pmh: document.getElementById('hc-pmh').value, - setting: document.getElementById('hc-setting').value, - los: document.getElementById('hc-los').value, - formatPreference: document.getElementById('hc-format').value, - additionalInstructions: document.getElementById('hc-instructions').value, - model: getSelectedModel() - }) + var memoriesPromise = (typeof getUserMemoryContext === 'function') ? getUserMemoryContext() : Promise.resolve(''); + + memoriesPromise.then(function(memCtx) { + return fetch('/api/generate-hospital-course', { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify({ + notes: notes, + edNote: edNote, + hAndP: hAndP, + labs: labs, + patientAge: document.getElementById('hc-age').value, + patientGender: document.getElementById('hc-gender').value, + pmh: document.getElementById('hc-pmh').value, + setting: document.getElementById('hc-setting').value, + los: document.getElementById('hc-los').value, + formatPreference: document.getElementById('hc-format').value, + additionalInstructions: document.getElementById('hc-instructions').value, + physicianMemories: memCtx || null, + model: getSelectedModel() + }) + }); }) .then(function(r) { return r.json(); }) .then(function(data) { diff --git a/public/js/liveEncounter.js b/public/js/liveEncounter.js index b770627..20a1c4d 100644 --- a/public/js/liveEncounter.js +++ b/public/js/liveEncounter.js @@ -137,16 +137,21 @@ if (!text) { showToast('No transcript', 'error'); return; } showLoading('Generating HPI...'); - fetch('/api/generate-hpi-encounter', { - method: 'POST', - headers: getAuthHeaders(), - body: JSON.stringify({ - transcript: text, - patientAge: document.getElementById('enc-age').value, - patientGender: document.getElementById('enc-gender').value, - setting: document.getElementById('enc-setting').value, - model: getSelectedModel() - }) + var memoriesPromise = (typeof getUserMemoryContext === 'function') ? getUserMemoryContext() : Promise.resolve(''); + + memoriesPromise.then(function(memCtx) { + return fetch('/api/generate-hpi-encounter', { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify({ + transcript: text, + patientAge: document.getElementById('enc-age').value, + patientGender: document.getElementById('enc-gender').value, + setting: document.getElementById('enc-setting').value, + physicianMemories: memCtx || null, + model: getSelectedModel() + }) + }); }) .then(function(r) { return r.json(); }) .then(function(data) { diff --git a/public/js/soap.js b/public/js/soap.js index f42ce1e..45fa8a3 100644 --- a/public/js/soap.js +++ b/public/js/soap.js @@ -90,17 +90,22 @@ showLoading('Generating SOAP note...'); - fetch('/api/generate-soap', { - method: 'POST', - headers: getAuthHeaders(), - body: JSON.stringify({ - transcript: text, - patientAge: document.getElementById('soap-age').value, - patientGender: document.getElementById('soap-gender').value, - type: document.getElementById('soap-type').value, - additionalInstructions: document.getElementById('soap-instructions').value, - model: getSelectedModel() - }) + var memoriesPromise = (typeof getUserMemoryContext === 'function') ? getUserMemoryContext() : Promise.resolve(''); + + memoriesPromise.then(function(memCtx) { + return fetch('/api/generate-soap', { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify({ + transcript: text, + patientAge: document.getElementById('soap-age').value, + patientGender: document.getElementById('soap-gender').value, + type: document.getElementById('soap-type').value, + additionalInstructions: document.getElementById('soap-instructions').value, + physicianMemories: memCtx || null, + model: getSelectedModel() + }) + }); }) .then(function(r) { return r.json(); }) .then(function(data) { diff --git a/public/js/voiceDictation.js b/public/js/voiceDictation.js index f8c5b68..1e05511 100644 --- a/public/js/voiceDictation.js +++ b/public/js/voiceDictation.js @@ -134,29 +134,34 @@ var outputType = document.getElementById('dict-output-type').value; var endpoint, bodyData; - if (outputType === 'soap-full' || outputType === 'soap-subjective') { - endpoint = '/api/generate-soap'; - bodyData = { - transcript: text, - patientAge: document.getElementById('dict-age').value, - patientGender: document.getElementById('dict-gender').value, - type: outputType === 'soap-full' ? 'full' : 'subjective', - model: getSelectedModel() - }; - } else { - endpoint = '/api/generate-hpi-dictation'; - bodyData = { - transcript: text, - patientAge: document.getElementById('dict-age').value, - patientGender: document.getElementById('dict-gender').value, - setting: document.getElementById('dict-setting').value, - model: getSelectedModel() - }; - } - showLoading('Generating...'); - fetch(endpoint, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(bodyData) }) + var memoriesPromise = (typeof getUserMemoryContext === 'function') ? getUserMemoryContext() : Promise.resolve(''); + + memoriesPromise.then(function(memCtx) { + if (outputType === 'soap-full' || outputType === 'soap-subjective') { + endpoint = '/api/generate-soap'; + bodyData = { + transcript: text, + patientAge: document.getElementById('dict-age').value, + patientGender: document.getElementById('dict-gender').value, + type: outputType === 'soap-full' ? 'full' : 'subjective', + physicianMemories: memCtx || null, + model: getSelectedModel() + }; + } else { + endpoint = '/api/generate-hpi-dictation'; + bodyData = { + transcript: text, + patientAge: document.getElementById('dict-age').value, + patientGender: document.getElementById('dict-gender').value, + setting: document.getElementById('dict-setting').value, + physicianMemories: memCtx || null, + model: getSelectedModel() + }; + } + return fetch(endpoint, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(bodyData) }); + }) .then(function(r) { return r.json(); }) .then(function(data) { hideLoading(); diff --git a/src/routes/hospitalCourse.js b/src/routes/hospitalCourse.js index 9dc0498..023f55b 100644 --- a/src/routes/hospitalCourse.js +++ b/src/routes/hospitalCourse.js @@ -17,7 +17,8 @@ router.post('/generate-hospital-course', authMiddleware, async (req, res) => { los, // length of stay model, formatPreference, // 'auto' | 'prose' | 'dayByDay' | 'organSystem' - additionalInstructions + additionalInstructions, + physicianMemories } = req.body; if (!notes || notes.length === 0) { @@ -80,6 +81,8 @@ router.post('/generate-hospital-course', authMiddleware, async (req, res) => { prompt += `\n\nADDITIONAL INSTRUCTIONS FROM PHYSICIAN:\n${additionalInstructions}`; } + if (physicianMemories) clinicalData += '\n\n' + physicianMemories; + const result = await callAI([ { role: 'system', content: prompt }, { role: 'user', content: clinicalData } diff --git a/src/routes/hpi.js b/src/routes/hpi.js index ba7ac50..db167b8 100644 --- a/src/routes/hpi.js +++ b/src/routes/hpi.js @@ -7,14 +7,17 @@ const { authMiddleware } = require('../middleware/auth'); // HPI from encounter router.post('/generate-hpi-encounter', authMiddleware, async (req, res) => { try { - const { transcript, patientAge, patientGender, model, setting } = req.body; + const { transcript, patientAge, patientGender, model, setting, physicianMemories } = req.body; if (!transcript || !transcript.trim()) return res.status(400).json({ error: 'Transcript empty' }); const prompt = setting === 'inpatient' ? PROMPTS.hpiInpatient : PROMPTS.hpiEncounter; + var context = `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\nSetting: ${setting || 'outpatient'}\n\nTRANSCRIPT:\n${transcript}`; + if (physicianMemories) context += '\n\n' + physicianMemories; + const result = await callAI([ { role: 'system', content: prompt }, - { role: 'user', content: `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\nSetting: ${setting || 'outpatient'}\n\nTRANSCRIPT:\n${transcript}` } + { role: 'user', content: context } ], { model }); res.json({ success: true, hpi: result.content, model: result.model }); @@ -26,14 +29,17 @@ router.post('/generate-hpi-encounter', authMiddleware, async (req, res) => { // HPI from dictation router.post('/generate-hpi-dictation', authMiddleware, async (req, res) => { try { - const { transcript, patientAge, patientGender, model, setting } = req.body; + const { transcript, patientAge, patientGender, model, setting, physicianMemories } = req.body; if (!transcript || !transcript.trim()) return res.status(400).json({ error: 'Dictation empty' }); const prompt = setting === 'inpatient' ? PROMPTS.hpiInpatient : PROMPTS.hpiDictation; + var context = `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\nSetting: ${setting || 'outpatient'}\n\nDICTATION:\n${transcript}`; + if (physicianMemories) context += '\n\n' + physicianMemories; + const result = await callAI([ { role: 'system', content: prompt }, - { role: 'user', content: `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\nSetting: ${setting || 'outpatient'}\n\nDICTATION:\n${transcript}` } + { role: 'user', content: context } ], { model }); res.json({ success: true, hpi: result.content, model: result.model }); diff --git a/src/routes/soap.js b/src/routes/soap.js index 199b3cd..73580f3 100644 --- a/src/routes/soap.js +++ b/src/routes/soap.js @@ -6,7 +6,7 @@ const { authMiddleware } = require('../middleware/auth'); router.post('/generate-soap', authMiddleware, async (req, res) => { try { - const { transcript, patientAge, patientGender, model, type, additionalInstructions } = req.body; + const { transcript, patientAge, patientGender, model, type, additionalInstructions, physicianMemories } = req.body; if (!transcript || !transcript.trim()) return res.status(400).json({ error: 'Empty input' }); let prompt; @@ -20,9 +20,12 @@ router.post('/generate-soap', authMiddleware, async (req, res) => { prompt += `\n\nADDITIONAL INSTRUCTIONS:\n${additionalInstructions}`; } + var context = `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\n\nINPUT:\n${transcript}`; + if (physicianMemories) context += '\n\n' + physicianMemories; + const result = await callAI([ { role: 'system', content: prompt }, - { role: 'user', content: `Patient: ${patientAge || 'Unknown'}, ${patientGender || 'Unknown'}\n\nINPUT:\n${transcript}` } + { role: 'user', content: context } ], { model }); res.json({ success: true, soap: result.content, model: result.model });