""" CDSS Rule Editor Component """ import gradio as gr import pandas as pd import json import ast def parse_rules(): with open("rules.py", "r") as f: tree = ast.parse(f.read()) rules = {"Mother": [], "Neonate": [], "Gyn": []} 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 isinstance(body_item.test, ast.Compare) and isinstance(body_item.test.left, ast.Attribute) and isinstance(body_item.test.left.value, ast.Name) and body_item.test.left.value.id == "state" and body_item.test.left.attr == "patient_type" and isinstance(body_item.test.ops[0], ast.Eq) and isinstance(body_item.test.comparators[0], ast.Constant) ): patient_type = body_item.test.comparators[0].value if patient_type in rules: for rule_node in body_item.body: if isinstance(rule_node, ast.If): conditions = ast.unparse(rule_node.test) alert = "" for item in rule_node.body: if ( isinstance(item, ast.Expr) and isinstance(item.value, ast.Call) and hasattr(item.value.func, "value") and hasattr(item.value.func.value, "id") and item.value.func.value.id == "alerts" and item.value.func.attr == "append" and isinstance(item.value.args[0], ast.Constant) ): alert = item.value.args[0].value rules[patient_type].append( {"conditions": conditions, "alert": alert} ) return rules def rules_to_dataframes(rules): dataframes = {} for patient_type, rules_list in rules.items(): data = {"Conditions": [], "Alert": []} for rule in rules_list: data["Conditions"].append(rule["conditions"]) data["Alert"].append(rule["alert"]) df = pd.DataFrame(data) dataframes[patient_type] = df return dataframes def dataframes_to_rules(dfs): rules = {"Mother": [], "Neonate": [], "Gyn": []} for patient_type, df in dfs.items(): if df is not None: for index, row in df.iterrows(): if row["Conditions"] and row["Alert"]: rules[patient_type].append( {"conditions": row["Conditions"], "alert": row["Alert"]} ) return rules def add_row(df): if df is None: df = pd.DataFrame(columns=["Conditions", "Alert"]) df.loc[len(df)] = ["", ""] return df def save_rules(df_mother, df_neonate, df_gyn): dfs = {"Mother": df_mother, "Neonate": df_neonate, "Gyn": df_gyn} for patient_type, df in dfs.items(): if not isinstance(df, pd.DataFrame): dfs[patient_type] = pd.DataFrame(df, columns=["Conditions", "Alert"]) rules = dataframes_to_rules(dfs) 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": node.body = [] node.body.append(ast.parse("v = state.vitals").body[0]) node.body.append(ast.parse("labs = state.labs").body[0]) node.body.append(ast.parse("alerts = []").body[0]) for patient_type, rule_list in rules.items(): if_patient_type_body = [] for rule in rule_list: conditions = ( rule["conditions"].replace("\r", " ").replace("\n", " ") ) if_rule_str = f"if {conditions}:\n alerts.append({json.dumps(rule['alert'])})" if_rule = ast.parse(if_rule_str).body[0] if_patient_type_body.append(if_rule) if if_patient_type_body: if_patient_type = ast.If( test=ast.Compare( left=ast.Attribute( value=ast.Name(id="state", ctx=ast.Load()), attr="patient_type", ctx=ast.Load(), ), ops=[ast.Eq()], comparators=[ast.Constant(value=patient_type)], ), body=if_patient_type_body, orelse=[], ) node.body.append(if_patient_type) node.body.append( ast.parse( 'if not alerts:\\n return "Tidak ada alert prioritas tinggi. Lanjutkan pemantauan dan dokumentasi."' ).body[0] ) node.body.append( ast.parse( 'return "\\n- ".join(["ALERT:"] + alerts)', mode="single" ).body[0] ) new_code = ast.unparse(tree) with open("rules.py", "w") as f: f.write(new_code) return "Rules saved successfully." def editor_ui(): with gr.TabItem("Rule Editor"): with gr.Tabs(): with gr.TabItem("Edit Rules"): gr.Markdown("## CDSS Rule Editor") initial_rules = parse_rules() initial_dfs = rules_to_dataframes(initial_rules) with gr.Tabs(): with gr.Tab("Mother"): df_mother = gr.DataFrame( value=initial_dfs["Mother"], headers=["Conditions", "Alert"], interactive=True, row_count=(len(initial_dfs["Mother"]) + 1, "dynamic"), type="pandas", ) add_mother_btn = gr.Button("➕ Add Mother Rule") add_mother_btn.click( add_row, inputs=df_mother, outputs=df_mother ) with gr.Tab("Neonate"): df_neonate = gr.DataFrame( value=initial_dfs["Neonate"], headers=["Conditions", "Alert"], interactive=True, row_count=(len(initial_dfs["Neonate"]) + 1, "dynamic"), type="pandas", ) add_neonate_btn = gr.Button("➕ Add Neonate Rule") add_neonate_btn.click( add_row, inputs=df_neonate, outputs=df_neonate ) with gr.Tab("Gyn"): df_gyn = gr.DataFrame( value=initial_dfs["Gyn"], headers=["Conditions", "Alert"], interactive=True, row_count=(len(initial_dfs["Gyn"]) + 1, "dynamic"), type="pandas", ) add_gyn_btn = gr.Button("➕ Add Gyn Rule") add_gyn_btn.click(add_row, inputs=df_gyn, outputs=df_gyn) save_button = gr.Button("💾 Save Rules") status_textbox = gr.Textbox(label="Status", interactive=False) save_button.click( save_rules, inputs=[df_mother, df_neonate, df_gyn], outputs=status_textbox, ) return df_mother, df_neonate, df_gyn, save_button, status_textbox