← back to AbramsOS
lib/bp-meds.js
73 lines
// bp-meds.js — deterministic classifier: does an active medication affect blood pressure?
//
// Drug pharmacology is NEVER guessed by an LLM here — it's a curated map of well-known
// generic stems / drug names to their BP effect. Matching is substring on the lowercased
// name + generic_name. This powers the read-only "meds that affect your BP" context on
// /health so a BP trend can be read alongside what the person actually takes.
//
// effect: 'lowers' — antihypertensives (taken to bring BP down)
// 'raises' — can elevate BP as a side effect (NSAIDs, decongestants, stimulants)
// This is context, NOT medical advice.
// Explicit generic/brand names (highest confidence).
const NAMED = [
// ACE inhibitors / ARBs
['lisinopril', 'lowers', 'ACE inhibitor'], ['enalapril', 'lowers', 'ACE inhibitor'],
['ramipril', 'lowers', 'ACE inhibitor'], ['benazepril', 'lowers', 'ACE inhibitor'],
['losartan', 'lowers', 'ARB'], ['valsartan', 'lowers', 'ARB'], ['olmesartan', 'lowers', 'ARB'],
['telmisartan', 'lowers', 'ARB'], ['irbesartan', 'lowers', 'ARB'],
// Beta-blockers
['metoprolol', 'lowers', 'beta-blocker'], ['atenolol', 'lowers', 'beta-blocker'],
['propranolol', 'lowers', 'beta-blocker'], ['carvedilol', 'lowers', 'beta-blocker'],
['bisoprolol', 'lowers', 'beta-blocker'], ['labetalol', 'lowers', 'beta-blocker'], ['nadolol', 'lowers', 'beta-blocker'],
// Calcium channel blockers
['amlodipine', 'lowers', 'calcium channel blocker'], ['nifedipine', 'lowers', 'calcium channel blocker'],
['diltiazem', 'lowers', 'calcium channel blocker'], ['verapamil', 'lowers', 'calcium channel blocker'],
// Diuretics
['hydrochlorothiazide', 'lowers', 'diuretic'], ['hctz', 'lowers', 'diuretic'],
['chlorthalidone', 'lowers', 'diuretic'], ['furosemide', 'lowers', 'diuretic'],
['spironolactone', 'lowers', 'diuretic'], ['triamterene', 'lowers', 'diuretic'],
// Other antihypertensives
['clonidine', 'lowers', 'antihypertensive'], ['hydralazine', 'lowers', 'antihypertensive'],
['doxazosin', 'lowers', 'alpha-blocker'], ['prazosin', 'lowers', 'alpha-blocker'], ['terazosin', 'lowers', 'alpha-blocker'],
// Can RAISE BP
['ibuprofen', 'raises', 'NSAID'], ['naproxen', 'raises', 'NSAID'], ['celecoxib', 'raises', 'NSAID'],
['indomethacin', 'raises', 'NSAID'], ['meloxicam', 'raises', 'NSAID'], ['diclofenac', 'raises', 'NSAID'], ['ketorolac', 'raises', 'NSAID'],
['pseudoephedrine', 'raises', 'decongestant'], ['phenylephrine', 'raises', 'decongestant'],
['prednisone', 'raises', 'corticosteroid'], ['methylprednisolone', 'raises', 'corticosteroid'],
['amphetamine', 'raises', 'stimulant'], ['methylphenidate', 'raises', 'stimulant'], ['venlafaxine', 'raises', 'SNRI (dose-dependent)'],
];
// Suffix stems (catch generics not explicitly listed). Anchored to word end to limit false hits.
const STEMS = [
[/\w{3,}pril\b/, 'lowers', 'ACE inhibitor'],
[/\w{3,}sartan\b/, 'lowers', 'ARB'],
[/\w{3,}olol\b/, 'lowers', 'beta-blocker'],
[/\w{3,}dipine\b/, 'lowers', 'calcium channel blocker'],
];
// Classify one medication → { effect, klass } or null.
function classify(med) {
const hay = `${(med.name || '')} ${(med.generic_name || '')}`.toLowerCase();
for (const [name, effect, klass] of NAMED) {
if (hay.includes(name)) return { effect, klass, matched: name };
}
for (const [re, effect, klass] of STEMS) {
const m = hay.match(re);
if (m) return { effect, klass, matched: m[0] };
}
return null;
}
// Given a list of active medication rows, return only the BP-relevant ones tagged.
function bpRelevant(meds) {
const out = [];
for (const m of meds) {
const c = classify(m);
if (c) out.push({ name: m.name, generic_name: m.generic_name, person: m.person_name || null, ...c });
}
return out;
}
module.exports = { classify, bpRelevant };