| |
| |
|
|
| |
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
| import pandas as pd |
| import matplotlib.pyplot as plt |
| import numpy as np |
| import gradio as gr |
| import sklearn |
| import pickle |
| import joblib |
| import time |
| import os |
| import json |
| import gspread |
|
|
|
|
| from sklearn.model_selection import train_test_split, RandomizedSearchCV |
| from sklearn.compose import ColumnTransformer |
| from sklearn.preprocessing import OneHotEncoder, StandardScaler |
| from sklearn.pipeline import Pipeline |
| from sklearn.linear_model import LogisticRegression |
| from sklearn.metrics import classification_report, confusion_matrix, f1_score, accuracy_score, precision_score, balanced_accuracy_score |
| from sklearn.ensemble import RandomForestClassifier |
| from lightgbm import LGBMClassifier |
| from AutoPreprocess import AutoPreprocess |
| from google.oauth2.service_account import Credentials |
| from datetime import datetime, timezone, timedelta |
|
|
|
|
| |
|
|
| |
|
|
|
|
| |
| import pickle |
| model_path = os.path.abspath("DASS_model.bin") |
|
|
| with open(model_path, "rb") as f: |
| model = pickle.load(f) |
| model |
|
|
|
|
| |
|
|
| |
|
|
|
|
| import os |
| import json |
| from datetime import datetime, timezone, timedelta |
| import gspread |
| from google.oauth2.service_account import Credentials |
|
|
| |
| tw_timezone = timezone(timedelta(hours=8)) |
|
|
| def save_to_google_sheets(inputs, a_score, d_score, s_score, t_score, score): |
|
|
| |
| scope = ['https://www.googleapis.com/auth/spreadsheets', |
| 'https://www.googleapis.com/auth/drive'] |
|
|
| |
| google_json = os.environ.get("DASS_JSON") |
| info = json.loads(google_json) |
| creds = Credentials.from_service_account_info(info, scopes=scope) |
| client = gspread.authorize(creds) |
|
|
| |
| sheet = client.open("DASS使用者測試資料").sheet1 |
|
|
|
|
| |
| user_info = inputs[:3] |
| q_answers = inputs[3:] |
| now = datetime.now(tw_timezone).strftime("%Y-%m-%d %H:%M:%S") |
|
|
| |
| row_to_add = [ |
| now, |
| user_info[0], |
| user_info[1], |
| user_info[2], |
| a_score, |
| d_score, |
| s_score, |
| t_score, |
| score |
| ] |
|
|
| row_to_add.extend(q_answers) |
|
|
| |
|
|
| def to_py(v): |
| return v.item() if hasattr(v, "item") else v |
|
|
| row_to_add = [to_py(x) for x in row_to_add] |
|
|
| sheet.append_row(row_to_add) |
|
|
| def save_to_google_sheets_full42(inputs, dep_score, anx_score, str_score, overall, answers42): |
| scope = ['https://www.googleapis.com/auth/spreadsheets', |
| 'https://www.googleapis.com/auth/drive'] |
|
|
| google_json = os.environ.get("DASS_JSON") |
| info = json.loads(google_json) |
| creds = Credentials.from_service_account_info(info, scopes=scope) |
| client = gspread.authorize(creds) |
|
|
| sh = client.open("DASS使用者測試資料") |
|
|
| ws_title = "DASS42_完整版" |
| try: |
| sheet = sh.worksheet(ws_title) |
| except gspread.exceptions.WorksheetNotFound: |
| sheet = sh.add_worksheet(title=ws_title, rows=2000, cols=60) |
|
|
| header = ( |
| ["測試時間", "性別", "年齡", "家庭人數", |
| "焦慮分數", "憂鬱分數", "壓力分數", "總體分數", "整體程度"] |
| + [f"Q{i}" for i in range(1, 43)] |
| ) |
|
|
| if sheet.acell("A1").value in (None, ""): |
| sheet.update("A1", [header]) |
|
|
| |
| now = datetime.now(tw_timezone).strftime("%Y-%m-%d %H:%M:%S") |
|
|
| |
| _, gen, age, family = inputs[0], inputs[1], inputs[2], inputs[3] |
|
|
| |
| if family == "15人以上": |
| family = 16 |
|
|
| t_score = dep_score + anx_score + str_score |
|
|
| row_to_add = [ |
| now, |
| gen, |
| age, |
| family, |
| anx_score, |
| dep_score, |
| str_score, |
| t_score, |
| overall |
| ] |
|
|
| row_to_add.extend(list(answers42)) |
|
|
| def to_py(v): |
| return v.item() if hasattr(v, "item") else v |
|
|
| row_to_add = [to_py(x) for x in row_to_add] |
|
|
| sheet.append_row(row_to_add) |
|
|
|
|
| |
|
|
| |
|
|
|
|
| def update_history(current_result_1, current_result_2, history_list): |
| """ |
| current_result_1 & 2: 來自 predict_risk 的兩個回傳值 (HTML 字串) |
| history_list: 來自 gr.State 的現有紀錄列表 |
| """ |
|
|
| |
| now = datetime.now(tw_timezone).strftime("%Y-%m-%d %H:%M:%S") |
|
|
| |
| new_entry = f""" |
| <div style="border-bottom: 2px solid #eee; padding-bottom: 20px; margin-bottom: 20px;"> |
| <div style="font-size: 18px; color: #666; margin-bottom: 10px; font-weight: bold;"> |
| 🕒 測驗時間:{now} |
| </div> |
| <div style=" |
| display: flex; |
| flex-direction: row; |
| justify-content: space-between; |
| align-items: flex-start; |
| gap: 20px; |
| border-bottom: 1px dashed #ccc; |
| padding-bottom: 15px; |
| margin-bottom: 15px; |
| width: 100%;"> |
| <div style="flex: 1;">{current_result_1}</div> |
| <div style="flex: 1;">{current_result_2}</div> |
| </div> |
| </div> |
| """ |
|
|
| |
| history_list.insert(0, new_entry) |
|
|
| |
| |
| combined_html = f""" |
| <div style="zoom: 0.8; -moz-transform: scale(0.8); -moz-transform-origin: 0 0;"> |
| {"".join(history_list)} |
| </div> |
| """ |
|
|
| return combined_html, history_list |
|
|
|
|
| |
|
|
| |
|
|
|
|
| |
| def clear_all(): |
| |
| return [None] * 15 + ["", ""] |
|
|
| |
| def make_rank_list(a_score, d_score, s_score): |
| items = [ |
| ("焦慮 (Anxiety)", a_score), |
| ("憂鬱 (Depression)", d_score), |
| ("壓力 (Stress)", s_score), |
| ] |
| items_sorted = sorted(items, key=lambda x: x[1], reverse=True) |
|
|
| medal = ["🥇", "🥈", "🥉"] |
| rows = "" |
|
|
| for i, (name, _) in enumerate(items_sorted): |
| rows += f""" |
| <div style="display:flex; justify-content:space-between; padding:10px 0; border-bottom:1px solid #eee;"> |
| <div style="font-size:18px;">{medal[i]} {name}</div> |
| <div style="font-size:18px; color:#666;">第 {i+1} 名</div> |
| </div> |
| """ |
|
|
| return f""" |
| <div style="padding: 20px; background: white; border-radius: 10px; border: 1px solid #ddd;"> |
| <h2 style="color:#313230; margin-top:0; margin-bottom:10px;">各面向排名</h2> |
| {rows} |
| </div> |
| """ |
|
|
| |
|
|
| |
|
|
|
|
|
|
| |
|
|
| dep_nums = [3,5,10,13,16,17,21,24,26,31,34,37,38,42] |
| anx_nums = [2,4,7,9,15,19,20,23,25,28,30,36,40,41] |
| str_nums = [1,6,8,11,12,14,18,22,27,29,32,33,35,39] |
|
|
| def qcols(nums): |
| return [f"Q{n}A" for n in nums] |
|
|
| def level_dep(score): |
| |
| if score <= 9: return 0 |
| if score <= 13: return 1 |
| if score <= 20: return 2 |
| if score <= 27: return 3 |
| return 4 |
|
|
| def level_anx(score): |
| |
| if score <= 7: return 0 |
| if score <= 9: return 1 |
| if score <= 14: return 2 |
| if score <= 19: return 3 |
| return 4 |
|
|
| def level_str(score): |
| |
| if score <= 14: return 0 |
| if score <= 18: return 1 |
| if score <= 25: return 2 |
| if score <= 33: return 3 |
| return 4 |
|
|
| LEVEL_NAME = {0:"正常", 1:"輕度", 2:"中度", 3:"重度", 4:"極重度"} |
|
|
| def overall_severity_v2(d_level, a_level, s_level): |
| total = d_level + a_level + s_level |
| if (d_level == 4) or (a_level == 4) or (s_level == 4): |
| return 2 |
| if total >= 9: |
| return 2 |
| if (d_level == 3) or (a_level == 3) or (s_level == 3): |
| return 1 |
| if total <= 5: |
| return 0 |
| else: |
| return 1 |
|
|
| OVERALL_NAME = { |
| 0:"低度風險", |
| 1:"中度風險", |
| 2:"高度風險"} |
|
|
| OVERALL_COLOR = { |
| 0: "#91cd92", |
| 1: "#f59e0b", |
| 2: "#ef4444", |
| } |
|
|
| def predict_dass42_full(name, gen, age, family, *answers): |
| """ |
| 完整版:42題官方計分(0-3) |
| 回傳:只顯示 Overall(v2)(大字置中)+ 右側排名卡(保留) |
| 並寫入 Google Sheet(DASS42_完整版) |
| """ |
| inputs = [name, gen, age, family] + list(answers) |
| if any(v is None or v == "" for v in inputs): |
| raise gr.Error("⚠️請確保基本資料與 42 題都已填答。") |
|
|
| |
| row = {f"Q{i+1}A": int(answers[i]) for i in range(42)} |
|
|
| |
| dep_score = sum(row[c] for c in qcols(dep_nums)) |
| anx_score = sum(row[c] for c in qcols(anx_nums)) |
| str_score = sum(row[c] for c in qcols(str_nums)) |
|
|
| |
| dep_level = level_dep(dep_score) |
| anx_level = level_anx(anx_score) |
| str_level = level_str(str_score) |
|
|
| |
| overall = overall_severity_v2(dep_level, anx_level, str_level) |
|
|
| |
| |
| save_to_google_sheets_full42( |
| inputs=[name, gen, age, family], |
| dep_score=dep_score, |
| anx_score=anx_score, |
| str_score=str_score, |
| overall=overall, |
| answers42=answers |
| ) |
|
|
| |
| color = OVERALL_COLOR.get(overall, "#999999") |
| text = OVERALL_NAME.get(overall, str(overall)) |
|
|
| |
| result_html = f""" |
| <div style="text-align:center; font-family:sans-serif; padding: 40px 0;"> |
| <div style="font-size: 44px; font-weight: 900; color:#313230; margin-bottom: 26px;"> |
| 您的預測結果為 |
| </div> |
| <div style="font-size: 96px; font-weight: 900; color:{color}; line-height: 1;"> |
| {text} |
| </div> |
| </div> |
| """ |
|
|
| |
| rank_html = make_rank_list(anx_score, dep_score, str_score) |
|
|
| return result_html, rank_html |
| |
| |
|
|
| def predict_risk(gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12): |
| inputs = [gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12] |
|
|
| if any(v is None or v == "" for v in inputs): |
| raise gr.Error("⚠️測驗載入有誤:請確保每一題都已填答或查看填答格式是否正確。") |
|
|
| progress = gr.Progress() |
| progress(0, desc="模型計算中...") |
|
|
| |
| age = int(age) |
|
|
| |
| if family == "15人以上": |
| family = 16 |
| else: |
| family = int(family) |
| |
| cols = ["gender", "age", "familysize", "Q2A", "Q4A", "Q19A", "Q20A", "Q28A", "Q21A", "Q26A", "Q37A", "Q42A", "Q11A", "Q12A", "Q27A"] |
| input_df = pd.DataFrame([[gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12]], columns=cols) |
|
|
| progress(0.5, desc="正在分析數據...") |
| time.sleep(0.5) |
|
|
| score = model.predict(input_df)[0] |
|
|
| if score == 0: |
| label = "低度風險" |
| color = "#91cd92" |
| elif score == 1: |
| label = "中度風險" |
| color = "#f59e0b" |
| elif score == 2: |
| label = "高度風險" |
| color = "#ef4444" |
| else: |
| label = "計算結果有誤,請重新測試。" |
| color = "#999999" |
|
|
| a_score = (q1 + q2 + q3 + q4 + q5) |
| d_score = (q6 + q7 + q8 + q9) |
| s_score = (q10 + q11 + q12) |
| t_score = a_score + d_score + s_score |
|
|
| result_score = f""" |
| <div style="text-align: center; font-family: sans-serif;"> |
| <h2 style="color: #313230;">您的預測結果為</h2> |
| <h1 style="font-size: 60px; color: {color}; margin: 0;"> |
| {label} |
| </h1> |
| </div> |
| """ |
|
|
| label_html = make_rank_list(a_score, d_score, s_score) |
|
|
| save_to_google_sheets(inputs, a_score, d_score, s_score, t_score, score) |
|
|
| progress(1.0, desc="完成") |
| return result_score, label_html |
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
| theme = gr.themes.Default( |
| primary_hue="amber", |
| secondary_hue="amber", |
| ).set( |
| body_background_fill="#fffbeb" |
| ) |
|
|
|
|
| |
|
|
|
|
| |
| |
|
|
|
|
| |
|
|
|
|
| |
|
|
| |
| custom_css = """ |
| #my_green_btn { |
| background-color: #91cd92 !important; |
| color: white !important; |
| border: none; |
| } |
| #my_green_btn:hover { |
| background-color: #72a473 !important; /* 滑鼠懸停時變深 */ |
| } |
| #my_white_btn { |
| background-color: #ffffff !important; |
| color: black !important; |
| border: 1px solid #e4e4e7; |
| } |
| #my_white_btn:hover { |
| background-color: #e4e4e7 !important; |
| color: black !important; /* 滑鼠懸停時變深 */ |
| } |
| .my-custom-panel { |
| background-color: #fffef8 !important; |
| border: 2px solid #e4e4e7 !important; |
| padding: 20px; |
| border-radius: 15px; |
| } |
| #history_panel .label-wrap span { |
| font-weight: bold !important; |
| } |
| """ |
|
|
|
|
| |
|
|
| age_choices = list(range(1, 100)) |
| family_choices = list(range(1, 16)) + ["15人以上"] |
|
|
| with gr.Blocks() as demo: |
| |
| history_state = gr.State([]) |
|
|
| gr.Markdown("") |
| gr.HTML(""" |
| <div style="text-align: center; font-family: sans-serif;"> |
| <h2 style="font-size: 32px; color: #313230; margin: 0;">🌿心理健康風險程度測試📝</h2> |
| </div> |
| """) |
|
|
| with gr.Tabs(): |
|
|
| |
| |
| |
| with gr.TabItem("簡易版 12題"): |
|
|
| gr.HTML(""" |
| <div style="text-align: center; font-family: sans-serif;"> |
| <h2 style="font-size: 18px; color: #313230; margin: 0;">歡迎來到心理健康風險程度測試環境!<br> |
| 本測驗將透過12題問答,替您在5分鐘內簡單計算出潛在的心理健康風險程度。<br> |
| 請輕鬆填答,無須思慮過度,測驗愉快!</h2> |
| </div> |
| """) |
|
|
| with gr.Column(variant="panel", elem_classes="my-custom-panel"): |
| gr.Markdown("## Step 1. 請輸入基本資訊") |
| with gr.Row(): |
| with gr.Column(): |
| name = gr.Textbox(label="暱稱") |
| gen = gr.Dropdown(choices=["男", "女", "其他"], label="性別") |
| with gr.Column(): |
| age = gr.Dropdown( |
| choices=age_choices, |
| label="年齡", |
| value=None |
| ) |
| |
| family = gr.Dropdown( |
| choices=family_choices, |
| label="家庭人數", |
| value=None |
| ) |
|
|
| gr.Markdown("## Step 2. 請依自身狀態選擇符合的答案") |
| q1 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q1.我感覺到口乾舌燥。") |
| q2 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q2.我感到呼吸困難(例如:在沒有體力勞動的情況下,呼吸過度急促或喘不過氣)。") |
| q3 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q3.在氣溫不高或沒有體力勞動的情況下,我明顯地流汗(例如:手汗)。") |
| q4 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q4.我無緣無故地感到害怕。") |
| q5 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q5.我覺得自己接近恐慌發作的邊緣。") |
| q6 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q6.我覺得生命沒什麼意義/價值。") |
| q7 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q7.我感到垂頭喪氣、情緒低落。") |
| q8 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q8.我覺得未來毫無希望。") |
| q9 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q9.我發現自己很難打起精神主動去做事。") |
| q10 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q10.我發現自己很容易變得心煩意亂。") |
| q11 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q11.我覺得自己消耗了大量的神經能量(處於高度緊繃狀態)。") |
| q12 = gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label="Q12.我發現自己非常易怒(容易焦躁)。") |
|
|
| sub_button = gr.Button("確認送出", elem_id="my_green_btn") |
| btn_reset = gr.Button("重新測驗", elem_id="my_white_btn") |
|
|
| with gr.Row(): |
| out_html = gr.HTML() |
| out_label = gr.HTML() |
|
|
| with gr.Accordion("查看歷史紀錄", open=False, elem_id="history_panel"): |
| history_display = gr.HTML(value="目前尚無測驗紀錄") |
|
|
| sub_button.click( |
| fn=predict_risk, |
| inputs=[gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12], |
| outputs=[out_html, out_label], |
| ).then( |
| fn=update_history, |
| inputs=[out_html, out_label, history_state], |
| outputs=[history_display, history_state], |
| ) |
|
|
| btn_reset.click( |
| fn=lambda: [None]*15 + ["", ""], |
| inputs=None, |
| outputs=[gen, age, family, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, out_html, out_label], |
| ) |
|
|
| gr.Markdown("## 免責聲明") |
| gr.Markdown("""本測驗結果僅供參考,非屬正規醫療檢驗範疇。 |
| 若對於自身狀況有任何疑慮,敬請尋求正規專業醫療協助!♡第四組關心您♡""") |
|
|
| |
| |
| |
| with gr.TabItem("完整版 42題"): |
|
|
| |
| full_history_state = gr.State([]) |
|
|
| gr.HTML(""" |
| <div style="text-align: center; font-family: sans-serif; margin-bottom: 6px;"> |
| <h2 style="font-size: 18px; color: #313230; margin: 0;"> |
| 歡迎來到 DASS-42 完整版心理測驗!<br> |
| 本測驗將依 42 題官方計分規則,計算您的心理狀態並輸出風險程度。<br> |
| 請依過去一週的感受作答,測驗愉快! |
| </h2> |
| </div> |
| """) |
|
|
| gr.Markdown("## Step 1. 請輸入基本資訊") |
| with gr.Row(): |
| with gr.Column(): |
| full_name = gr.Textbox(label="暱稱") |
| full_gen = gr.Dropdown(choices=["男", "女", "其他"], label="性別") |
| with gr.Column(): |
| full_age = gr.Dropdown( |
| choices=age_choices, |
| label="年齡", |
| value=None |
| ) |
| |
| full_family = gr.Dropdown( |
| choices=family_choices, |
| label="家庭人數", |
| value=None |
| ) |
|
|
| gr.Markdown("## Step 2. DASS-42(0~3)") |
|
|
| dass42_questions = [ |
| "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. 我發覺難以產生動力去做事", |
| ] |
|
|
| full_q_widgets = [] |
| for q_text in dass42_questions: |
| full_q_widgets.append( |
| gr.Radio([("從不", 0), ("偶爾", 1), ("經常", 2), ("總是", 3)], label=q_text) |
| ) |
|
|
| full_submit = gr.Button("確認送出(計算完整版分數)", elem_id="my_green_btn") |
|
|
| with gr.Row(): |
| full_out_html = gr.HTML() |
| full_out_rank = gr.HTML() |
|
|
| with gr.Accordion("查看歷史紀錄(完整版)", open=False, elem_id="history_panel"): |
| full_history_display = gr.HTML(value="目前尚無測驗紀錄") |
|
|
| full_submit.click( |
| fn=predict_dass42_full, |
| inputs=[full_name, full_gen, full_age, full_family] + full_q_widgets, |
| outputs=[full_out_html, full_out_rank], |
| ).then( |
| fn=update_history, |
| inputs=[full_out_html, full_out_rank, full_history_state], |
| outputs=[full_history_display, full_history_state], |
| ) |
|
|
| gr.Markdown("## 免責聲明") |
| gr.Markdown("""本測驗結果僅供參考,非屬正規醫療檢驗範疇。 |
| 若對於自身狀況有任何疑慮,敬請尋求正規專業醫療協助!♡第四組關心您♡""") |
|
|
|
|
| demo.launch(theme=theme, css=custom_css) |