File size: 11,908 Bytes
9bc2f29 eed2ff1 9bc2f29 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
import type { Severity, ErrorCategory, Settings, PromptPreset, PromptSettings } from '@/types';
// ---- Class Name Utility ----
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// ---- Category Information ----
export const CATEGORY_INFO = {
medication: {
id: 'medication' as const,
label: 'Medication',
icon: 'π',
description: 'Dosage errors, drug interactions, contraindications',
},
measurement: {
id: 'measurement' as const,
label: 'Measurement',
icon: 'π',
description: 'Vital signs, lab values outside possible ranges',
},
logical: {
id: 'logical' as const,
label: 'Logical',
icon: 'π',
description: 'Temporal contradictions, diagnostic inconsistencies',
},
missing: {
id: 'missing' as const,
label: 'Missing Info',
icon: 'β',
description: 'Incomplete documentation, missing required elements',
},
terminology: {
id: 'terminology' as const,
label: 'Terminology',
icon: 'π',
description: 'Misspellings, ambiguous abbreviations',
},
} as const;
// ---- Severity Information ----
export const SEVERITY_INFO = {
critical: {
id: 'critical' as const,
label: 'Critical',
className: 'glass-critical',
textColor: 'text-[var(--critical-text)]',
bgColor: 'bg-[var(--critical-bg)]',
borderColor: 'border-[var(--critical-border)]',
glowClass: 'pulse-glow-critical',
},
warning: {
id: 'warning' as const,
label: 'Warning',
className: 'glass-warning',
textColor: 'text-[var(--warning-text)]',
bgColor: 'bg-[var(--warning-bg)]',
borderColor: 'border-[var(--warning-border)]',
glowClass: 'pulse-glow-warning',
},
suggestion: {
id: 'suggestion' as const,
label: 'Suggestion',
className: 'glass-suggestion',
textColor: 'text-[var(--suggestion-text)]',
bgColor: 'bg-[var(--suggestion-bg)]',
borderColor: 'border-[var(--suggestion-border)]',
glowClass: '',
},
} as const;
// ---- Default Prompt (user-editable portion) ----
export const DEFAULT_PROMPT = `You are an emergency medicine clinical safety reviewer analyzing a real patient's emergency department documentation. Your ONLY task is to identify CRITICAL patient safety errors β the kind that could cause direct harm if missed.
FOCUS EXCLUSIVELY on these error types:
1. CONTRAINDICATED_MEDICATION β A prescribed drug that is dangerous given the patient's diagnosis, allergies, or concurrent medications (e.g., Amiodarone in WPW, penicillin with documented allergy, NSAID with active GI bleeding).
2. DANGEROUS_DOSAGE β Medication dose significantly outside the therapeutic range β 2x or more above maximum, clearly subtherapeutic, or wrong frequency that changes total daily dose dangerously (e.g., Metoprolol 500mg instead of 50mg).
3. CLINICAL_SCORE_ERROR β Risk stratification scores (CHAβDSβ-VASc, NIHSS, Wells, HEART, GCS, etc.) are miscalculated, leading to a wrong treatment decision.
4. MISSING_CRITICAL_TREATMENT β A life-saving medication or intervention is clearly indicated by the diagnosis but completely absent from the treatment plan.
5. TREATMENT_LOGIC_FAILURE β The treatment plan directly contradicts the diagnosis or clinical findings (e.g., patient discharged when admission is clearly required).
6. MISSING_CRITICAL_WORKUP β Diagnostic tests urgently indicated by the clinical presentation are not ordered (e.g., no troponin in chest pain, no CT in suspected PE/stroke).
STRICT RULES:
- Report AT MOST 3 errors, strictly prioritized by patient safety impact.
- Only report errors you are β₯80% confident about.
- Do NOT report: style preferences, minor documentation gaps, formatting issues, or speculative concerns.
- If the clinical note has no critical safety errors, return an empty errors array.
- Less is more β a false alarm wastes physician time and erodes trust.`;
export const STRICT_PROMPT = `You are a rigorous clinical safety auditor. Analyze emergency department documentation with the highest standards. ONLY flag issues that represent genuine, immediate patient safety threats.
FOCUS EXCLUSIVELY on these error types:
1. CONTRAINDICATED_MEDICATION β Only flag drugs with clear, documented contraindications (allergy, organ failure, dangerous interaction).
2. DANGEROUS_DOSAGE β Only flag doses that are β₯2x above maximum or clearly subtherapeutic for a critical condition.
3. CLINICAL_SCORE_ERROR β Only flag score miscalculations that directly change the treatment decision.
4. MISSING_CRITICAL_TREATMENT β Only flag omissions of life-saving interventions that are standard of care.
5. TREATMENT_LOGIC_FAILURE β Only flag treatment plans that directly contradict the diagnosis.
6. MISSING_CRITICAL_WORKUP β Only flag urgently indicated tests that are completely absent.
ULTRA-STRICT RULES:
- Report AT MOST 2 errors, only the most critical.
- Only report errors you are β₯90% confident about.
- When in doubt, do NOT flag it. Zero false positives is the goal.
- If no clear safety errors exist, return an empty errors array.`;
export const VERBOSE_PROMPT = `You are a comprehensive clinical documentation reviewer for emergency department notes. Perform a thorough analysis identifying all potential patient safety issues.
Review these error categories in detail:
1. CONTRAINDICATED_MEDICATION β Check all prescribed drugs against documented allergies, diagnoses, organ function, and concurrent medications for dangerous interactions or contraindications.
2. DANGEROUS_DOSAGE β Verify all medication dosages against standard therapeutic ranges, weight-based dosing, renal/hepatic adjustments, and frequency schedules.
3. CLINICAL_SCORE_ERROR β Recalculate all risk stratification scores (CHAβDSβ-VASc, NIHSS, Wells, HEART, GCS, CURB-65, etc.) and verify they match the documented values and resulting treatment decisions.
4. MISSING_CRITICAL_TREATMENT β Cross-reference the diagnosis with standard treatment protocols to identify any omitted life-saving medications or interventions.
5. TREATMENT_LOGIC_FAILURE β Analyze the treatment plan for internal contradictions with the diagnosis, clinical findings, and documented assessments.
6. MISSING_CRITICAL_WORKUP β Review the clinical presentation against standard diagnostic algorithms to identify any urgently indicated tests not ordered.
RULES:
- Report up to 3 errors, prioritized by patient safety impact.
- Only report errors you are β₯80% confident about.
- Provide detailed explanations with specific clinical reasoning for each finding.
- Include specific recommendations for corrective action.`;
// ---- MedGemma Backend Prompt (read-only display in frontend) ----
export const MEDGEMMA_BACKEND_PROMPT = `You are an emergency medicine clinical safety reviewer analyzing a real patient's emergency department documentation. Your ONLY task is to identify CRITICAL patient safety errors β the kind that could cause direct harm if missed.
FOCUS EXCLUSIVELY on these error types:
1. CONTRAINDICATED_MEDICATION
A prescribed drug that is dangerous given the patient's diagnosis, allergies, or concurrent medications (e.g., Amiodarone in WPW, penicillin with documented allergy, NSAID with active GI bleeding).
2. DANGEROUS_DOSAGE
Medication dose significantly outside the therapeutic range β 2x or more above maximum, clearly subtherapeutic, or wrong frequency that changes total daily dose dangerously (e.g., Metoprolol 500mg instead of 50mg, Furosemide 1x1 when 3x1 needed).
3. CLINICAL_SCORE_ERROR
Risk stratification scores (CHAβDSβ-VASc, NIHSS, Wells, HEART, GCS, etc.) are miscalculated, leading to a wrong treatment decision (e.g., CHAβDSβ-VASc scored 1 when it should be 2 β patient denied anticoagulation).
4. MISSING_CRITICAL_TREATMENT
A life-saving medication or intervention is clearly indicated by the diagnosis but completely absent from the treatment plan (e.g., no aspirin/antiplatelet in STEMI, no anticoagulation for high-risk AF, no IV fluids in severe dehydration).
5. TREATMENT_LOGIC_FAILURE
The treatment plan directly contradicts the diagnosis or clinical findings (e.g., patient discharged when admission is clearly required, antibiotics stopped too early in active sepsis, no reperfusion in acute MI).
6. MISSING_CRITICAL_WORKUP
Diagnostic tests urgently indicated by the clinical presentation are not ordered (e.g., no troponin in chest pain, no CT in suspected PE/stroke, no imaging for acute abdomen, no blood cultures in sepsis).
STRICT RULES:
- Report AT MOST 3 errors, strictly prioritized by patient safety impact.
- Only report errors you are β₯80% confident about.
- Do NOT report: style preferences, minor documentation gaps, formatting issues, findings that are "could be improved" but not directly dangerous, or speculative concerns.
- If the clinical note has no critical safety errors, return an empty errors array.
- Less is more β a false alarm wastes physician time and erodes trust.
Output: Valid JSON with "errors" array and "summary" string. Each error has: type, severity, quote, problem, recommendation, confidence.`;
// ---- Built-in Prompt Presets ----
export const BUILT_IN_PRESETS: PromptPreset[] = [
{
id: 'default',
name: 'Default',
prompt: DEFAULT_PROMPT,
isBuiltIn: true,
},
{
id: 'strict',
name: 'Strict',
prompt: STRICT_PROMPT,
isBuiltIn: true,
},
{
id: 'verbose',
name: 'Verbose',
prompt: VERBOSE_PROMPT,
isBuiltIn: true,
},
];
// ---- Default Prompt Settings ----
export const DEFAULT_PROMPT_SETTINGS: PromptSettings = {
activePresetId: 'default',
customPrompt: DEFAULT_PROMPT,
savedPresets: [],
};
// ---- Default Settings ----
export const DEFAULT_SETTINGS: Settings = {
provider: 'local',
selectedModel: '',
temperature: 0.1,
confidenceThreshold: 0.7,
enabledSeverities: ['critical', 'warning', 'suggestion'] as Severity[],
enabledCategories: ['medication', 'measurement', 'logical', 'missing', 'terminology'] as ErrorCategory[],
promptSettings: DEFAULT_PROMPT_SETTINGS,
};
// ---- Format Confidence ----
export function formatConfidence(confidence: number): string {
return `${Math.round(confidence * 100)}%`;
}
// ---- Format Duration ----
export function formatDuration(ms: number): string {
if (ms < 1000) {
return `${ms}ms`;
}
const seconds = ms / 1000;
if (seconds < 60) {
return `${seconds.toFixed(1)}s`;
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.round(seconds % 60);
return `${minutes}m ${remainingSeconds}s`;
}
// ---- Truncate Text ----
export function truncateText(text: string, maxLength: number): string {
if (text.length <= maxLength) return text;
return text.slice(0, maxLength - 3) + '...';
}
// ---- Generate Unique ID ----
export function generateId(): string {
return Math.random().toString(36).substring(2, 11);
}
// ---- Debounce ----
export function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
// ---- Local Storage Helpers ----
export function getFromStorage<T>(key: string, defaultValue: T): T {
if (typeof window === 'undefined') return defaultValue;
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch {
return defaultValue;
}
}
export function setToStorage<T>(key: string, value: T): void {
if (typeof window === 'undefined') return;
try {
localStorage.setItem(key, JSON.stringify(value));
} catch {
// Storage might be full or disabled
}
}
|