cdss / validator.py
spriambada3's picture
refactored
d18fef3
"""
CDSS Rule Validator Component
"""
import gradio as gr
import json
import ast
from models import Vitals, PatientState
def test_condition(
patient_type, sbp, dbp, hr, rr, temp_c, spo2, labs_text, condition, alert_text
):
"""
Tests a single condition against a manually defined patient state.
"""
try:
labs = json.loads(labs_text)
except json.JSONDecodeError:
return "Error: Invalid JSON in Labs field."
vitals = Vitals(
sbp=int(sbp),
dbp=int(dbp),
hr=int(hr),
rr=int(rr),
temp_c=float(temp_c),
spo2=int(spo2),
)
state = PatientState(
scenario="Validation",
patient_type=patient_type,
notes="",
labs=labs,
vitals=vitals,
)
# Dynamically create a rule function for testing
rule_fnc_str = f"""
def dynamic_rule(state):
v = state.vitals
labs = state.labs
alerts = []
if {condition}:
alerts.append("{alert_text}")
if not alerts:
return "No alert triggered."
return "- ".join(["ALERT:"] + alerts)
"""
try:
exec(rule_fnc_str, globals())
result = dynamic_rule(state)
return result
except Exception as e:
return f"Error in condition syntax: {e}"
def add_rule_to_set(patient_type, condition, alert_text):
"""
Adds the new rule to the rules.py file.
"""
if not condition or not alert_text:
return "Error: Condition and Alert text cannot be empty."
try:
with open("rules.py", "r") as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == "rule_based_cdss":
for body_item in node.body:
if (
isinstance(body_item, ast.If)
and hasattr(body_item.test, "comparators")
and body_item.test.comparators
and isinstance(body_item.test.comparators[0], ast.Constant)
and body_item.test.comparators[0].value == patient_type
):
new_rule_str = (
f'if {condition}:\n alerts.append("{alert_text}")'
)
new_rule_node = ast.parse(new_rule_str).body[0]
body_item.body.append(new_rule_node)
break
new_code = ast.unparse(tree)
with open("rules.py", "w") as f:
f.write(new_code)
return f"Rule added to {patient_type} ruleset and saved to rules.py."
except Exception as e:
return f"Failed to add rule: {e}"
def validator_ui():
with gr.TabItem("Rule Validator"):
gr.Markdown("## Validate and Add New Rules")
with gr.Row():
with gr.Column():
gr.Markdown("### 1. Define Patient State")
patient_type_validate = gr.Radio(
["Mother", "Neonate", "Gyn"],
label="Patient Type",
value="Mother",
)
sbp_validate = gr.Number(label="SBP", value=120)
dbp_validate = gr.Number(label="DBP", value=80)
hr_validate = gr.Number(label="HR", value=80)
rr_validate = gr.Number(label="RR", value=18)
temp_c_validate = gr.Number(label="Temp (°C)", value=37.0)
spo2_validate = gr.Number(label="SpO₂ (%)", value=98)
labs_validate = gr.Textbox(
label="Labs (JSON format)",
value='{"Hb": 12.0}',
lines=3,
)
with gr.Column():
gr.Markdown("### 2. Define and Test Rule")
condition_validate = gr.Textbox(
label="Condition (Python expression)",
value="v.sbp > 140",
lines=3,
)
alert_validate = gr.Textbox(
label="Alert Message",
value="Preeclampsia suspected",
lines=3,
)
test_button = gr.Button("Test Rule", variant="secondary")
validation_result = gr.Textbox(
label="Validation Result", interactive=False
)
gr.Markdown("### 3. Add Rule to Ruleset")
add_rule_button = gr.Button(
"Add Rule to Ruleset", variant="primary"
)
add_rule_status = gr.Textbox(
label="Status", interactive=False
)
test_button.click(
test_condition,
inputs=[
patient_type_validate,
sbp_validate,
dbp_validate,
hr_validate,
rr_validate,
temp_c_validate,
spo2_validate,
labs_validate,
condition_validate,
alert_validate,
],
outputs=validation_result,
)
add_rule_button.click(
add_rule_to_set,
inputs=[
patient_type_validate,
condition_validate,
alert_validate,
],
outputs=add_rule_status,
)
return patient_type_validate, sbp_validate, dbp_validate, hr_validate, rr_validate, temp_c_validate, spo2_validate, labs_validate, condition_validate, alert_validate, test_button, validation_result, add_rule_button, add_rule_status