Spaces:
Sleeping
Sleeping
| // Form configuration for all sepsis prediction input fields | |
| // Organized by category with metadata for dynamic form generation | |
| export interface ValidationRange { | |
| normal: { min: number; max: number }; // Normal range | |
| warning: { min: number; max: number }; // Warning range (show yellow) | |
| critical: { min: number; max: number }; // Critical range (show red) | |
| } | |
| export interface FieldConfig { | |
| name: string; | |
| label: string; | |
| type: 'number' | 'select' | 'text'; | |
| unit?: string; | |
| hasMinMax?: boolean; // If true, generates _min and _max fields IN PAYLOAD, but shows single input | |
| options?: { value: string; label: string }[]; | |
| required?: boolean; | |
| placeholder?: string; | |
| step?: string; | |
| validation?: ValidationRange; | |
| } | |
| export interface CategoryConfig { | |
| id: string; | |
| label: string; | |
| icon: string; // lucide icon name | |
| description: string; | |
| fields: FieldConfig[]; | |
| } | |
| export const formCategories: CategoryConfig[] = [ | |
| { | |
| id: 'demographics', | |
| label: 'Patient Demographics', | |
| icon: 'User', | |
| description: 'Basic patient information and identifiers', | |
| fields: [ | |
| { | |
| name: 'age', label: 'Age', type: 'number', unit: 'years', required: true, placeholder: '65', | |
| validation: { normal: { min: 18, max: 100 }, warning: { min: 0, max: 120 }, critical: { min: 0, max: 150 } } | |
| }, | |
| { | |
| name: 'f0_', label: 'Gender', type: 'select', required: true, options: [ | |
| { value: 'M', label: 'Male' }, | |
| { value: 'F', label: 'Female' } | |
| ] | |
| }, | |
| { | |
| name: 'height', label: 'Height', type: 'number', unit: 'cm', placeholder: '170', | |
| validation: { normal: { min: 100, max: 220 }, warning: { min: 50, max: 250 }, critical: { min: 30, max: 300 } } | |
| }, | |
| ] | |
| }, | |
| { | |
| id: 'vitals', | |
| label: 'Vital Signs', | |
| icon: 'Activity', | |
| description: 'Core vital sign measurements', | |
| fields: [ | |
| { | |
| name: 'heart_rate', label: 'Heart Rate', type: 'number', unit: 'bpm', hasMinMax: true, | |
| validation: { normal: { min: 60, max: 100 }, warning: { min: 40, max: 150 }, critical: { min: 20, max: 250 } } | |
| }, | |
| { | |
| name: 'sbp', label: 'Systolic BP', type: 'number', unit: 'mmHg', hasMinMax: true, | |
| validation: { normal: { min: 90, max: 140 }, warning: { min: 70, max: 180 }, critical: { min: 40, max: 260 } } | |
| }, | |
| { | |
| name: 'dbp', label: 'Diastolic BP', type: 'number', unit: 'mmHg', hasMinMax: true, | |
| validation: { normal: { min: 60, max: 90 }, warning: { min: 40, max: 120 }, critical: { min: 20, max: 180 } } | |
| }, | |
| { | |
| name: 'mbp', label: 'Mean Arterial Pressure', type: 'number', unit: 'mmHg', hasMinMax: true, | |
| validation: { normal: { min: 70, max: 100 }, warning: { min: 50, max: 130 }, critical: { min: 30, max: 180 } } | |
| }, | |
| { | |
| name: 'resp_rate', label: 'Respiratory Rate', type: 'number', unit: '/min', hasMinMax: true, | |
| validation: { normal: { min: 12, max: 20 }, warning: { min: 8, max: 35 }, critical: { min: 4, max: 60 } } | |
| }, | |
| { | |
| name: 'temperature', label: 'Temperature', type: 'number', unit: '°C', hasMinMax: true, step: '0.1', | |
| validation: { normal: { min: 36, max: 37.5 }, warning: { min: 35, max: 40 }, critical: { min: 30, max: 45 } } | |
| }, | |
| { | |
| name: 'spo2', label: 'SpO2', type: 'number', unit: '%', hasMinMax: true, | |
| validation: { normal: { min: 95, max: 100 }, warning: { min: 88, max: 100 }, critical: { min: 50, max: 100 } } | |
| }, | |
| { | |
| name: 'glucose', label: 'Glucose', type: 'number', unit: 'mg/dL', hasMinMax: true, | |
| validation: { normal: { min: 70, max: 140 }, warning: { min: 40, max: 300 }, critical: { min: 10, max: 600 } } | |
| }, | |
| ] | |
| }, | |
| { | |
| id: 'labs', | |
| label: 'Laboratory Results', | |
| icon: 'Beaker', | |
| description: 'Complete blood count and chemistry panel', | |
| fields: [ | |
| { | |
| name: 'wbc', label: 'WBC', type: 'number', unit: 'K/µL', hasMinMax: true, | |
| validation: { normal: { min: 4, max: 11 }, warning: { min: 1, max: 25 }, critical: { min: 0, max: 100 } } | |
| }, | |
| { | |
| name: 'platelet', label: 'Platelets', type: 'number', unit: 'K/µL', hasMinMax: true, | |
| validation: { normal: { min: 150, max: 400 }, warning: { min: 50, max: 600 }, critical: { min: 0, max: 1000 } } | |
| }, | |
| { | |
| name: 'hemoglobin', label: 'Hemoglobin', type: 'number', unit: 'g/dL', hasMinMax: true, | |
| validation: { normal: { min: 12, max: 17 }, warning: { min: 7, max: 20 }, critical: { min: 3, max: 25 } } | |
| }, | |
| { name: 'neutrophils_abs', label: 'Neutrophils (Abs)', type: 'number', unit: 'K/µL', hasMinMax: true }, | |
| { name: 'bands', label: 'Bands', type: 'number', unit: '%', hasMinMax: true }, | |
| { name: 'immature_granulocytes', label: 'Immature Granulocytes', type: 'number', unit: '%', hasMinMax: true }, | |
| { name: 'lymphocytes_abs', label: 'Lymphocytes (Abs)', type: 'number', unit: 'K/µL', hasMinMax: true }, | |
| { name: 'fibrinogen', label: 'Fibrinogen', type: 'number', unit: 'mg/dL', hasMinMax: true }, | |
| { | |
| name: 'inr', label: 'INR', type: 'number', hasMinMax: true, step: '0.1', | |
| validation: { normal: { min: 0.8, max: 1.2 }, warning: { min: 0.5, max: 5 }, critical: { min: 0, max: 10 } } | |
| }, | |
| { name: 'pt', label: 'PT', type: 'number', unit: 'sec', hasMinMax: true }, | |
| { name: 'antibiotic_count', label: 'Antibiotic Count', type: 'number', placeholder: '0' }, | |
| ] | |
| }, | |
| { | |
| id: 'bloodgas', | |
| label: 'Blood Gas Analysis', | |
| icon: 'Wind', | |
| description: 'Arterial blood gas and oxygenation parameters', | |
| fields: [ | |
| { name: 'so2', label: 'SaO2', type: 'number', unit: '%', hasMinMax: true }, | |
| { name: 'po2', label: 'PaO2', type: 'number', unit: 'mmHg', hasMinMax: true }, | |
| { name: 'pco2', label: 'PaCO2', type: 'number', unit: 'mmHg', hasMinMax: true }, | |
| { name: 'fio2', label: 'FiO2', type: 'number', unit: '%', hasMinMax: true }, | |
| { name: 'pfratio', label: 'P/F Ratio', type: 'number', hasMinMax: true }, | |
| { | |
| name: 'ventilation_flag', label: 'On Ventilation', type: 'select', options: [ | |
| { value: '0', label: 'No' }, | |
| { value: '1', label: 'Yes' } | |
| ] | |
| }, | |
| { | |
| name: 'ph', label: 'pH', type: 'number', hasMinMax: true, step: '0.01', | |
| validation: { normal: { min: 7.35, max: 7.45 }, warning: { min: 7.1, max: 7.6 }, critical: { min: 6.8, max: 7.8 } } | |
| }, | |
| { name: 'baseexcess', label: 'Base Excess', type: 'number', unit: 'mEq/L', hasMinMax: true }, | |
| { name: 'bicarbonate', label: 'Bicarbonate', type: 'number', unit: 'mEq/L', hasMinMax: true }, | |
| { name: 'totalco2', label: 'Total CO2', type: 'number', unit: 'mEq/L', hasMinMax: true }, | |
| { | |
| name: 'lactate', label: 'Lactate', type: 'number', unit: 'mmol/L', hasMinMax: true, | |
| validation: { normal: { min: 0.5, max: 2 }, warning: { min: 0, max: 4 }, critical: { min: 0, max: 20 } } | |
| }, | |
| ] | |
| }, | |
| { | |
| id: 'electrolytes', | |
| label: 'Electrolytes', | |
| icon: 'Droplets', | |
| description: 'Serum electrolyte panel', | |
| fields: [ | |
| { | |
| name: 'sodium', label: 'Sodium', type: 'number', unit: 'mEq/L', hasMinMax: true, | |
| validation: { normal: { min: 136, max: 145 }, warning: { min: 120, max: 160 }, critical: { min: 100, max: 180 } } | |
| }, | |
| { | |
| name: 'potassium', label: 'Potassium', type: 'number', unit: 'mEq/L', hasMinMax: true, step: '0.1', | |
| validation: { normal: { min: 3.5, max: 5 }, warning: { min: 2.5, max: 6.5 }, critical: { min: 1.5, max: 8 } } | |
| }, | |
| { name: 'chloride', label: 'Chloride', type: 'number', unit: 'mEq/L', hasMinMax: true }, | |
| { name: 'calcium', label: 'Calcium', type: 'number', unit: 'mg/dL', hasMinMax: true, step: '0.1' }, | |
| { name: 'glucose_1', label: 'Glucose (Lab)', type: 'number', unit: 'mg/dL', hasMinMax: true }, | |
| { name: 'albumin', label: 'Albumin', type: 'number', unit: 'g/dL', hasMinMax: true, step: '0.1' }, | |
| { name: 'aniongap', label: 'Anion Gap', type: 'number', unit: 'mEq/L', hasMinMax: true }, | |
| { | |
| name: 'bun', label: 'BUN', type: 'number', unit: 'mg/dL', hasMinMax: true, | |
| validation: { normal: { min: 7, max: 20 }, warning: { min: 3, max: 50 }, critical: { min: 0, max: 150 } } | |
| }, | |
| { | |
| name: 'creatinine', label: 'Creatinine', type: 'number', unit: 'mg/dL', hasMinMax: true, step: '0.1', | |
| validation: { normal: { min: 0.6, max: 1.2 }, warning: { min: 0.3, max: 5 }, critical: { min: 0, max: 15 } } | |
| }, | |
| { name: 'total_protein', label: 'Total Protein', type: 'number', unit: 'g/dL', hasMinMax: true }, | |
| { name: 'globulin', label: 'Globulin', type: 'number', unit: 'g/dL', hasMinMax: true }, | |
| ] | |
| }, | |
| { | |
| id: 'liver', | |
| label: 'Liver Function', | |
| icon: 'Pill', | |
| description: 'Hepatic function and enzyme levels', | |
| fields: [ | |
| { | |
| name: 'alt', label: 'ALT', type: 'number', unit: 'U/L', hasMinMax: true, | |
| validation: { normal: { min: 7, max: 56 }, warning: { min: 0, max: 200 }, critical: { min: 0, max: 1000 } } | |
| }, | |
| { | |
| name: 'ast', label: 'AST', type: 'number', unit: 'U/L', hasMinMax: true, | |
| validation: { normal: { min: 10, max: 40 }, warning: { min: 0, max: 200 }, critical: { min: 0, max: 1000 } } | |
| }, | |
| { name: 'alp', label: 'Alkaline Phosphatase', type: 'number', unit: 'U/L', hasMinMax: true }, | |
| { name: 'ggt', label: 'GGT', type: 'number', unit: 'U/L', hasMinMax: true }, | |
| { | |
| name: 'bilirubin_total', label: 'Bilirubin (Total)', type: 'number', unit: 'mg/dL', hasMinMax: true, step: '0.1', | |
| validation: { normal: { min: 0.1, max: 1.2 }, warning: { min: 0, max: 5 }, critical: { min: 0, max: 30 } } | |
| }, | |
| { name: 'bilirubin_direct', label: 'Bilirubin (Direct)', type: 'number', unit: 'mg/dL', hasMinMax: true, step: '0.1' }, | |
| { name: 'bilirubin_indirect', label: 'Bilirubin (Indirect)', type: 'number', unit: 'mg/dL', hasMinMax: true, step: '0.1' }, | |
| ] | |
| }, | |
| { | |
| id: 'neuro', | |
| label: 'Neurological', | |
| icon: 'Brain', | |
| description: 'Glasgow Coma Scale and CNS assessment', | |
| fields: [ | |
| { | |
| name: 'gcs', label: 'GCS Total', type: 'number', hasMinMax: true, | |
| validation: { normal: { min: 15, max: 15 }, warning: { min: 9, max: 14 }, critical: { min: 3, max: 8 } } | |
| }, | |
| { | |
| name: 'gcs_motor', label: 'GCS Motor', type: 'number', hasMinMax: true, | |
| validation: { normal: { min: 6, max: 6 }, warning: { min: 4, max: 5 }, critical: { min: 1, max: 3 } } | |
| }, | |
| { | |
| name: 'gcs_verbal', label: 'GCS Verbal', type: 'number', hasMinMax: true, | |
| validation: { normal: { min: 5, max: 5 }, warning: { min: 3, max: 4 }, critical: { min: 1, max: 2 } } | |
| }, | |
| { | |
| name: 'gcs_eyes', label: 'GCS Eyes', type: 'number', hasMinMax: true, | |
| validation: { normal: { min: 4, max: 4 }, warning: { min: 3, max: 3 }, critical: { min: 1, max: 2 } } | |
| }, | |
| ] | |
| }, | |
| { | |
| id: 'cardiac', | |
| label: 'Cardiac & Inflammation', | |
| icon: 'Heart', | |
| description: 'Cardiac biomarkers and inflammatory markers', | |
| fields: [ | |
| { | |
| name: 'crp', label: 'CRP', type: 'number', unit: 'mg/L', hasMinMax: true, | |
| validation: { normal: { min: 0, max: 10 }, warning: { min: 0, max: 50 }, critical: { min: 0, max: 500 } } | |
| }, | |
| { | |
| name: 'urineoutput', label: 'Urine Output', type: 'number', unit: 'mL/hr', hasMinMax: true, | |
| validation: { normal: { min: 30, max: 100 }, warning: { min: 10, max: 200 }, critical: { min: 0, max: 500 } } | |
| }, | |
| { name: 'troponin_t', label: 'Troponin T', type: 'number', unit: 'ng/mL', hasMinMax: true, step: '0.001' }, | |
| { name: 'ck_mb', label: 'CK-MB', type: 'number', unit: 'ng/mL', hasMinMax: true }, | |
| { name: 'ntprobnp', label: 'NT-proBNP', type: 'number', unit: 'pg/mL', hasMinMax: true }, | |
| ] | |
| }, | |
| ]; | |
| // Get validation status for a value | |
| export function getValidationStatus(field: FieldConfig, value: string): 'normal' | 'warning' | 'critical' | 'invalid' | null { | |
| if (!field.validation || value === '' || value === null || value === undefined) { | |
| return null; | |
| } | |
| const numValue = parseFloat(value); | |
| if (isNaN(numValue)) return null; | |
| const { normal, warning, critical } = field.validation; | |
| // Check if outside critical range (invalid) | |
| if (numValue < critical.min || numValue > critical.max) { | |
| return 'invalid'; | |
| } | |
| // Check normal range | |
| if (numValue >= normal.min && numValue <= normal.max) { | |
| return 'normal'; | |
| } | |
| // Check warning range | |
| if (numValue >= warning.min && numValue <= warning.max) { | |
| return 'warning'; | |
| } | |
| // Outside warning but inside critical = critical | |
| return 'critical'; | |
| } | |
| // Helper to generate field keys for form state | |
| export function generateFormFields(): Record<string, any> { | |
| const fields: Record<string, any> = {}; | |
| formCategories.forEach(category => { | |
| category.fields.forEach(field => { | |
| // Simplified: Just one field for the input | |
| fields[field.name] = field.type === 'select' && field.options | |
| ? field.options[0]?.value | |
| : ''; | |
| }); | |
| }); | |
| return fields; | |
| } | |
| // Helper to prepare payload for API | |
| export function preparePayload(formData: Record<string, any>): Record<string, any> { | |
| const payload: Record<string, any> = {}; | |
| // First copy all known fields | |
| Object.entries(formData).forEach(([key, value]) => { | |
| if (value === '' || value === null || value === undefined) { | |
| return; | |
| } | |
| const numValue = parseFloat(value as string); | |
| payload[key] = isNaN(numValue) ? value : numValue; | |
| }); | |
| // Now auto-populate min/max if they don't exist | |
| // Loop through all defined categories/fields | |
| formCategories.forEach(category => { | |
| category.fields.forEach(field => { | |
| if (field.hasMinMax) { | |
| const val = formData[field.name]; | |
| if (val !== '' && val !== null && val !== undefined) { | |
| const numVal = parseFloat(val); | |
| if (!isNaN(numVal)) { | |
| // Assuming single measurement means min = max = value | |
| payload[`${field.name}_min`] = numVal; | |
| payload[`${field.name}_max`] = numVal; | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| return payload; | |
| } | |