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
  }
}