Spaces:
Sleeping
Sleeping
File size: 14,301 Bytes
2b4d16b cfa5c80 50334f0 2c33c1f 67c449b 1879d3b 50334f0 26c6012 2b4d16b cfa5c80 d000266 8e586ae f8ec48b 1d5d00a f8ec48b d000266 7f36c84 d000266 8e586ae 1d5d00a 2b4d16b d000266 67c449b 1879d3b eceb86c 1879d3b 67c449b 1879d3b 67c449b 1879d3b 67c449b 1879d3b 67c449b 1879d3b 13c64be d000266 50334f0 99a76a3 1879d3b 50334f0 1879d3b f94e45c 1879d3b eceb86c 1879d3b eceb86c 1879d3b e788cbb 50334f0 e788cbb 50334f0 c171bb5 0bd6c76 50334f0 c171bb5 2c33c1f c171bb5 7dfcca0 f94e45c d5ccaaa a5214cf 0bd6c76 ecf64e8 0bd6c76 cc0cacd fdd99f9 a524bf1 1844b2a a524bf1 0bd6c76 8b83033 0bd6c76 cc0cacd a524bf1 1844b2a a524bf1 0bd6c76 cc0cacd 67c449b cc0cacd c171bb5 67c449b eceb86c 1879d3b 67c449b 7e96f5f 1879d3b 67c449b f94e45c 50334f0 500e531 c987c13 500e531 c987c13 b7afaa9 c987c13 b7afaa9 500e531 84e1d73 500e531 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | import torch.utils.data as _tud
from pytorch_tabular.tabular_datamodule import TabularDatamodule
from streamlit_option_menu import option_menu
import google.generativeai as genai
import os
from deep_translator import GoogleTranslator
translator = GoogleTranslator()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
_OriginalDataLoader = _tud.DataLoader
class SafeDataLoader(_OriginalDataLoader):
def __init__(self, *args, **kwargs):
kwargs.pop("batch_size", None)
kwargs.pop("num_workers", None)
super().__init__(*args, **kwargs)
_tud.DataLoader = SafeDataLoader
_old_prepare = TabularDatamodule.prepare_inference_dataloader
def _patched_prepare(self, df):
if not hasattr(self.config, "dataloader_kwargs"):
self.config.dataloader_kwargs = {}
return _old_prepare(self, df)
TabularDatamodule.prepare_inference_dataloader = _patched_prepare
import streamlit as st
import pandas as pd
import numpy as np
import torch
import json
import pickle
from pytorch_tabular import TabularModel
from sklearn.preprocessing import LabelEncoder
from omegaconf import OmegaConf, DictConfig
from types import SimpleNamespace
# Load model
model = TabularModel.load_model("FTTransformerModel")
dm = model.datamodule
if hasattr(dm, "label_encoder") and isinstance(dm.label_encoder, LabelEncoder):
dm.label_encoder = [dm.label_encoder]
dm._inferred_config = SimpleNamespace(output_cardinality=[2])
# Load threshold
with open("FTTransformerModel/threshold.json", "r") as f:
threshold = json.load(f)["threshold"]
# Sidebar: language selection
with st.sidebar:
lang = st.selectbox("🌐 Language / 語言 / Bahasa", ["English", "中文", "Malay"])
# Label dictionary for multilingual UI
LABELS = {
"user_type": {"English": "I am a...", "中文": "我的身份是...", "Malay": "Saya seorang..."},
"user_type_options": {"English": ["Patient", "Medical Professional"], "中文": ["病患", "醫護人員"], "Malay": ["Pesakit", "Profesional Perubatan"]},
"input_header": {"English": "Enter Health Info", "中文": "輸入健康資料", "Malay": "Masukkan Maklumat Kesihatan"},
"age": {"English": "Patient's Age", "中文": "年齡", "Malay": "Umur"},
"height": {"English": "Patient's Height (cm)", "中文": "身高 (cm)", "Malay": "Tinggi (cm)"},
"weight": {"English": "Patient's Weight (kg)", "中文": "體重 (kg)", "Malay": "Berat (kg)"},
"systolic": {"English": "Patient's Systolic BP", "中文": "收縮壓", "Malay": "Tekanan Sistolik"},
"diastolic": {"English": "Patient's Diastolic BP", "中文": "舒張壓", "Malay": "Tekanan Diastolik"},
"cholesterol": {"English": "Patient's Cholesterol", "中文": "膽固醇", "Malay": "Kolesterol"},
"gluc": {"English": "Patient's Glucose", "中文": "血糖", "Malay": "Glukosa"},
"gender": {"English": "Patient's Gender", "中文": "性別", "Malay": "Jantina"},
"smoke": {"English": "Do patient smoke?", "中文": "是否吸菸?", "Malay": "Adakah merokok?"},
"alco": {"English": "Do patient drink alcohol?", "中文": "是否喝酒?", "Malay": "Adakah minum alkohol?"},
"active": {"English": "Are patient physically active?", "中文": "是否有運動習慣?", "Malay": "Adakah aktif secara fizikal?"},
"predict": {"English": "Predict CVD Risk", "中文": "預測心血管風險", "Malay": "Ramalkan Risiko CVD"}
}
MENU = {
"English": ["Prediction Tool", "Let's know more about CVD!"],
"中文": ["預測工具", "了解更多心血管資訊"],
"Malay": ["Alat Ramalan", "Ketahui lebih lanjut tentang CVD"]
}
chol_options = {
"English": {0: "Normal", 1: "High", 2: "Very High"},
"中文": {0: "正常", 1: "偏高", 2: "非常高"},
"Malay": {0: "Normal", 1: "Tinggi", 2: "Sangat Tinggi"}
}
gluc_options = chol_options.copy()
gender_options = {
"English": {0: "Female", 1: "Male"},
"中文": {0: "女性", 1: "男性"},
"Malay": {0: "Perempuan", 1: "Lelaki"}
}
yn_options = {
"English": {0: "No", 1: "Yes"},
"中文": {0: "否", 1: "是"},
"Malay": {0: "Tidak", 1: "Ya"}
}
# User input
with st.sidebar:
selected = option_menu(
menu_title="Menu",
options=MENU[lang],
icons=["activity", "book"],
menu_icon="cast",
default_index=0,
)
if selected == MENU[lang][0]:
with st.sidebar:
st.header(LABELS["input_header"][lang])
user_type = st.selectbox(LABELS["user_type"][lang], LABELS["user_type_options"][lang])
age = st.number_input(LABELS["age"][lang], min_value=18, max_value=100, value=50)
height = st.number_input(LABELS["height"][lang], min_value=100, max_value=250, value=170)
weight = st.number_input(LABELS["weight"][lang], min_value=30, max_value=200, value=70)
systolic = st.number_input(LABELS["systolic"][lang], min_value=80, max_value=250, value=120)
diastolic = st.number_input(LABELS["diastolic"][lang], min_value=40, max_value=150, value=80)
cholesterol = st.selectbox(LABELS["cholesterol"][lang], [0, 1, 2], format_func=lambda x: chol_options[lang][x])
gluc = st.selectbox(LABELS["gluc"][lang], [0, 1, 2], format_func=lambda x: gluc_options[lang][x])
gender = st.selectbox(LABELS["gender"][lang], [0, 1], format_func=lambda x: gender_options[lang][x])
smoke = st.selectbox(LABELS["smoke"][lang], [0, 1], format_func=lambda x: yn_options[lang][x])
alco = st.selectbox(LABELS["alco"][lang], [0, 1], format_func=lambda x: yn_options[lang][x])
active = st.selectbox(LABELS["active"][lang], [0, 1], format_func=lambda x: yn_options[lang][x])
input_data = pd.DataFrame([{ "age": age * 365, "height": height, "weight": weight, "ap_hi": systolic, "ap_lo": diastolic, "cholesterol": cholesterol, "gluc": gluc, "gender": gender, "smoke": smoke, "alco": alco, "active": active }])
predict_clicked = st.button(LABELS["predict"][lang])
if predict_clicked:
input_data["bmi"] = input_data["weight"] / ((input_data["height"]/100)**2)
input_data["pulse_pressure"] = input_data["ap_hi"] - input_data["ap_lo"]
input_data["hypertension"] = ((input_data["ap_hi"] > 140) | (input_data["ap_lo"] > 90)).astype(int)
preds = model.predict(input_data)
proba = preds["cardio_1_probability"].iloc[0]
result = "❌ At Risk of CVD" if proba >= threshold else " ✅ Low Risk"
with st.container():
st.markdown("### 🧬Prediction Result🧬")
st.markdown(f"<div style='text-align:center; font-size:26px'>{result}</div>", unsafe_allow_html=True)
# st.write(f"(Probability: {proba:.2%}, Threshold: {threshold:.2f})")
is_patient = user_type in ["Patient", "病患", "Pesakit"]
if is_patient:
prompt = (
f"As a healthcare professional, explain to the patient what this result '{result}' means "
f"Then, give five actionable lifestyle suggestions "
f"based on this result. Lastly, remind them clearly that this prediction is just a reference and "
f"they should consult a certified medical professional for an official diagnosis."
f"The title of response must be Health Advice From Your Lovely AI Friend."
f"Always care about the patient and be empathetic."
f"Add interesting emoji."
f"Do not use Markdown symbols such as # or **"
f"The punctuation format needs to follow the language standard。 For example, Chinese using Chinese punctuation format, Malay follows punctuation rules in Malay language"
f"Please keep the entire response within 150 words."
)
else:
prompt = (
f"You are a cardiovascular disease specialist reviewing a prediction result of '{result}' "
f"Please interpret this result for clinical use, and suggest the next diagnostic steps such as ECG, "
f"angiogram, or lab work. Make it clear that this model is a support tool and not a substitute for "
f"clinical judgment."
f"The title of response must be Diagnosis Support From Your Lovely AI Friend."
f"Keep the response in a clear and clean format."
f"Do not use Markdown symbols such as # or **"
f"The punctuation format needs to follow the language standard。 For example, Chinese using Chinese punctuation format, Malay follows punctuation rules in Malay language"
f"Please keep the entire response within 150 words."
)
model_gemini = genai.GenerativeModel(
model_name="models/gemini-2.0-flash",
generation_config=genai.types.GenerationConfig(temperature=0.2)
)
response = model_gemini.generate_content(prompt)
original_text = response.text
if lang == "中文":
translated = GoogleTranslator(source="auto", target="zh-TW").translate(original_text)
st.markdown("### 🔹 AI 健康建議")
st.write(translated)
elif lang == "Malay":
translated = GoogleTranslator(source="auto", target="ms").translate(original_text)
st.markdown("### 🔹 Nasihat Kesihatan AI")
st.write(translated)
else:
st.markdown("### 🔹 AI Health Advice")
st.write(original_text)
elif selected == MENU[lang][1]:
st.title({
"English": "Understanding Cardiovascular Disease",
"中文": "了解心血管疾病",
"Malay": "Memahami Penyakit Kardiovaskular"
}[lang])
st.markdown({
"English": """
**What is Cardiovascular Disease (CVD)?**
CVDs are a group of heart and blood vessel conditions, such as coronary heart disease, stroke, and heart failure. They are the leading cause of death globally.
**Key Facts (by WHO):**
- Over 4 out of 5 CVD deaths are due to heart attacks and strokes.
- One-third of these deaths happen in people under age 70.
- Many CVDs can be prevented by addressing risk factors such as tobacco use, poor diet, obesity, inactivity, and harmful alcohol use.
**Prevention:**
- Stop smoking and avoid secondhand smoke
- Choose healthy foods with less salt and saturated fat
- Stay active at least 30 minutes a day
- Get regular health checkups
""",
"中文": """
**什麼是心血管疾病(CVD)?**
CVD 是一類包括冠心病、中風、心力衰竭在內的心臟與血管疾病。它是全球主要死因之一。
**世界衛生組織重點資訊:**
- 超過八成的心血管死亡來自心臟病和中風
- 三分之一發生在70歲以下的人
- 多數可透過控制菸酒、不良飲食、運動不足、肥胖等風險因素來預防
**預防建議:**
- 戒菸,遠離二手菸
- 飲食清淡,減少油脂和鹽分
- 每天至少運動 30 分鐘
- 定期健康檢查
""",
"Malay": """
**Apakah Penyakit Kardiovaskular (CVD)?**
CVD ialah kumpulan penyakit jantung dan saluran darah seperti penyakit jantung koronari, strok dan kegagalan jantung. Ia adalah penyebab utama kematian di dunia.
**Fakta Penting (WHO):**
- Lebih 80% kematian CVD berpunca daripada serangan jantung dan strok
- Sepertiga berlaku pada mereka di bawah umur 70 tahun
- Sebahagian besar boleh dicegah melalui gaya hidup sihat
**Langkah Pencegahan:**
- Berhenti merokok dan elakkan asap rokok
- Pilih makanan sihat kurang garam dan lemak
- Kekal aktif sekurang-kurangnya 30 minit sehari
- Lakukan pemeriksaan kesihatan secara berkala
"""
}[lang])
st.markdown("## " + {
"English": "🥗 Healthy Diet Guidelines",
"中文": "🥗 健康飲食指引",
"Malay": "🥗 Garis Panduan Pemakanan Sihat"
}[lang])
st.markdown({
"English": """
- Eat at least 400g of fruits and vegetables per day.
- Reduce total fat intake, especially saturated and trans fats.
- Limit salt to less than 5g per day.
- Avoid sugar-sweetened beverages and processed snacks.
- Breastfeed exclusively for 6 months where applicable.
""",
"中文": """
- 每天攝取至少400克蔬果
- 減少脂肪攝取,特別是飽和脂肪與反式脂肪
- 每日鹽分少於5克
- 避免含糖飲料與加工零食
- 鼓勵6個月內純母乳哺育(如適用)
""",
"Malay": """
- Makan sekurang-kurangnya 400g buah dan sayur setiap hari
- Kurangkan pengambilan lemak tepu dan lemak trans
- Hadkan garam kurang daripada 5g sehari
- Elakkan minuman bergula dan makanan ringan diproses
- Susukan bayi secara eksklusif selama 6 bulan jika boleh
"""
}[lang])
st.markdown("## " + {
"English": "🧘️♂️ Physical Activity Tips",
"中文": "🧘️♂️ 身體活動建議",
"Malay": "🧘️♂️ Petua Aktiviti Fizikal"
}[lang])
st.markdown({
"English": """
- Adults: At least 150–300 minutes of moderate-intensity aerobic activity weekly
- Children/teens: 60 minutes per day of physical activity
- Reduce sedentary behavior (screen time, sitting)
- Include muscle-strengthening exercises twice a week
""",
"中文": """
- 成人:每週應進行150至300分鐘中等強度的有氧運動
- 兒童與青少年:每天至少60分鐘身體活動
- 減少久坐與看螢幕時間
- 每週應有兩次肌力訓練
""",
"Malay": """
- Dewasa: Sekurang-kurangnya 150–300 minit senaman aerobik sederhana setiap minggu
- Kanak-kanak/remaja: 60 minit sehari aktiviti fizikal
- Kurangkan masa duduk atau menghadap skrin
- Lakukan latihan kekuatan otot dua kali seminggu
"""
}[lang])
MAP_TITLE = {
"English": "🏥 Search Nearby Hospitals",
"中文": "🏥 搜尋附近的醫院",
"Malay": "🏥 Cari Hospital Berdekatan"
}
st.markdown(f"### {MAP_TITLE[lang]}")
st.markdown("""
<iframe src="https://www.google.com/maps?q=hospital+near+me&output=embed"
width="100%" height="400" style="border:0;" allowfullscreen="" loading="lazy">
</iframe>
""", unsafe_allow_html=True)
|