Update app.py
Browse files
app.py
CHANGED
|
@@ -138,7 +138,6 @@ def update_history(current_result_1, current_result_2, history_list):
|
|
| 138 |
<div style="font-size: 18px; color: #666; margin-bottom: 10px; font-weight: bold;">
|
| 139 |
🕒 測驗時間:{now}
|
| 140 |
</div>
|
| 141 |
-
|
| 142 |
<div style="
|
| 143 |
display: flex;
|
| 144 |
flex-direction: row;
|
|
@@ -149,10 +148,8 @@ def update_history(current_result_1, current_result_2, history_list):
|
|
| 149 |
padding-bottom: 15px;
|
| 150 |
margin-bottom: 15px;
|
| 151 |
width: 100%;">
|
| 152 |
-
|
| 153 |
<div style="flex: 1;">{current_result_1}</div>
|
| 154 |
<div style="flex: 1;">{current_result_2}</div>
|
| 155 |
-
|
| 156 |
</div>
|
| 157 |
</div>
|
| 158 |
"""
|
|
@@ -181,6 +178,32 @@ def clear_all():
|
|
| 181 |
# 15個輸入(gen, age, family, q1~q12) + 2個即時結果 + 1個歷史面板
|
| 182 |
return [None] * 15 + ["", ""]
|
| 183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
|
| 185 |
# 定義主要測試功能
|
| 186 |
|
|
@@ -192,94 +215,54 @@ def clear_all():
|
|
| 192 |
def predict_risk(gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12):
|
| 193 |
inputs = [gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12]
|
| 194 |
|
| 195 |
-
# 檢查是否有任何一個選項是 None (未按)
|
| 196 |
if any(v is None or v == "" for v in inputs):
|
| 197 |
-
# 觸發彈出視窗
|
| 198 |
raise gr.Error("⚠️測驗載入有誤:請確保每一題都已填答或查看填答格式是否正確。")
|
| 199 |
|
| 200 |
-
# 1. 跑進度條 (需確保函式參數有 progress=gr.Progress())
|
| 201 |
progress = gr.Progress()
|
| 202 |
progress(0, desc="模型計算中...")
|
| 203 |
|
| 204 |
-
|
| 205 |
-
# 欄位名稱必須與訓練時完全相同
|
| 206 |
-
cols = ["gender", "age", "familysize", "Q2A", "Q4A", "Q19A", "Q20A", "Q28A", "Q21A", "Q26A", "Q37A", "Q42A", "Q11A", "Q12A", "Q27A"
|
| 207 |
-
]
|
| 208 |
input_df = pd.DataFrame([[gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12]], columns=cols)
|
| 209 |
|
| 210 |
progress(0.5, desc="正在分析數據...")
|
| 211 |
-
time.sleep(0.5)
|
| 212 |
|
| 213 |
-
# 3. 使用模型 model 進行預測
|
| 214 |
score = model.predict(input_df)[0]
|
| 215 |
-
progress(1.0, desc="計算完成!")
|
| 216 |
|
| 217 |
-
|
| 218 |
-
# 4. 定義風險標籤
|
| 219 |
if score == 0:
|
| 220 |
label = "低度風險"
|
| 221 |
-
color = "#91cd92"
|
| 222 |
elif score == 1:
|
| 223 |
label = "中度風險"
|
| 224 |
-
color = "#f59e0b"
|
| 225 |
elif score == 2:
|
| 226 |
label = "高度風險"
|
| 227 |
-
color = "#ef4444"
|
| 228 |
else:
|
| 229 |
label = "計算結果有誤,請重新測試。"
|
|
|
|
| 230 |
|
| 231 |
-
# 定義類別分數條
|
| 232 |
a_score = (q1 + q2 + q3 + q4 + q5)
|
| 233 |
d_score = (q6 + q7 + q8 + q9)
|
| 234 |
s_score = (q10 + q11 + q12)
|
| 235 |
t_score = a_score + d_score + s_score
|
| 236 |
-
max_val = 36
|
| 237 |
-
|
| 238 |
-
def make_bar(label, score, max_val, color):
|
| 239 |
-
percent = (score / max_val) * 100
|
| 240 |
-
return f"""
|
| 241 |
-
<div style="margin-bottom: 10px;">
|
| 242 |
-
<div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
|
| 243 |
-
<span style="font-weight: bold;">{label}</span>
|
| 244 |
-
</div>
|
| 245 |
-
<div style="background-color: #e0e0e0; border-radius: 10px; height: 12px; width: 100%;">
|
| 246 |
-
<div style="background-color: {color}; width: {percent}%; height: 100%; border-radius: 10px;"></div>
|
| 247 |
-
</div>
|
| 248 |
-
</div>
|
| 249 |
-
"""
|
| 250 |
|
| 251 |
-
# 5. 準備回傳內容
|
| 252 |
-
# 總分與風險標籤
|
| 253 |
result_score = f"""
|
| 254 |
<div style="text-align: center; font-family: sans-serif;">
|
| 255 |
<h2 style="color: #313230;">您的預測結果為</h2>
|
| 256 |
<h1 style="font-size: 60px; color: {color}; margin: 0;">
|
| 257 |
{label}
|
| 258 |
</h1>
|
| 259 |
-
<h1 style="font-size: 20px; color: #bbbbc2; margin: 0;">
|
| 260 |
-
{t_score}/36
|
| 261 |
-
</h1>
|
| 262 |
</div>
|
| 263 |
"""
|
| 264 |
|
| 265 |
-
|
| 266 |
-
label_html = f"""
|
| 267 |
-
<div style="padding: 20px; background: white; border-radius: 10px; border: 1px solid #ddd;">
|
| 268 |
-
<h2 style="color: #313230;margin-top: 0; margin-bottom: 15px;">各面向之比重</h2>
|
| 269 |
-
{make_bar("焦慮 (Anxiety)", a_score, max_val, "#fccb42")}
|
| 270 |
-
{make_bar("憂鬱 (Depression)", d_score, max_val, "#6dc8fe")}
|
| 271 |
-
{make_bar("壓力 (Stress)", s_score, max_val, "#fb6d6d")}
|
| 272 |
-
</div>
|
| 273 |
-
"""
|
| 274 |
|
| 275 |
-
# 儲存測試資料
|
| 276 |
save_to_google_sheets(inputs, a_score, d_score, s_score, t_score, score)
|
| 277 |
|
| 278 |
-
|
| 279 |
progress(1.0, desc="完成")
|
| 280 |
-
|
| 281 |
return result_score, label_html
|
| 282 |
-
|
| 283 |
|
| 284 |
|
| 285 |
# In[59]:
|
|
@@ -317,26 +300,21 @@ custom_css = """
|
|
| 317 |
#my_green_btn:hover {
|
| 318 |
background-color: #72a473 !important; /* 滑鼠懸停時變深 */
|
| 319 |
}
|
| 320 |
-
|
| 321 |
#my_white_btn {
|
| 322 |
background-color: #ffffff !important;
|
| 323 |
color: black !important;
|
| 324 |
border: 1px solid #e4e4e7;
|
| 325 |
}
|
| 326 |
-
|
| 327 |
#my_white_btn:hover {
|
| 328 |
background-color: #e4e4e7 !important;
|
| 329 |
color: black !important; /* 滑鼠懸停時變深 */
|
| 330 |
}
|
| 331 |
-
|
| 332 |
-
|
| 333 |
.my-custom-panel {
|
| 334 |
background-color: #fffef8 !important;
|
| 335 |
border: 2px solid #e4e4e7 !important;
|
| 336 |
padding: 20px;
|
| 337 |
border-radius: 15px;
|
| 338 |
}
|
| 339 |
-
|
| 340 |
#history_panel .label-wrap span {
|
| 341 |
font-weight: bold !important;
|
| 342 |
}
|
|
@@ -459,8 +437,3 @@ demo.launch()
|
|
| 459 |
|
| 460 |
|
| 461 |
# 如需免費永久托管,需在終端機模式執行「gradio deploy」部署到 Hugging Face Spaces。
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
|
|
|
| 138 |
<div style="font-size: 18px; color: #666; margin-bottom: 10px; font-weight: bold;">
|
| 139 |
🕒 測驗時間:{now}
|
| 140 |
</div>
|
|
|
|
| 141 |
<div style="
|
| 142 |
display: flex;
|
| 143 |
flex-direction: row;
|
|
|
|
| 148 |
padding-bottom: 15px;
|
| 149 |
margin-bottom: 15px;
|
| 150 |
width: 100%;">
|
|
|
|
| 151 |
<div style="flex: 1;">{current_result_1}</div>
|
| 152 |
<div style="flex: 1;">{current_result_2}</div>
|
|
|
|
| 153 |
</div>
|
| 154 |
</div>
|
| 155 |
"""
|
|
|
|
| 178 |
# 15個輸入(gen, age, family, q1~q12) + 2個即時結果 + 1個歷史面板
|
| 179 |
return [None] * 15 + ["", ""]
|
| 180 |
|
| 181 |
+
# 排名設定
|
| 182 |
+
def make_rank_list(a_score, d_score, s_score):
|
| 183 |
+
items = [
|
| 184 |
+
("焦慮 (Anxiety)", a_score),
|
| 185 |
+
("憂鬱 (Depression)", d_score),
|
| 186 |
+
("壓力 (Stress)", s_score),
|
| 187 |
+
]
|
| 188 |
+
items_sorted = sorted(items, key=lambda x: x[1], reverse=True)
|
| 189 |
+
|
| 190 |
+
medal = ["🥇", "🥈", "🥉"]
|
| 191 |
+
rows = ""
|
| 192 |
+
|
| 193 |
+
for i, (name, _) in enumerate(items_sorted):
|
| 194 |
+
rows += f"""
|
| 195 |
+
<div style="display:flex; justify-content:space-between; padding:10px 0; border-bottom:1px solid #eee;">
|
| 196 |
+
<div style="font-size:18px;">{medal[i]} {name}</div>
|
| 197 |
+
<div style="font-size:18px; color:#666;">第 {i+1} 名</div>
|
| 198 |
+
</div>
|
| 199 |
+
"""
|
| 200 |
+
|
| 201 |
+
return f"""
|
| 202 |
+
<div style="padding: 20px; background: white; border-radius: 10px; border: 1px solid #ddd;">
|
| 203 |
+
<h2 style="color:#313230; margin-top:0; margin-bottom:10px;">各面向排名</h2>
|
| 204 |
+
{rows}
|
| 205 |
+
</div>
|
| 206 |
+
"""
|
| 207 |
|
| 208 |
# 定義主要測試功能
|
| 209 |
|
|
|
|
| 215 |
def predict_risk(gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12):
|
| 216 |
inputs = [gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12]
|
| 217 |
|
|
|
|
| 218 |
if any(v is None or v == "" for v in inputs):
|
|
|
|
| 219 |
raise gr.Error("⚠️測驗載入有誤:請確保每一題都已填答或查看填答格式是否正確。")
|
| 220 |
|
|
|
|
| 221 |
progress = gr.Progress()
|
| 222 |
progress(0, desc="模型計算中...")
|
| 223 |
|
| 224 |
+
cols = ["gender", "age", "familysize", "Q2A", "Q4A", "Q19A", "Q20A", "Q28A", "Q21A", "Q26A", "Q37A", "Q42A", "Q11A", "Q12A", "Q27A"]
|
|
|
|
|
|
|
|
|
|
| 225 |
input_df = pd.DataFrame([[gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12]], columns=cols)
|
| 226 |
|
| 227 |
progress(0.5, desc="正在分析數據...")
|
| 228 |
+
time.sleep(0.5)
|
| 229 |
|
|
|
|
| 230 |
score = model.predict(input_df)[0]
|
|
|
|
| 231 |
|
|
|
|
|
|
|
| 232 |
if score == 0:
|
| 233 |
label = "低度風險"
|
| 234 |
+
color = "#91cd92"
|
| 235 |
elif score == 1:
|
| 236 |
label = "中度風險"
|
| 237 |
+
color = "#f59e0b"
|
| 238 |
elif score == 2:
|
| 239 |
label = "高度風險"
|
| 240 |
+
color = "#ef4444"
|
| 241 |
else:
|
| 242 |
label = "計算結果有誤,請重新測試。"
|
| 243 |
+
color = "#999999"
|
| 244 |
|
|
|
|
| 245 |
a_score = (q1 + q2 + q3 + q4 + q5)
|
| 246 |
d_score = (q6 + q7 + q8 + q9)
|
| 247 |
s_score = (q10 + q11 + q12)
|
| 248 |
t_score = a_score + d_score + s_score
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
|
|
|
|
|
|
|
| 250 |
result_score = f"""
|
| 251 |
<div style="text-align: center; font-family: sans-serif;">
|
| 252 |
<h2 style="color: #313230;">您的預測結果為</h2>
|
| 253 |
<h1 style="font-size: 60px; color: {color}; margin: 0;">
|
| 254 |
{label}
|
| 255 |
</h1>
|
|
|
|
|
|
|
|
|
|
| 256 |
</div>
|
| 257 |
"""
|
| 258 |
|
| 259 |
+
label_html = make_rank_list(a_score, d_score, s_score)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
|
|
|
| 261 |
save_to_google_sheets(inputs, a_score, d_score, s_score, t_score, score)
|
| 262 |
|
|
|
|
| 263 |
progress(1.0, desc="完成")
|
|
|
|
| 264 |
return result_score, label_html
|
| 265 |
+
|
| 266 |
|
| 267 |
|
| 268 |
# In[59]:
|
|
|
|
| 300 |
#my_green_btn:hover {
|
| 301 |
background-color: #72a473 !important; /* 滑鼠懸停時變深 */
|
| 302 |
}
|
|
|
|
| 303 |
#my_white_btn {
|
| 304 |
background-color: #ffffff !important;
|
| 305 |
color: black !important;
|
| 306 |
border: 1px solid #e4e4e7;
|
| 307 |
}
|
|
|
|
| 308 |
#my_white_btn:hover {
|
| 309 |
background-color: #e4e4e7 !important;
|
| 310 |
color: black !important; /* 滑鼠懸停時變深 */
|
| 311 |
}
|
|
|
|
|
|
|
| 312 |
.my-custom-panel {
|
| 313 |
background-color: #fffef8 !important;
|
| 314 |
border: 2px solid #e4e4e7 !important;
|
| 315 |
padding: 20px;
|
| 316 |
border-radius: 15px;
|
| 317 |
}
|
|
|
|
| 318 |
#history_panel .label-wrap span {
|
| 319 |
font-weight: bold !important;
|
| 320 |
}
|
|
|
|
| 437 |
|
| 438 |
|
| 439 |
# 如需免費永久托管,需在終端機模式執行「gradio deploy」部署到 Hugging Face Spaces。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|