CoolFace
Apppublic

phamnguyenhuan/rapidpredict

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
streamlit_app.py190 linesDownload Raw Back to src
1import streamlit as st2import numpy as np3 4st.set_page_config(page_title="Công Cụ Tiên Lượng mRS", page_icon="🧠")5 6text_dict = {7    "TOOL_TITLE": {"vi": "CÔNG CỤ TIÊN LƯỢNG PHỤC HỒI CHỨC NĂNG THẦN KINH (mRS)", "en": "Prognostic Tool for Neurological Functional Outcome (mRS)"},8    "TOOL_DESC_1": {"vi": "Mô hình tiên lượng phục hồi chức năng thần kinh tốt (mRS 0-2) trên bệnh nhân đột quỵ thiếu máu não cấp cửa sổ 6-24 giờ được điều trị tái thông lấy huyết khối cơ học có sử dụng phần mềm RAPID", "en": "A prognostic model for functional independence outcome (mRS 0–2) in acute ischemic stroke patients treated with thrombectomy within the 6–24 hour window using RAPID software"},9    "LANG_TITLE": {"vi": "🌐 Chọn ngôn ngữ", "en": "🌐 Choose Language"},10    "AGE": {"vi": "TUỔI - NĂM", "en": "AGE - YEARS"},11    "SEX": {"vi": "GIỚI", "en": "SEX"},12    "HYPERTENSION": {"vi": "TĂNG HUYẾT ÁP", "en": "HYPERTENSION"},13    "HYPERLIPIDEMIA": {"vi": "RỐI LOẠN LIPID MÁU", "en": "HYPERLIPIDEMIA"},14    "ONSET_TYPE_LABEL": {"vi": "KIỂU KHỞI PHÁT", "en": "TYPE OF STROKE ONSET"},15    "ONSET_HOS": {"vi": "THỜI GIAN KHỞI PHÁT ĐẾN NHẬP VIỆN - giờ", "en": "TIME FROM ONSET TO HOSPITALIZATION (hours)"},16    "ONSET_GROIN": {"vi": "THỜI GIAN KHỞI PHÁT ĐẾN ĐÂM KIM - giờ", "en": "TIME FROM ONSET TO GROIN PUNCTURE (hours)"},17    "TMAX": {"vi": "Thể tích Tmax > 4 giây (ml)", "en": "Tmax > 4 seconds (ml)"},18    "OCCLUSION": {"vi": "ĐỘNG MẠCH TẮC TRÊN DSA", "en": "OCCLUSION LOCATION"},19    "TICI": {"vi": "MỨC ĐỘ TÁI THÔNG (eTICI)", "en": "eTICI SCORE POST-INTERVENTION"},20    "NIHSS_24H": {"vi": "NIHSS 24H SAU CAN THIỆP", "en": "NIHSS AFTER 24H"},21    "SEX_CHOICES": {"vi": ["Nữ", "Nam"], "en": ["Female", "Male"]},22    "YES_NO": {"vi": ["Không", "Có"], "en": ["No", "Yes"]},23    "ONSET_TYPE": {"vi": ["Không xác định", "Rõ thời gian"], "en": ["Unclear onset", "Clear onset"]},24    "TICI_CHOICES": {"vi": ["TICI 2B-3", "TICI 0-2A"], "en": ["TICI 2B-3", "TICI 0-2A"]},25    "ARTERY_DSA": {"vi": ["ICA", "M1", "M2", "TANDEM"], "en": ["ICA", "M1", "M2", "Tandem"]},26    "RESULT_TITLE": {"vi": "KHẢ NĂNG PHỤC HỒI CHỨC NĂNG TỐT (mRS 0-2) SAU 3 THÁNG",27                     "en": "PREDICTED PROBABILITY OF 3-MONTH FUNCTIONAL INDEPENDENCE (mRS 0-2)"},28    "PERCENT": {"vi": "Xác suất", "en": "Probability"}29}30 31def process_decimal_input(label, default_value_vi="12,0", default_value_en="12.0", key=None, lang="vi"):32    # Pick default value based on language33    default_value = default_value_vi if lang == "vi" else default_value_en34    input_str = st.text_input(label, value=default_value, key=key)35 36    # Normalize input: replace comma with dot for calculation37    normalized_str = input_str.replace(',', '.') if lang == "vi" else input_str.replace(',', '.')38 39    try:40        value = float(normalized_str)41    except ValueError:42        st.error("Vui lòng nhập số hợp lệ!" if lang == "vi" else "Please enter a valid number!")43        return None44 45    return value46 47def calc_logit_and_prob(48    tuoi, tha, khoiphat, nihss24h, tmax_4, ticig, gioi, rllm, 49    onset_hos, onset_punc, m1_occl, m2_occl, tandem_occl50):51    logit = (52        10.81453        - 0.066 * tuoi54        - 2.805 * tha55        + 1.405 * khoiphat56        - 0.276 * nihss24h57        - 0.005 * tmax_458        - 1.525 * ticig59        + 0.895 * gioi60        + 0.608 * rllm61        + 0.139 * onset_hos62        - 0.162 * onset_punc63        - 0.807 * m1_occl64        - 1.522 * m2_occl65        + 0.653 * tandem_occl66    )67    p = 1 / (1 + np.exp(-logit))68    return logit, p69 70if "lang" not in st.session_state:71    st.session_state.lang = "vi"  # Default is Vietnamese72 73st.markdown(f"""74<div style='text-align: center; margin-top: -10px; margin-bottom: 10px;'>75    <h4>{text_dict['LANG_TITLE'][st.session_state.lang]}</h4>76</div>77""", unsafe_allow_html=True)78 79_, col1, col2, _ = st.columns([5, 3, 3, 5])80with col1:81    if st.button("![vn](https://flagcdn.com/w40/vn.png) Tiếng Việt"):82        st.session_state.lang = "vi"83        st.rerun()84with col2:85    if st.button("![us](https://flagcdn.com/w40/us.png) English"):86        st.session_state.lang = "en"87        st.rerun()88 89lang = st.session_state.lang90 91st.markdown(f"""92    <div style='text-align: center;'>93        <p style='font-size: 24px; font-weight: bold; color: darkblue;'>94            RAPID PREDICT95        </p>96        <p style='font-size: 20px; font-weight: bold; color: darkblue;'>97            {text_dict["TOOL_TITLE"][lang]}98        </p>99        <p style='font-size: 16px; color: black;'>100            {text_dict["TOOL_DESC_1"][lang]}101        </p>102    </div>103""", unsafe_allow_html=True)104 105# --- GIAO DIỆN NHẬP LIỆU ---106st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['AGE'][lang]}</strong></div>", unsafe_allow_html=True)107tuoi = st.number_input("", value=60)108 109if tuoi < 30 or tuoi > 95:110    st.warning("Tuổi phải nằm trong khoảng từ 30 - 95!")111 112st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['SEX'][lang]}</strong></div>", unsafe_allow_html=True)113gioi = st.selectbox('', text_dict["SEX_CHOICES"][lang], key="gioi_select")114 115st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['HYPERTENSION'][lang]}</strong></div>", unsafe_allow_html=True)116tha = st.selectbox('', text_dict["YES_NO"][lang], key="tha_select")117 118st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['HYPERLIPIDEMIA'][lang]}</strong></div>", unsafe_allow_html=True)119rllm = st.selectbox('', text_dict["YES_NO"][lang], key="rllm_select")120 121st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['ONSET_TYPE_LABEL'][lang]}</strong></div>", unsafe_allow_html=True)122khoiphat = st.selectbox('', text_dict["ONSET_TYPE"][lang], key="khoiphat_select")123 124st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['ONSET_HOS'][lang]}</strong></div>", unsafe_allow_html=True)125onset_hos = process_decimal_input(126    "", default_value_vi="12,0", default_value_en="12.0", key="onset_hos_input", lang=lang127)    128 129st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['ONSET_GROIN'][lang]}</strong></div>", unsafe_allow_html=True)130onset_groin = process_decimal_input(131    "", default_value_vi="13,0", default_value_en="13.0", key="onset_groin_input", lang=lang132)    133 134st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['TMAX'][lang]}</strong></div>", unsafe_allow_html=True)135tmax_4 = process_decimal_input('', default_value_vi="100,0", default_value_en="100.0", key="tmax_input", lang=lang)136 137st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['OCCLUSION'][lang]}</strong></div>", unsafe_allow_html=True)138artery_dsa_final = st.selectbox('', text_dict["ARTERY_DSA"][lang], key="artery_dsa_select")139 140st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['TICI'][lang]}</strong></div>", unsafe_allow_html=True)141ticig = st.selectbox('', text_dict["TICI_CHOICES"][lang], key="ticig_select")142 143st.markdown(f"<div style='margin-bottom: -30px'><strong>{text_dict['NIHSS_24H'][lang]}</strong></div>", unsafe_allow_html=True)144nihss_24h = st.number_input('', min_value=0, max_value=42, value=10, step=1, key="nihss_input")145 146# --- CHUYỂN ĐỔI GIÁ TRỊ INPUT ---147tha_value = 1 if tha in ["Có", "Yes"] else 0148rllm_value = 1 if rllm in ["Có", "Yes"] else 0149khoiphat_value = 1 if khoiphat in ["Không xác định", "Unclear onset"] else 0150gioi_value = 1 if gioi in ["Nam", "Male"] else 0151ticig_value = 1 if ticig in ['TICI 0-2A'] else 0152 153m1_occl = 1 if artery_dsa_final.upper() == "M1" else 0154m2_occl = 1 if artery_dsa_final.upper() == "M2" else 0155tandem_occl = 1 if artery_dsa_final.upper() == "TANDEM" else 0156 157onset_punc = onset_groin  # (giống ONSETTOGROIN)158 159if None not in [onset_hos, onset_groin, tmax_4]:160    logit_value, predicted_prob = calc_logit_and_prob(161        tuoi=tuoi,162        tha=tha_value,163        khoiphat=khoiphat_value,164        nihss24h=nihss_24h,165        tmax_4=tmax_4,166        ticig=ticig_value,167        gioi=gioi_value,168        rllm=rllm_value,169        onset_hos=onset_hos,170        onset_punc=onset_punc,171        m1_occl=m1_occl,172        m2_occl=m2_occl,173        tandem_occl=tandem_occl174    )175 176    st.write(f"🧮 Computed logit value: {logit_value:.4f}")177 178    formatted_percent = f"{predicted_prob * 100:.1f}".replace('.', ',') if lang == "vi" else f"{predicted_prob * 100:.1f}"179 180    st.markdown(f"""181        <h1 style='text-align: center; font-size: 24px; color: darkblue;'>182            {text_dict["RESULT_TITLE"][lang]}183        </h1>184        <h2 style='text-align: center; font-size: 38px; color: red;'>185            {formatted_percent}%186        </h2>187        """, unsafe_allow_html=True)188    image_url = "https://raw.githubusercontent.com/huanpham1211/public_image/main/mrs_scale.jpg"189    st.image(image_url, caption="Modified Rankin Scale (mRS)", use_container_width=True)190