PhilipL commited on
Commit
6090d14
·
unverified ·
1 Parent(s): 2111b0e

update passing weight

Browse files
Files changed (1) hide show
  1. app.py +58 -38
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
- # 👉 修改點 1: 直接讀取本地的 baseline_logs.csv,不再向雲端同步
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">總監測量 (靜態+動態資料庫)</div>
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, ow, tw, iw, dw, gw, fw):
248
  if not AI_READY: return "success"
249
  if action in ["login_attempt", "logout"]: return "success"
250
 
251
  try:
252
- ow, tw, iw, dw = float(ow), float(tw), float(iw), float(dw)
253
- gw, fw = float(gw), float(fw)
 
 
 
 
 
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, ow, tw, iw, dw, gw, fw):
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw):
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw):
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw)
401
  return fail_response("密碼錯誤!", df_all, df_abn, inp_upd)
402
 
403
- def toggle_role(current_account, ip, cookie, time_mode, custom_time, ow, tw, iw, dw, gw, fw):
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw):
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, ow, tw, iw, dw, gw, fw)
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, ow, tw, iw, dw, gw, fw):
415
  role = USER_DB.get(account, ["", "Unknown"])[1]
416
- return record_log(ip, cookie, account, role, button_name, "success", time_mode, custom_time, ow, tw, iw, dw, gw, fw)
417
 
418
- def test_anomaly(ip, cookie, account, action_name, test_time_str, ow, tw, iw, dw, gw, fw):
419
  role = USER_DB.get(account, ["", "Unknown"])[1]
420
- return record_log(ip, cookie, account, role, action_name, "success", "自訂時間 (模擬過去/未來)", test_time_str, ow, tw, iw, dw, gw, fw)
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] + weight_inputs, outputs=update_outputs)
572
- logout_btn.click(fn=logout, inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input] + weight_inputs, outputs=[main_router, acc_input, pwd_input, captcha_input, login_msg, store_df_all, store_df_abn, abnormal_log_input])
573
 
574
- fast_inputs = [mock_ip, mock_cookie, time_mode, custom_time_input] + weight_inputs
575
  fast_outputs = update_outputs + [acc_input]
576
 
577
- btn_fast_student.click(fn=lambda ip, c, tm, ct, ow, tw, iw, dw, gw, fw: fast_login("student", ip, c, tm, ct, ow, tw, iw, dw, gw, fw), inputs=fast_inputs, outputs=fast_outputs)
578
- btn_fast_admin.click(fn=lambda ip, c, tm, ct, ow, tw, iw, dw, gw, fw: fast_login("admin", ip, c, tm, ct, ow, tw, iw, dw, gw, fw), inputs=fast_inputs, outputs=fast_outputs)
579
- btn_toggle_role.click(fn=toggle_role, inputs=[acc_input, mock_ip, mock_cookie, time_mode, custom_time_input] + weight_inputs, outputs=[role_tabs, welcome_text, store_df_all, store_df_abn, abnormal_log_input, acc_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, ow, tw, iw, dw, gw, fw, n=action_name: simulate_click(ip, c, acc, n, tm, ct, ow, tw, iw, dw, gw, fw),
592
- inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input] + weight_inputs,
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, ow, tw, iw, dw, gw, fw, n=action_name, t_str=test_time_str: test_anomaly(ip, c, acc, n, t_str, ow, tw, iw, dw, gw, fw),
607
- inputs=[mock_ip, mock_cookie, acc_input, overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight],
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