Spaces:
Sleeping
Sleeping
update passing weight
Browse files
app.py
CHANGED
|
@@ -26,13 +26,26 @@ if os.path.exists(font_path):
|
|
| 26 |
plt.rc('font', family='SimHei')
|
| 27 |
plt.rcParams['axes.unicode_minus'] = False
|
| 28 |
|
| 29 |
-
# --- 全域統計狀態變數 ---
|
| 30 |
global_stats = {
|
| 31 |
"total_count": 0,
|
| 32 |
"abnormal_count": 0,
|
| 33 |
"start_time": datetime.datetime.now()
|
| 34 |
}
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
# --- 13 個系統按鈕的對應字典 ---
|
| 37 |
ACTION_MAP = {
|
| 38 |
"教務系統: 期末網路教學評量": "click_eval_system",
|
|
@@ -66,7 +79,7 @@ try:
|
|
| 66 |
le_action = joblib.load('le_action.pkl')
|
| 67 |
|
| 68 |
print("📂 正在讀取本地歷史資料庫...")
|
| 69 |
-
#
|
| 70 |
if os.path.exists('baseline_logs.csv'):
|
| 71 |
baseline_df = pd.read_csv('baseline_logs.csv')
|
| 72 |
else:
|
|
@@ -108,7 +121,7 @@ try:
|
|
| 108 |
))
|
| 109 |
|
| 110 |
AI_READY = True
|
| 111 |
-
print("✅ AI 模組與
|
| 112 |
except Exception as e:
|
| 113 |
AI_READY = False
|
| 114 |
global_stats["total_count"] = 0; global_stats["abnormal_count"] = 0
|
|
@@ -130,7 +143,7 @@ def get_dashboard_html():
|
|
| 130 |
<div class="stat-card card-total">
|
| 131 |
<div class="card-icon">📊</div>
|
| 132 |
<div class="card-content">
|
| 133 |
-
<div class="card-label">總監測量 (
|
| 134 |
<div class="card-value">{total:,} <span class="card-unit">筆 Log</span></div>
|
| 135 |
<div class="card-sub-text">自系統啟動起統計 (+今日即時)</div>
|
| 136 |
</div>
|
|
@@ -244,15 +257,20 @@ def explain_abnormal_log(log_text):
|
|
| 244 |
except Exception as e: return f"⚠️ 呼叫 API 發生錯誤: {str(e)}"
|
| 245 |
|
| 246 |
# --- 2. 核心邏輯與真實 HDBSCAN 異常偵測 ---
|
| 247 |
-
def check_anomaly(ip, account, action, log_time
|
| 248 |
if not AI_READY: return "success"
|
| 249 |
if action in ["login_attempt", "logout"]: return "success"
|
| 250 |
|
| 251 |
try:
|
| 252 |
-
|
| 253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
|
| 255 |
-
# ---
|
| 256 |
current_dt = pd.to_datetime(str(log_time))
|
| 257 |
cutoff_dt = current_dt - pd.Timedelta(seconds=60) # 往前回溯 60 秒
|
| 258 |
|
|
@@ -260,13 +278,11 @@ def check_anomaly(ip, account, action, log_time, ow, tw, iw, dw, gw, fw):
|
|
| 260 |
for log in log_history:
|
| 261 |
log_dt = pd.to_datetime(log['timestamp'])
|
| 262 |
if log_dt >= cutoff_dt:
|
| 263 |
-
# 🌟 修改:同時檢查「同一個帳號」且「同一個動作 (按鈕)」
|
| 264 |
if log.get('account') == account and log.get('action') == action:
|
| 265 |
recent_clicks += 1
|
| 266 |
else:
|
| 267 |
break
|
| 268 |
|
| 269 |
-
# 🌟 修改:依據你要求的階梯式敏感度設定最高容忍次數
|
| 270 |
if fw <= 0: max_allowed_clicks = 100
|
| 271 |
elif fw <= 10: max_allowed_clicks = 90
|
| 272 |
elif fw <= 20: max_allowed_clicks = 80
|
|
@@ -279,7 +295,6 @@ def check_anomaly(ip, account, action, log_time, ow, tw, iw, dw, gw, fw):
|
|
| 279 |
elif fw <= 90: max_allowed_clicks = 9
|
| 280 |
else: max_allowed_clicks = 3
|
| 281 |
|
| 282 |
-
# 觸發條件:若包含這一次的點擊,超過了容忍次數,直接攔截!
|
| 283 |
if (recent_clicks + 1) > max_allowed_clicks:
|
| 284 |
return f"⚠️異常_單一操作頻率過高 ({recent_clicks+1}次/分)"
|
| 285 |
|
|
@@ -342,17 +357,18 @@ def check_anomaly(ip, account, action, log_time, ow, tw, iw, dw, gw, fw):
|
|
| 342 |
except Exception as e:
|
| 343 |
return f"⚠️系統錯誤: {str(e)}"
|
| 344 |
|
| 345 |
-
def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
|
| 346 |
global baseline_X
|
| 347 |
if time_mode == "自訂時間 (模擬過去/未來)" and custom_time and str(custom_time).strip() != "": log_time = str(custom_time)
|
| 348 |
else: log_time = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S")
|
| 349 |
|
| 350 |
if status == "success":
|
| 351 |
-
ai_judgment = check_anomaly(ip, account, action, log_time
|
| 352 |
if ai_judgment != "success": status = ai_judgment
|
| 353 |
|
| 354 |
new_log = {"timestamp": log_time, "ip_address": ip, "cookie_id": cookie, "account": account, "role": role, "action": action, "status": status}
|
| 355 |
|
|
|
|
| 356 |
new_df = pd.DataFrame([new_log])
|
| 357 |
new_df.to_csv('baseline_logs.csv', mode='a', header=not os.path.exists('baseline_logs.csv'), index=False)
|
| 358 |
|
|
@@ -379,45 +395,45 @@ def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
|
|
| 379 |
input_update = gr.update(value=f"時間: {log_time} | IP: {ip} | 帳號: {account} | 動作: {action} | 狀態: {status}") if "異常" in str(status) else gr.update()
|
| 380 |
return df_all, df_abnormal, input_update
|
| 381 |
|
| 382 |
-
def fast_login(target_account, ip, cookie, time_mode, custom_time
|
| 383 |
role, name = USER_DB[target_account][1], USER_DB[target_account][2]
|
| 384 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, target_account, role, "login_attempt", "success", time_mode, custom_time
|
| 385 |
target_tab = "student_tab" if role == "學生" else "admin_tab"
|
| 386 |
return gr.update(selected="dashboard_route"), gr.update(selected=target_tab), "", f"**{name}** 歡迎您 | 線上人數: 938 (⚡快速登入模式)", df_all, df_abn, inp_upd, target_account
|
| 387 |
|
| 388 |
-
def process_login(ip, cookie, account, password, captcha, time_mode, custom_time
|
| 389 |
def fail_response(msg, df_all, df_abn, inp_upd): return gr.update(selected="login_route"), gr.update(), msg, gr.update(), df_all, df_abn, inp_upd
|
| 390 |
if account not in USER_DB:
|
| 391 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, account, "Unknown", "login_attempt", "failed_no_account", time_mode, custom_time
|
| 392 |
return fail_response("帳號不存在!", df_all, df_abn, inp_upd)
|
| 393 |
role, name = USER_DB[account][1], USER_DB[account][2]
|
| 394 |
if captcha.upper() != "FEIK":
|
| 395 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "failed_captcha", time_mode, custom_time
|
| 396 |
return fail_response("驗證碼錯誤!", df_all, df_abn, inp_upd)
|
| 397 |
if USER_DB[account][0] == password:
|
| 398 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "success", time_mode, custom_time
|
| 399 |
return gr.update(selected="dashboard_route"), gr.update(selected="student_tab" if role == "學生" else "admin_tab"), "", f"**{name}** 歡迎您 | 線上人數: 938", df_all, df_abn, inp_upd
|
| 400 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "failed_password", time_mode, custom_time
|
| 401 |
return fail_response("密碼錯誤!", df_all, df_abn, inp_upd)
|
| 402 |
|
| 403 |
-
def toggle_role(current_account, ip, cookie, time_mode, custom_time
|
| 404 |
target_account = "student" if current_account == "admin" else "admin"
|
| 405 |
role, name = USER_DB[target_account][1], USER_DB[target_account][2]
|
| 406 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, target_account, role, "login_attempt", "success", time_mode, custom_time
|
| 407 |
return gr.update(selected="student_tab" if role == "學生" else "admin_tab"), f"**{name}** 歡迎您 | 線上人數: 938 (⚡單鍵切換模式)", df_all, df_abn, inp_upd, target_account
|
| 408 |
|
| 409 |
-
def logout(ip, cookie, account, time_mode, custom_time
|
| 410 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 411 |
-
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "logout", "success", time_mode, custom_time
|
| 412 |
return gr.update(selected="login_route"), "", "", "", "", df_all, df_abn, inp_upd
|
| 413 |
|
| 414 |
-
def simulate_click(ip, cookie, account, button_name, time_mode, custom_time
|
| 415 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 416 |
-
return record_log(ip, cookie, account, role, button_name, "success", time_mode, custom_time
|
| 417 |
|
| 418 |
-
def test_anomaly(ip, cookie, account, action_name, test_time_str
|
| 419 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 420 |
-
return record_log(ip, cookie, account, role, action_name, "success", "自訂時間 (模擬過去/未來)", test_time_str
|
| 421 |
|
| 422 |
def toggle_time_input(mode): return gr.update(visible=(mode == "自訂時間 (模擬過去/未來)"))
|
| 423 |
|
|
@@ -565,18 +581,22 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
|
|
| 565 |
time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
|
| 566 |
btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
|
| 567 |
|
|
|
|
| 568 |
weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
|
|
|
|
|
|
|
|
|
|
| 569 |
update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
|
| 570 |
|
| 571 |
-
login_btn.click(fn=process_login, inputs=[mock_ip, mock_cookie, acc_input, pwd_input, captcha_input, time_mode, custom_time_input]
|
| 572 |
-
logout_btn.click(fn=logout, inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input]
|
| 573 |
|
| 574 |
-
fast_inputs = [mock_ip, mock_cookie, time_mode, custom_time_input]
|
| 575 |
fast_outputs = update_outputs + [acc_input]
|
| 576 |
|
| 577 |
-
btn_fast_student.click(fn=lambda ip, c, tm, ct
|
| 578 |
-
btn_fast_admin.click(fn=lambda ip, c, tm, ct
|
| 579 |
-
btn_toggle_role.click(fn=toggle_role, inputs=[acc_input, mock_ip, mock_cookie, time_mode, custom_time_input]
|
| 580 |
|
| 581 |
action_mapping = [
|
| 582 |
(btn_eval, "click_eval_system"), (btn_pre_select, "click_pre_select_system"), (btn_add_drop, "click_add_drop_system"),
|
|
@@ -588,8 +608,8 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
|
|
| 588 |
|
| 589 |
for btn, action_name in action_mapping:
|
| 590 |
btn.click(
|
| 591 |
-
fn=lambda ip, c, acc, tm, ct,
|
| 592 |
-
inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input]
|
| 593 |
outputs=[store_df_all, store_df_abn, abnormal_log_input]
|
| 594 |
)
|
| 595 |
|
|
@@ -603,8 +623,8 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
|
|
| 603 |
|
| 604 |
for btn, action_name, test_time_str in test_mapping:
|
| 605 |
btn.click(
|
| 606 |
-
fn=lambda ip, c, acc,
|
| 607 |
-
inputs=[mock_ip, mock_cookie, acc_input
|
| 608 |
outputs=[store_df_all, store_df_abn, abnormal_log_input]
|
| 609 |
)
|
| 610 |
|
|
|
|
| 26 |
plt.rc('font', family='SimHei')
|
| 27 |
plt.rcParams['axes.unicode_minus'] = False
|
| 28 |
|
| 29 |
+
# --- 全域統計與狀態變數 ---
|
| 30 |
global_stats = {
|
| 31 |
"total_count": 0,
|
| 32 |
"abnormal_count": 0,
|
| 33 |
"start_time": datetime.datetime.now()
|
| 34 |
}
|
| 35 |
|
| 36 |
+
# 系統防護權重全域變數 (預設值)
|
| 37 |
+
system_weights = {
|
| 38 |
+
"ow": 75.0, "tw": 80.0, "iw": 65.0,
|
| 39 |
+
"dw": 45.0, "gw": 50.0, "fw": 60.0
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
# 專屬更新權重的副程式
|
| 43 |
+
def update_system_weights(ow, tw, iw, dw, gw, fw):
|
| 44 |
+
system_weights.update({
|
| 45 |
+
"ow": float(ow), "tw": float(tw), "iw": float(iw),
|
| 46 |
+
"dw": float(dw), "gw": float(gw), "fw": float(fw)
|
| 47 |
+
})
|
| 48 |
+
|
| 49 |
# --- 13 個系統按鈕的對應字典 ---
|
| 50 |
ACTION_MAP = {
|
| 51 |
"教務系統: 期末網路教學評量": "click_eval_system",
|
|
|
|
| 79 |
le_action = joblib.load('le_action.pkl')
|
| 80 |
|
| 81 |
print("📂 正在讀取本地歷史資料庫...")
|
| 82 |
+
# 直接讀取本地的 baseline_logs.csv,不再向雲端同步
|
| 83 |
if os.path.exists('baseline_logs.csv'):
|
| 84 |
baseline_df = pd.read_csv('baseline_logs.csv')
|
| 85 |
else:
|
|
|
|
| 121 |
))
|
| 122 |
|
| 123 |
AI_READY = True
|
| 124 |
+
print("✅ AI 模組與歷史基準資料載入成功!")
|
| 125 |
except Exception as e:
|
| 126 |
AI_READY = False
|
| 127 |
global_stats["total_count"] = 0; global_stats["abnormal_count"] = 0
|
|
|
|
| 143 |
<div class="stat-card card-total">
|
| 144 |
<div class="card-icon">📊</div>
|
| 145 |
<div class="card-content">
|
| 146 |
+
<div class="card-label">總監測量 (本地歷史資料庫)</div>
|
| 147 |
<div class="card-value">{total:,} <span class="card-unit">筆 Log</span></div>
|
| 148 |
<div class="card-sub-text">自系統啟動起統計 (+今日即時)</div>
|
| 149 |
</div>
|
|
|
|
| 257 |
except Exception as e: return f"⚠️ 呼叫 API 發生錯誤: {str(e)}"
|
| 258 |
|
| 259 |
# --- 2. 核心邏輯與真實 HDBSCAN 異常偵測 ---
|
| 260 |
+
def check_anomaly(ip, account, action, log_time):
|
| 261 |
if not AI_READY: return "success"
|
| 262 |
if action in ["login_attempt", "logout"]: return "success"
|
| 263 |
|
| 264 |
try:
|
| 265 |
+
# 直接從全域變數提取當前權重
|
| 266 |
+
ow = float(system_weights["ow"])
|
| 267 |
+
tw = float(system_weights["tw"])
|
| 268 |
+
iw = float(system_weights["iw"])
|
| 269 |
+
dw = float(system_weights["dw"])
|
| 270 |
+
gw = float(system_weights["gw"])
|
| 271 |
+
fw = float(system_weights["fw"])
|
| 272 |
|
| 273 |
+
# --- 第一道防線 (限縮為單一按鈕判斷,並套用精確的閾值) ---
|
| 274 |
current_dt = pd.to_datetime(str(log_time))
|
| 275 |
cutoff_dt = current_dt - pd.Timedelta(seconds=60) # 往前回溯 60 秒
|
| 276 |
|
|
|
|
| 278 |
for log in log_history:
|
| 279 |
log_dt = pd.to_datetime(log['timestamp'])
|
| 280 |
if log_dt >= cutoff_dt:
|
|
|
|
| 281 |
if log.get('account') == account and log.get('action') == action:
|
| 282 |
recent_clicks += 1
|
| 283 |
else:
|
| 284 |
break
|
| 285 |
|
|
|
|
| 286 |
if fw <= 0: max_allowed_clicks = 100
|
| 287 |
elif fw <= 10: max_allowed_clicks = 90
|
| 288 |
elif fw <= 20: max_allowed_clicks = 80
|
|
|
|
| 295 |
elif fw <= 90: max_allowed_clicks = 9
|
| 296 |
else: max_allowed_clicks = 3
|
| 297 |
|
|
|
|
| 298 |
if (recent_clicks + 1) > max_allowed_clicks:
|
| 299 |
return f"⚠️異常_單一操作頻率過高 ({recent_clicks+1}次/分)"
|
| 300 |
|
|
|
|
| 357 |
except Exception as e:
|
| 358 |
return f"⚠️系統錯誤: {str(e)}"
|
| 359 |
|
| 360 |
+
def record_log(ip, cookie, account, role, action, status, time_mode, custom_time):
|
| 361 |
global baseline_X
|
| 362 |
if time_mode == "自訂時間 (模擬過去/未來)" and custom_time and str(custom_time).strip() != "": log_time = str(custom_time)
|
| 363 |
else: log_time = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S")
|
| 364 |
|
| 365 |
if status == "success":
|
| 366 |
+
ai_judgment = check_anomaly(ip, account, action, log_time)
|
| 367 |
if ai_judgment != "success": status = ai_judgment
|
| 368 |
|
| 369 |
new_log = {"timestamp": log_time, "ip_address": ip, "cookie_id": cookie, "account": account, "role": role, "action": action, "status": status}
|
| 370 |
|
| 371 |
+
# 將產生的新 Log 直接 append (附加) 到本地的 baseline_logs.csv 中
|
| 372 |
new_df = pd.DataFrame([new_log])
|
| 373 |
new_df.to_csv('baseline_logs.csv', mode='a', header=not os.path.exists('baseline_logs.csv'), index=False)
|
| 374 |
|
|
|
|
| 395 |
input_update = gr.update(value=f"時間: {log_time} | IP: {ip} | 帳號: {account} | 動作: {action} | 狀態: {status}") if "異常" in str(status) else gr.update()
|
| 396 |
return df_all, df_abnormal, input_update
|
| 397 |
|
| 398 |
+
def fast_login(target_account, ip, cookie, time_mode, custom_time):
|
| 399 |
role, name = USER_DB[target_account][1], USER_DB[target_account][2]
|
| 400 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, target_account, role, "login_attempt", "success", time_mode, custom_time)
|
| 401 |
target_tab = "student_tab" if role == "學生" else "admin_tab"
|
| 402 |
return gr.update(selected="dashboard_route"), gr.update(selected=target_tab), "", f"**{name}** 歡迎您 | 線上人數: 938 (⚡快速登入模式)", df_all, df_abn, inp_upd, target_account
|
| 403 |
|
| 404 |
+
def process_login(ip, cookie, account, password, captcha, time_mode, custom_time):
|
| 405 |
def fail_response(msg, df_all, df_abn, inp_upd): return gr.update(selected="login_route"), gr.update(), msg, gr.update(), df_all, df_abn, inp_upd
|
| 406 |
if account not in USER_DB:
|
| 407 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, account, "Unknown", "login_attempt", "failed_no_account", time_mode, custom_time)
|
| 408 |
return fail_response("帳號不存在!", df_all, df_abn, inp_upd)
|
| 409 |
role, name = USER_DB[account][1], USER_DB[account][2]
|
| 410 |
if captcha.upper() != "FEIK":
|
| 411 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "failed_captcha", time_mode, custom_time)
|
| 412 |
return fail_response("驗證碼錯誤!", df_all, df_abn, inp_upd)
|
| 413 |
if USER_DB[account][0] == password:
|
| 414 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "success", time_mode, custom_time)
|
| 415 |
return gr.update(selected="dashboard_route"), gr.update(selected="student_tab" if role == "學生" else "admin_tab"), "", f"**{name}** 歡迎您 | 線上人數: 938", df_all, df_abn, inp_upd
|
| 416 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "login_attempt", "failed_password", time_mode, custom_time)
|
| 417 |
return fail_response("密碼錯誤!", df_all, df_abn, inp_upd)
|
| 418 |
|
| 419 |
+
def toggle_role(current_account, ip, cookie, time_mode, custom_time):
|
| 420 |
target_account = "student" if current_account == "admin" else "admin"
|
| 421 |
role, name = USER_DB[target_account][1], USER_DB[target_account][2]
|
| 422 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, target_account, role, "login_attempt", "success", time_mode, custom_time)
|
| 423 |
return gr.update(selected="student_tab" if role == "學生" else "admin_tab"), f"**{name}** 歡迎您 | 線上人數: 938 (⚡單鍵切換模式)", df_all, df_abn, inp_upd, target_account
|
| 424 |
|
| 425 |
+
def logout(ip, cookie, account, time_mode, custom_time):
|
| 426 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 427 |
+
df_all, df_abn, inp_upd = record_log(ip, cookie, account, role, "logout", "success", time_mode, custom_time)
|
| 428 |
return gr.update(selected="login_route"), "", "", "", "", df_all, df_abn, inp_upd
|
| 429 |
|
| 430 |
+
def simulate_click(ip, cookie, account, button_name, time_mode, custom_time):
|
| 431 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 432 |
+
return record_log(ip, cookie, account, role, button_name, "success", time_mode, custom_time)
|
| 433 |
|
| 434 |
+
def test_anomaly(ip, cookie, account, action_name, test_time_str):
|
| 435 |
role = USER_DB.get(account, ["", "Unknown"])[1]
|
| 436 |
+
return record_log(ip, cookie, account, role, action_name, "success", "自訂時間 (模擬過去/未來)", test_time_str)
|
| 437 |
|
| 438 |
def toggle_time_input(mode): return gr.update(visible=(mode == "自訂時間 (模擬過去/未來)"))
|
| 439 |
|
|
|
|
| 581 |
time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
|
| 582 |
btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
|
| 583 |
|
| 584 |
+
# 綁定權重拉桿與更新函式
|
| 585 |
weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
|
| 586 |
+
for w_input in weight_inputs:
|
| 587 |
+
w_input.change(fn=update_system_weights, inputs=weight_inputs, outputs=[])
|
| 588 |
+
|
| 589 |
update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
|
| 590 |
|
| 591 |
+
login_btn.click(fn=process_login, inputs=[mock_ip, mock_cookie, acc_input, pwd_input, captcha_input, time_mode, custom_time_input], outputs=update_outputs)
|
| 592 |
+
logout_btn.click(fn=logout, inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input], outputs=[main_router, acc_input, pwd_input, captcha_input, login_msg, store_df_all, store_df_abn, abnormal_log_input])
|
| 593 |
|
| 594 |
+
fast_inputs = [mock_ip, mock_cookie, time_mode, custom_time_input]
|
| 595 |
fast_outputs = update_outputs + [acc_input]
|
| 596 |
|
| 597 |
+
btn_fast_student.click(fn=lambda ip, c, tm, ct: fast_login("student", ip, c, tm, ct), inputs=fast_inputs, outputs=fast_outputs)
|
| 598 |
+
btn_fast_admin.click(fn=lambda ip, c, tm, ct: fast_login("admin", ip, c, tm, ct), inputs=fast_inputs, outputs=fast_outputs)
|
| 599 |
+
btn_toggle_role.click(fn=toggle_role, inputs=[acc_input, mock_ip, mock_cookie, time_mode, custom_time_input], outputs=[role_tabs, welcome_text, store_df_all, store_df_abn, abnormal_log_input, acc_input])
|
| 600 |
|
| 601 |
action_mapping = [
|
| 602 |
(btn_eval, "click_eval_system"), (btn_pre_select, "click_pre_select_system"), (btn_add_drop, "click_add_drop_system"),
|
|
|
|
| 608 |
|
| 609 |
for btn, action_name in action_mapping:
|
| 610 |
btn.click(
|
| 611 |
+
fn=lambda ip, c, acc, tm, ct, n=action_name: simulate_click(ip, c, acc, n, tm, ct),
|
| 612 |
+
inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input],
|
| 613 |
outputs=[store_df_all, store_df_abn, abnormal_log_input]
|
| 614 |
)
|
| 615 |
|
|
|
|
| 623 |
|
| 624 |
for btn, action_name, test_time_str in test_mapping:
|
| 625 |
btn.click(
|
| 626 |
+
fn=lambda ip, c, acc, n=action_name, t_str=test_time_str: test_anomaly(ip, c, acc, n, t_str),
|
| 627 |
+
inputs=[mock_ip, mock_cookie, acc_input],
|
| 628 |
outputs=[store_df_all, store_df_abn, abnormal_log_input]
|
| 629 |
)
|
| 630 |
|