""" Gradio CDSS Simulator for RSIA (Obstetri, Neonatologi, Ginekologi) FINAL INTEGRATED VERSION - Now with: - **Custom Plotly graphs** using gr.Plot for full control. - **X-Axis shows only the first and last timestamps.** - Tabbed plots for each vital sign, guaranteeing graph rendering. - Historic Clinical Text, 30s countdown, CSV loader, and all scenarios. Requirements: pip install gradio google-generativeai pandas plotly Set environment variable for Gemini: export GOOGLE_API_KEY=your_key_here Run: python app.py """ from __future__ import annotations import time import gradio as gr import pandas as pd from models import Vitals, PatientState from simulator import ( simulator_ui, inject_scenario, manual_edit, tick_timer, load_csv, countdown_tick, SCENARIOS, ) from editor import editor_ui, save_rules from validator import validator_ui, test_condition, add_rule_to_set from diagnosis import diagnosis_ui, generate_diagnosis, check_medication_interaction, generate_medical_record_from_image # --- Build UI --- with gr.Blocks( css=".gradio-container { max-width: 1200px !important; margin: auto !important; }" ) as demo: gr.Markdown("# RSIA CDSS Simulator with Custom Plotly Graphs") state = gr.State({}) history_df = gr.State(pd.DataFrame()) historic_text = gr.State("") last_tick_ts = gr.State(time.time()) interpretation = gr.Textbox(label="CDSS Interpretation", lines=2, interactive=False) with gr.Tabs(): bp_plot, hr_plot, rr_plot, temp_plot, spo2_plot = simulator_ui() (df_mother, df_neonate, df_gyn, save_button, status_textbox) = editor_ui() ( 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, ) = validator_ui() ( generate_button, diagnosis_output, medication_output, medication_input, check_button, interaction_output, image_input, generate_from_image_button, medical_record_output, ) = diagnosis_ui() with gr.Row(): with gr.Column(scale=2): with gr.Accordion("Inject New Scenario (resets chart)", open=True): with gr.Row(): btn_A0 = gr.Button("A0: Normal", elem_classes="small-btn") btn_A1 = gr.Button("A1: PPH", elem_classes="small-btn") btn_A2 = gr.Button("A2: Preeklampsia", elem_classes="small-btn") btn_A3 = gr.Button("A3: Sepsis", elem_classes="small-btn") with gr.Row(): btn_B1 = gr.Button("B1: Prematuritas", elem_classes="small-btn") btn_B2 = gr.Button("B2: Asfiksia", elem_classes="small-btn") btn_B3 = gr.Button("B3: Sepsis", elem_classes="small-btn") with gr.Row(): btn_C1 = gr.Button("C1: Bedah Komplikasi", elem_classes="small-btn") btn_C2 = gr.Button( "C2: Infeksi Pasca-Bedah", elem_classes="small-btn" ) btn_C3 = gr.Button("C3: Kanker", elem_classes="small-btn") notes = gr.Textbox(label="Catatan Klinis", lines=2) labs_text = gr.Textbox(label="Lab (dict or text)", value="{}") labs_show = gr.Textbox(label="Labs (Parsed)", interactive=False) with gr.Column(scale=1): with gr.Group(): patient_type_radio = gr.Radio( ["Mother", "Neonate", "Gyn"], label="Patient Type", value="Mother" ) sbp = gr.Number(label="SBP") dbp = gr.Number(label="DBP") hr = gr.Number(label="HR") rr = gr.Number(label="RR") temp_c = gr.Number(label="Temp (°C)") spo2 = gr.Number(label="SpO₂ (%)") apply_manual = gr.Button("Apply Manual Edits", variant="secondary") with gr.Row(): csv_file = gr.File(label="Load CSV to Graph") df_view = gr.Dataframe(label="History Table", wrap=True, interactive=False) cdss_toggle = gr.Checkbox(value=False, label="With CDSS (Gemini)") scenario_lbl = gr.Textbox(label="Active Scenario", interactive=False) countdown_lbl = gr.Label() historic_box = gr.Textbox(label="Historic Text", lines=12, interactive=False) # --- Event Handlers --- def update_medication_input(patient_type): if patient_type == "Mother": return gr.update(value="Aspirin, Ibuprofen") elif patient_type == "Gyn": return gr.update(value="Clopidogrel, Omeprazole") elif patient_type == "Neonate": return gr.update(value="Ceftriaxone, Calcium") patient_type_radio.change(update_medication_input, inputs=patient_type_radio, outputs=medication_input) ui_outputs = [ state, scenario_lbl, patient_type_radio, notes, sbp, dbp, hr, rr, temp_c, spo2, labs_text, labs_show, interpretation, history_df, df_view, historic_box, last_tick_ts, bp_plot, hr_plot, rr_plot, temp_plot, spo2_plot, ] manual_inputs = [ sbp, dbp, hr, rr, temp_c, spo2, notes, labs_text, cdss_toggle, patient_type_radio, state, history_df, historic_text, ] apply_manual.click(manual_edit, manual_inputs, ui_outputs) for tag, btn in zip( SCENARIOS.keys(), [ btn_A0, btn_A1, btn_A2, btn_A3, btn_B1, btn_B2, btn_B3, btn_C1, btn_C2, btn_C3, ], ): btn.click( inject_scenario, [gr.State(tag), cdss_toggle, history_df, historic_text], ui_outputs, ) csv_outputs = [history_df, df_view, bp_plot, hr_plot, rr_plot, temp_plot, spo2_plot] csv_file.change(load_csv, [csv_file, history_df], csv_outputs) timer_inputs = [cdss_toggle, state, history_df, historic_text] gr.Timer(30.0).tick(tick_timer, timer_inputs, ui_outputs) gr.Timer(1.0).tick(countdown_tick, [last_tick_ts], [countdown_lbl]) generate_button.click(generate_diagnosis, inputs=state, outputs=[diagnosis_output, medication_output]) check_button.click(check_medication_interaction, inputs=[patient_type_radio, medication_input], outputs=interaction_output) generate_from_image_button.click( generate_medical_record_from_image, inputs=[state, image_input], outputs=medical_record_output ) demo.load(inject_scenario, [gr.State("A0"), cdss_toggle, history_df, historic_text], ui_outputs) if __name__ == "__main__": demo.launch()