use indexed assistant prompt examples

This commit is contained in:
Daniel 2026-05-08 08:44:34 +02:00
parent c2ac647e29
commit dfaf8f15db
6 changed files with 24 additions and 116 deletions

View file

@ -485,7 +485,7 @@
<script type="module" src="/js/chartReview.js"></script>
<script type="module" src="/js/soap.js"></script>
<script type="module" src="/js/milestones.js"></script>
<script defer src="/js/peGuide.js"></script>
<script type="module" src="/js/peGuide.js"></script>
<script type="module" src="/js/extensions.js"></script>
<script type="module" src="/js/notes.js"></script>
<script type="module" src="/js/diagrams.js"></script>

View file

@ -15,8 +15,6 @@
// step array and produces a Technique + Findings narrative.
// ============================================================
(function () {
// ────────────────────────────────────────────────────────────
// GRADING SCALES — universal reference shown at top of each system
// ────────────────────────────────────────────────────────────
@ -1710,5 +1708,3 @@
if (s == null) return '';
return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
})();

View file

@ -44,73 +44,6 @@ var GREETING_RE = /^(hi|hello|hey|yo|good\s+(morning|afternoon|evening)|thanks|t
var MAX_SAVED_CHATS_PER_USER = 100;
var MAX_SAVED_CHAT_PAYLOAD = 250000;
var MAX_SAVED_CHAT_TITLE = 160;
var EXAMPLE_CANDIDATES = [
{ label: 'Status asthma escalation', prompt: 'In a 4-year-old with acute wheeze, when should magnesium sulfate be considered and what dose is recommended?' },
{ label: 'Febrile neonate', prompt: 'What initial workup and empiric antibiotics are recommended for a well-appearing febrile neonate?' },
{ label: 'Sepsis vasoactives', prompt: 'In pediatric septic shock, when should fluid boluses be limited and vasoactives started?' },
{ label: 'Toxic ingestion', prompt: 'How should an unknown pediatric ingestion be initially assessed and when is activated charcoal appropriate?' },
{ label: 'Meningitis antibiotics', prompt: 'What empiric antibiotics are recommended for suspected bacterial meningitis by pediatric age group?' },
{ label: 'Sickle fever', prompt: 'How should fever in a child with sickle cell disease be evaluated and treated?' },
{ label: 'Head injury CT', prompt: 'Which pediatric head injury features should prompt CT imaging or ED observation?' },
{ label: 'Anaphylaxis IM epi', prompt: 'What is the recommended IM epinephrine dose for pediatric anaphylaxis and when should it be repeated?' },
{ label: 'Dehydration fluids', prompt: 'How should dehydration severity guide oral rehydration versus IV fluids in children?' },
{ label: 'Neonatal jaundice', prompt: 'Which neonatal jaundice risk factors change phototherapy thresholds or urgency?' },
{ label: 'UTI imaging', prompt: 'When should children with febrile UTI receive renal ultrasound or further imaging?' },
{ label: 'Kawasaki workup', prompt: 'What clinical and laboratory features support incomplete Kawasaki disease evaluation?' },
{ label: 'Intussusception', prompt: 'What are the red flags, diagnostic steps, and reduction approach for suspected intussusception?' },
{ label: 'NAT red flags', prompt: 'What injury patterns and history features should raise concern for non-accidental trauma?' },
{ label: 'Status epilepticus', prompt: 'Outline first- and second-line treatment for pediatric status epilepticus with typical dosing.' },
{ label: 'Croup escalation', prompt: 'When should a child with croup receive nebulized epinephrine, and how long should they be observed?' },
{ label: 'Bilious vomiting', prompt: 'What are the red flags for bilious vomiting in neonates, and what immediate workup is recommended?' },
{ label: 'Bronchiolitis oxygen', prompt: 'What supportive care and oxygen/admission criteria are recommended for infant bronchiolitis?' },
{ label: 'DKA cerebral edema', prompt: 'What warning signs suggest cerebral edema during pediatric DKA treatment, and what immediate treatment is recommended?' },
{ label: 'Neonatal resuscitation', prompt: 'Summarize the first minute steps in neonatal resuscitation and when positive pressure ventilation is indicated.' }
];
var TOPIC_SUGGESTIONS = {
asthma: [
'How should acute pediatric asthma exacerbation severity guide SABA frequency, ipratropium, steroids, magnesium sulfate, and disposition?',
'When should magnesium sulfate, continuous albuterol, noninvasive ventilation, ICU transfer, or intubation be considered in status asthmaticus?',
'How can bronchiolitis, viral-induced wheeze, and early asthma be distinguished in infants and preschool children?',
'What discharge criteria, observation period, relapse risks, and follow-up are recommended after an ED asthma exacerbation?',
'When should controller therapy be started or stepped up after an ED asthma visit?'
],
bronchiolitis: [
'What supportive care, suctioning, hydration, oxygen targets, and feeding guidance are recommended for infant bronchiolitis?',
'When is a bronchodilator trial reasonable in bronchiolitis, and when should it be stopped?',
'What apnea risk, work of breathing, oxygen saturation, hydration, and social factors support admission for bronchiolitis?',
'How can bronchiolitis be distinguished from early asthma, pneumonia, cardiac disease, or foreign body aspiration?',
'When should high-flow nasal cannula, CPAP, ICU transfer, or escalation be considered in bronchiolitis?'
],
fever: [
'How should fever without source be evaluated by age group in neonates, young infants, and older children?',
'What cultures, inflammatory markers, LP decisions, empiric antibiotics, and disposition are recommended for febrile neonates?',
'Which clinical and laboratory features stratify risk for serious bacterial infection in febrile infants?',
'When is lumbar puncture indicated or avoidable in febrile infants by age and risk category?',
'How should fever be approached in immunocompromised children, central lines, or incomplete immunization?'
],
seizure: [
'What is the timed pediatric status epilepticus algorithm including benzodiazepine dosing and second-line choices?',
'How should simple versus complex febrile seizures be evaluated, treated, and explained to caregivers?',
'When should levetiracetam, fosphenytoin, phenobarbital, valproate, anesthetic infusion, or ICU transfer be used?',
'Which seizure presentations require neuroimaging, labs, toxicology, LP, EEG, or admission?',
'What common seizure mimics in children should be considered and how are they distinguished?'
],
croup: [
'How should croup severity guide dexamethasone, nebulized epinephrine, observation, and disposition?',
'When is nebulized epinephrine indicated for croup and how long should the child be observed afterward?',
'What dexamethasone dose and route are recommended for mild, moderate, and severe croup?',
'What discharge, admission, ICU, and airway escalation criteria apply after croup treatment?',
'What alternative diagnoses should be considered in a child with stridor or atypical croup?'
],
dehydration: [
'Which clinical signs best estimate mild, moderate, and severe dehydration in children?',
'What oral rehydration protocol, volumes, antiemetic use, and reassessment are recommended for gastroenteritis?',
'When are IV boluses, maintenance fluids, deficit replacement, glucose, or electrolyte checks indicated?',
'How should hypernatremic dehydration be recognized and corrected safely?',
'What discharge, admission, and follow-up criteria apply after pediatric gastroenteritis or dehydration?'
]
};
var promptPool = createClinicalPromptPool({
redisCache: redisCache,
callAI: callAI,
@ -118,9 +51,7 @@ var promptPool = createClinicalPromptPool({
semanticSearch: semanticSearch,
dedupeSources: dedupeSources,
normalizeMcpSearchResponse: normalizeMcpSearchResponse,
getIndexedTopicExamples: getIndexedTopicExamples,
exampleCandidates: EXAMPLE_CANDIDATES,
topicSuggestions: TOPIC_SUGGESTIONS
getIndexedTopicExamples: getIndexedTopicExamples
});
function positiveInt(value, fallback) {
@ -386,18 +317,6 @@ async function prepareAssistantChat(body) {
}
var history = Array.isArray(body.history) ? body.history.slice(-8) : [];
var contextualHistory = priorClinicalHistory(history, message);
var suggestions = getTopicSuggestions(message);
if (!contextualHistory.length && suggestions.length > 0 && message.split(/\s+/).length < 4) {
return { direct: {
success: true,
answer: buildSuggestionAnswer(message, suggestions),
suggestions: suggestions,
sources: [],
model: null,
search: { skipped: true, reason: 'topic_suggestions' }
} };
}
var searchQuery = await rewriteSearchQuery(message, history, chatModel).catch(function(e) {
console.warn('[clinical-assistant] query rewrite skipped:', e.message);
@ -503,13 +422,6 @@ function needsContextualRewrite(message) {
return words.length <= 8 || /\b(it|this|that|they|them|he|she|dose|dosing|how much|what about|next|admit|discharge|criteria|side effects?|contraindications?|monitor|monitoring)\b/i.test(text);
}
function priorClinicalHistory(history, message) {
var latest = String(message || '').trim();
return (Array.isArray(history) ? history : []).filter(function(m) {
return m && (m.role === 'user' || m.role === 'assistant') && m.content && String(m.content).trim() !== latest;
});
}
function deterministicFollowupQuery(message, history) {
var text = String(message || '').trim().toLowerCase();
if (!/^(dose|dosing|what dose|dose\?|how much|med dose|medication dose)$/i.test(text)) return '';
@ -716,22 +628,4 @@ function assistantErrorMessage(e) {
return msg || 'Assistant request failed';
}
function getTopicSuggestions(message) {
var normalized = String(message || '').toLowerCase().replace(/[^a-z0-9\s-]/g, ' ').replace(/\s+/g, ' ').trim();
if (!normalized) return [];
var direct = TOPIC_SUGGESTIONS[normalized];
if (direct) return direct;
var keys = Object.keys(TOPIC_SUGGESTIONS);
for (var i = 0; i < keys.length; i++) {
if (normalized.indexOf(keys[i]) !== -1) return TOPIC_SUGGESTIONS[keys[i]];
}
return [];
}
function buildSuggestionAnswer(topic, suggestions) {
return 'I can look up **' + topic + '**. Pick a specific clinical question so I retrieve the right cited pages instead of giving a broad summary:\n\n' +
suggestions.map(function(s) { return '- ' + s; }).join('\n') +
'\n\nOr type your own specific question, for example: "management of acute asthma exacerbation in a 6-year-old".';
}
module.exports = router;

View file

@ -41,10 +41,7 @@ function createClinicalPromptPool(opts) {
refreshIfNeeded(false).catch(function() {});
var examples = [];
rotateExamples(opts.exampleCandidates || [], now).slice(0, 9).forEach(function(item) {
examples.push({ label: item.label, prompt: item.prompt });
});
var examples = await fallbackIndexedExamples();
memoryCache = { expiresAt: now + cacheMs, examples: examples };
return examples;

View file

@ -0,0 +1,20 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const root = path.join(__dirname, '..');
function read(relativePath) {
return fs.readFileSync(path.join(root, relativePath), 'utf8');
}
test('clinical assistant starter prompts are Redis or indexed-source backed', () => {
const route = read('src/routes/clinicalAssistant.js');
const pool = read('src/utils/clinicalPromptPool.js');
assert.doesNotMatch(route, /EXAMPLE_CANDIDATES|TOPIC_SUGGESTIONS|topic_suggestions|buildSuggestionAnswer/);
assert.match(route, /createClinicalPromptPool\(\{[\s\S]*redisCache: redisCache/);
assert.match(pool, /opts\.redisCache\.getJson\(redisKey\)/);
assert.match(pool, /opts\.redisCache\.setJson\(redisKey, payload, ttlSeconds\)/);
assert.match(pool, /var examples = await fallbackIndexedExamples\(\)/);
});

View file

@ -20,6 +20,7 @@ const moduleEntrypoints = [
'public/js/milestones.js',
'public/js/nextcloud.js',
'public/js/notes.js',
'public/js/peGuide.js',
'public/js/sickVisit.js',
'public/js/soap.js',
'public/js/secureStorage.js',