Spaces:
Running
Running
""" | |
Clinical Calculator Suite - Phase 1.2 MCP Development | |
Implements common clinical calculations for pharmacist workflow | |
""" | |
import logging | |
from typing import Dict, Any | |
logger = logging.getLogger(__name__) | |
def cockcroft_gault_creatinine_clearance( | |
age: int, | |
weight_kg: float, | |
serum_creatinine_mg_dl: float, | |
is_female: bool = False | |
) -> Dict[str, Any]: | |
""" | |
Calculate creatinine clearance using Cockcroft-Gault equation. | |
Args: | |
age: Patient age in years | |
weight_kg: Weight in kilograms | |
serum_creatinine_mg_dl: Serum creatinine in mg/dL | |
is_female: True if patient is female | |
Returns: | |
Dict with calculated creatinine clearance and interpretation | |
""" | |
# Enhanced input validation with specific error messages | |
if age <= 0: | |
raise ValueError(f"Age must be positive, got {age}") | |
if age > 120: | |
raise ValueError(f"Age seems unrealistic, got {age}") | |
if weight_kg <= 0: | |
raise ValueError(f"Weight must be positive, got {weight_kg}") | |
if weight_kg > 500: | |
raise ValueError(f"Weight seems unrealistic, got {weight_kg}") | |
if serum_creatinine_mg_dl <= 0: | |
raise ValueError(f"Serum creatinine must be positive, got {serum_creatinine_mg_dl}") | |
if serum_creatinine_mg_dl > 20: | |
raise ValueError(f"Serum creatinine seems unrealistic, got {serum_creatinine_mg_dl}") | |
clearance = ((140 - age) * weight_kg) / (72 * serum_creatinine_mg_dl) | |
if is_female: | |
clearance *= 0.85 | |
if clearance >= 90: | |
stage = "Normal or high" | |
category = "G1" | |
elif clearance >= 60: | |
stage = "Mildly decreased" | |
category = "G2" | |
elif clearance >= 45: | |
stage = "Mild to moderately decreased" | |
category = "G3a" | |
elif clearance >= 30: | |
stage = "Moderately to severely decreased" | |
category = "G3b" | |
elif clearance >= 15: | |
stage = "Severely decreased" | |
category = "G4" | |
else: | |
stage = "Kidney failure" | |
category = "G5" | |
return { | |
"creatinine_clearance_ml_min": round(clearance, 1), | |
"kidney_function_stage": stage, | |
"gfr_category": category, | |
"formula_used": "Cockcroft-Gault", | |
"requires_dose_adjustment": clearance < 60, | |
"patient_info": { | |
"age": age, | |
"weight_kg": weight_kg, | |
"serum_creatinine_mg_dl": serum_creatinine_mg_dl, | |
"is_female": is_female | |
} | |
} | |
def ckd_epi_egfr( | |
age: int, | |
serum_creatinine_mg_dl: float, | |
is_female: bool = False, | |
is_black: bool = False | |
) -> Dict[str, Any]: | |
""" | |
Calculate estimated GFR using CKD-EPI equation. | |
Args: | |
age: Patient age in years | |
serum_creatinine_mg_dl: Serum creatinine in mg/dL | |
is_female: True if patient is female | |
is_black: True if patient is Black | |
Returns: | |
Dict with calculated eGFR and interpretation | |
""" | |
if age <= 0 or serum_creatinine_mg_dl <= 0: | |
raise ValueError("Age and creatinine must be positive") | |
if is_female: | |
kappa = 0.7 | |
alpha = -0.329 | |
if serum_creatinine_mg_dl <= kappa: | |
alpha = -0.411 | |
else: | |
kappa = 0.9 | |
alpha = -0.411 | |
if serum_creatinine_mg_dl <= kappa: | |
alpha = -0.302 | |
scr_kappa_ratio = serum_creatinine_mg_dl / kappa | |
if serum_creatinine_mg_dl <= kappa: | |
egfr = 141 * (scr_kappa_ratio ** alpha) * (0.993 ** age) | |
else: | |
egfr = 141 * (scr_kappa_ratio ** -1.209) * (0.993 ** age) | |
if is_female: | |
egfr *= 1.018 | |
if is_black: | |
egfr *= 1.159 | |
if egfr >= 90: | |
stage = "Normal or high" | |
category = "G1" | |
elif egfr >= 60: | |
stage = "Mildly decreased" | |
category = "G2" | |
elif egfr >= 45: | |
stage = "Mild to moderately decreased" | |
category = "G3a" | |
elif egfr >= 30: | |
stage = "Moderately to severely decreased" | |
category = "G3b" | |
elif egfr >= 15: | |
stage = "Severely decreased" | |
category = "G4" | |
else: | |
stage = "Kidney failure" | |
category = "G5" | |
return { | |
"egfr_ml_min_1_73m2": round(egfr, 1), | |
"kidney_function_stage": stage, | |
"gfr_category": category, | |
"formula_used": "CKD-EPI", | |
"requires_dose_adjustment": egfr < 60, | |
"patient_info": { | |
"age": age, | |
"serum_creatinine_mg_dl": serum_creatinine_mg_dl, | |
"is_female": is_female, | |
"is_black": is_black | |
} | |
} | |
def child_pugh_score( | |
bilirubin_mg_dl: float, | |
albumin_g_dl: float, | |
inr: float, | |
ascites: str, | |
encephalopathy: str | |
) -> Dict[str, Any]: | |
""" | |
Calculate Child-Pugh score for liver function assessment. | |
Args: | |
bilirubin_mg_dl: Total bilirubin in mg/dL | |
albumin_g_dl: Serum albumin in g/dL | |
inr: International Normalized Ratio | |
ascites: 'none', 'mild', or 'moderate-severe' | |
encephalopathy: 'none', 'grade-1-2', or 'grade-3-4' | |
Returns: | |
Dict with Child-Pugh score, class, and interpretation | |
""" | |
score = 0 | |
if bilirubin_mg_dl < 2: | |
score += 1 | |
elif bilirubin_mg_dl <= 3: | |
score += 2 | |
else: | |
score += 3 | |
if albumin_g_dl > 3.5: | |
score += 1 | |
elif albumin_g_dl >= 2.8: | |
score += 2 | |
else: | |
score += 3 | |
if inr < 1.7: | |
score += 1 | |
elif inr <= 2.3: | |
score += 2 | |
else: | |
score += 3 | |
ascites_lower = ascites.lower() | |
if 'none' in ascites_lower: | |
score += 1 | |
elif 'mild' in ascites_lower: | |
score += 2 | |
else: | |
score += 3 | |
encephalopathy_lower = encephalopathy.lower() | |
if 'none' in encephalopathy_lower: | |
score += 1 | |
elif 'grade-1-2' in encephalopathy_lower or '1-2' in encephalopathy_lower: | |
score += 2 | |
else: | |
score += 3 | |
if score <= 6: | |
child_class = "A" | |
mortality_1yr = "< 10%" | |
mortality_2yr = "< 15%" | |
perioperative_mortality = "10%" | |
elif score <= 9: | |
child_class = "B" | |
mortality_1yr = "10-20%" | |
mortality_2yr = "20-30%" | |
perioperative_mortality = "30%" | |
else: | |
child_class = "C" | |
mortality_1yr = "> 20%" | |
mortality_2yr = "> 35%" | |
perioperative_mortality = "50%" | |
return { | |
"child_pugh_score": score, | |
"child_pugh_class": child_class, | |
"one_year_mortality": mortality_1yr, | |
"two_year_mortality": mortality_2yr, | |
"perioperative_mortality": perioperative_mortality, | |
"requires_dose_adjustment": child_class in ["B", "C"], | |
"severe_impairment": child_class == "C", | |
"components": { | |
"bilirubin_mg_dl": bilirubin_mg_dl, | |
"albumin_g_dl": albumin_g_dl, | |
"inr": inr, | |
"ascites": ascites, | |
"encephalopathy": encephalopathy | |
} | |
} | |
def bmi_calculator( | |
weight_kg: float, | |
height_cm: float | |
) -> Dict[str, Any]: | |
""" | |
Calculate Body Mass Index and provide interpretation. | |
Args: | |
weight_kg: Weight in kilograms | |
height_cm: Height in centimeters | |
Returns: | |
Dict with BMI and weight category | |
""" | |
if weight_kg <= 0 or height_cm <= 0: | |
raise ValueError("Weight and height must be positive") | |
height_m = height_cm / 100 | |
bmi = weight_kg / (height_m ** 2) | |
if bmi < 18.5: | |
category = "Underweight" | |
risk = "Increased risk of malnutrition" | |
elif bmi < 25: | |
category = "Normal weight" | |
risk = "Low risk" | |
elif bmi < 30: | |
category = "Overweight" | |
risk = "Increased risk" | |
elif bmi < 35: | |
category = "Obesity Class I" | |
risk = "High risk" | |
elif bmi < 40: | |
category = "Obesity Class II" | |
risk = "Very high risk" | |
else: | |
category = "Obesity Class III" | |
risk = "Extremely high risk" | |
return { | |
"bmi": round(bmi, 1), | |
"category": category, | |
"health_risk": risk, | |
"weight_kg": weight_kg, | |
"height_cm": height_cm | |
} | |
def ideal_body_weight( | |
height_cm: float, | |
is_male: bool = True | |
) -> Dict[str, Any]: | |
""" | |
Calculate Ideal Body Weight using Devine formula. | |
Args: | |
height_cm: Height in centimeters | |
is_male: True if patient is male | |
Returns: | |
Dict with ideal body weight | |
""" | |
if height_cm <= 0: | |
raise ValueError("Height must be positive") | |
height_inches = height_cm / 2.54 | |
if is_male: | |
ibw_kg = 50 + 2.3 * (height_inches - 60) | |
else: | |
ibw_kg = 45.5 + 2.3 * (height_inches - 60) | |
ibw_kg = max(ibw_kg, 30) | |
return { | |
"ideal_body_weight_kg": round(ibw_kg, 1), | |
"height_cm": height_cm, | |
"is_male": is_male, | |
"formula_used": "Devine" | |
} | |
def adjusted_body_weight( | |
actual_weight_kg: float, | |
ideal_weight_kg: float, | |
correction_factor: float = 0.4 | |
) -> Dict[str, Any]: | |
""" | |
Calculate Adjusted Body Weight for obese patients. | |
Args: | |
actual_weight_kg: Actual body weight in kg | |
ideal_weight_kg: Ideal body weight in kg | |
correction_factor: Correction factor (default 0.4) | |
Returns: | |
Dict with adjusted body weight | |
""" | |
if actual_weight_kg <= 0 or ideal_weight_kg <= 0: | |
raise ValueError("Weights must be positive") | |
if actual_weight_kg <= ideal_weight_kg * 1.2: | |
adjusted_weight = actual_weight_kg | |
adjustment_needed = False | |
else: | |
adjusted_weight = ideal_weight_kg + correction_factor * (actual_weight_kg - ideal_weight_kg) | |
adjustment_needed = True | |
return { | |
"adjusted_body_weight_kg": round(adjusted_weight, 1), | |
"actual_weight_kg": actual_weight_kg, | |
"ideal_weight_kg": ideal_weight_kg, | |
"correction_factor": correction_factor, | |
"adjustment_needed": adjustment_needed, | |
"percent_above_ideal": round(((actual_weight_kg / ideal_weight_kg) - 1) * 100, 1) | |
} | |
def creatinine_conversion( | |
creatinine_value: float, | |
from_unit: str, | |
to_unit: str | |
) -> Dict[str, Any]: | |
""" | |
Convert creatinine between mg/dL and μmol/L. | |
Args: | |
creatinine_value: Creatinine value to convert | |
from_unit: 'mg_dl' or 'umol_l' | |
to_unit: 'mg_dl' or 'umol_l' | |
Returns: | |
Dict with converted value | |
""" | |
if creatinine_value <= 0: | |
raise ValueError("Creatinine value must be positive") | |
conversion_factor = 88.42 | |
if from_unit == to_unit: | |
converted_value = creatinine_value | |
elif from_unit == 'mg_dl' and to_unit == 'umol_l': | |
converted_value = creatinine_value * conversion_factor | |
elif from_unit == 'umol_l' and to_unit == 'mg_dl': | |
converted_value = creatinine_value / conversion_factor | |
else: | |
raise ValueError("Invalid units. Use 'mg_dl' or 'umol_l'") | |
return { | |
"original_value": creatinine_value, | |
"original_unit": from_unit, | |
"converted_value": round(converted_value, 2), | |
"converted_unit": to_unit, | |
"conversion_factor": conversion_factor | |
} | |
def dosing_weight_recommendation( | |
actual_weight_kg: float, | |
height_cm: float, | |
is_male: bool = True | |
) -> Dict[str, Any]: | |
""" | |
Recommend appropriate weight for dosing calculations. | |
Args: | |
actual_weight_kg: Actual body weight in kg | |
height_cm: Height in centimeters | |
is_male: True if patient is male | |
Returns: | |
Dict with dosing weight recommendation | |
""" | |
ibw_result = ideal_body_weight(height_cm, is_male) | |
ibw = ibw_result["ideal_body_weight_kg"] | |
bmi_result = bmi_calculator(actual_weight_kg, height_cm) | |
bmi = bmi_result["bmi"] | |
if actual_weight_kg <= ibw * 1.2: | |
dosing_weight = actual_weight_kg | |
recommendation = "Use actual body weight" | |
rationale = "Patient weight is within 20% of ideal body weight" | |
elif bmi >= 30: | |
adj_weight_result = adjusted_body_weight(actual_weight_kg, ibw) | |
dosing_weight = adj_weight_result["adjusted_body_weight_kg"] | |
recommendation = "Use adjusted body weight" | |
rationale = "Patient is obese (BMI ≥ 30); adjusted weight recommended for most drugs" | |
else: | |
dosing_weight = actual_weight_kg | |
recommendation = "Use actual body weight (consider drug-specific guidelines)" | |
rationale = "Patient is overweight but not obese; actual weight typically appropriate" | |
return { | |
"recommended_dosing_weight_kg": dosing_weight, | |
"recommendation": recommendation, | |
"rationale": rationale, | |
"actual_weight_kg": actual_weight_kg, | |
"ideal_weight_kg": ibw, | |
"bmi": bmi, | |
"bmi_category": bmi_result["category"] | |
} |