PhilipL commited on
Commit
57f41df
·
unverified ·
1 Parent(s): c4461f6

dynamic history data

Browse files
Files changed (1) hide show
  1. app.py +18 -11
app.py CHANGED
@@ -52,23 +52,33 @@ ACTION_MAP = {
52
  log_history = []
53
  initial_df_abn = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
54
 
55
- # --- 1. 載入模型與歷史資料 ---
56
  try:
57
  le_action = joblib.load('le_action.pkl')
58
  le_ip = joblib.load('le_ip.pkl')
59
 
60
- baseline_df = pd.read_csv('baseline_logs.csv')
 
 
 
 
 
 
 
 
61
  baseline_df['timestamp'] = pd.to_datetime(baseline_df['timestamp'])
62
 
 
63
  global_stats["total_count"] = len(baseline_df)
64
  global_stats["abnormal_count"] = baseline_df[baseline_df['status'].str.contains("異常", na=False)].shape[0]
65
  print(f"📊 統計初始化:總監測量 {global_stats['total_count']}, 異常數 {global_stats['abnormal_count']}")
66
 
67
- # 🌟 修正點 1:將 Timestamp 強制轉為字串,避免前端 JS 崩潰卡讀取
68
  display_df = baseline_df.sort_values(by='timestamp', ascending=False).head(20).copy()
69
  display_df['timestamp'] = display_df['timestamp'].dt.strftime('%Y-%m-%d %H:%M:%S')
70
  log_history = display_df.to_dict('records')
71
 
 
72
  initial_abnormal_logs = [log for log in log_history if "異常" in str(log.get("status", ""))]
73
  if initial_abnormal_logs:
74
  initial_df_abn = pd.DataFrame(initial_abnormal_logs)
@@ -86,7 +96,7 @@ try:
86
  ))
87
 
88
  AI_READY = True
89
- print("✅ AI 模組與歷史基準資料載入成功!")
90
  except Exception as e:
91
  AI_READY = False
92
  global_stats["total_count"] = 0
@@ -116,7 +126,7 @@ def get_dashboard_html():
116
  <div class="stat-card card-total">
117
  <div class="card-icon">📊</div>
118
  <div class="card-content">
119
- <div class="card-label">總監測量 (預警流量)</div>
120
  <div class="card-value">{total:,} <span class="card-unit">筆 Log</span></div>
121
  <div class="card-sub-text">自系統啟動起統計 (+今日即時)</div>
122
  </div>
@@ -456,7 +466,7 @@ custom_css = """
456
 
457
  with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
458
 
459
- # 🌟 修正點 2:建立隱形的 State,作為 Dataframe 的獨立資料載體 (解耦)
460
  store_df_all = gr.State(value=pd.DataFrame(log_history))
461
  store_df_abn = gr.State(value=initial_df_abn)
462
 
@@ -472,7 +482,6 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
472
  custom_time_input = gr.Textbox(label="輸入自訂時間", placeholder="格式: YYYY-MM-DD HH:MM:SS", value="2026-03-17 03:00:00", visible=False)
473
  gr.Markdown("---")
474
  gr.Markdown("### 📊 即時 Log 與 AI 判定區")
475
- # 🌟 指定吃 Pandas Dataframe 以維持最穩定的序列化
476
  log_display = gr.Dataframe(value=pd.DataFrame(log_history), headers=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"], datatype=["str", "str", "str", "str", "str", "str", "str"], interactive=False, wrap=True)
477
 
478
  with gr.Column(scale=2):
@@ -585,7 +594,6 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
585
  with gr.Row():
586
  t_vdesk_norm = gr.Button("✅ 正常: 軟體雲/WebMail (03-22 18:00)", size="sm"); t_vdesk_anom = gr.Button("⚠️ 異常: 軟體雲/WebMail (08-10 00:00)", size="sm")
587
 
588
- # --- 🌟 修正點 3:綁定 State 更新到實體的 Dataframe (確保 DOM 渲染完畢後才餵入資料) ---
589
  def update_dataframes(df_all, df_abn):
590
  return gr.update(value=df_all), gr.update(value=df_abn)
591
 
@@ -600,7 +608,6 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
600
 
601
  weight_inputs = [overall_weight, time_weight, ip_weight, device_weight]
602
 
603
- # 🎯 把輸出目標從實體 Dataframe 改為背後的 State
604
  update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
605
 
606
  login_btn.click(
@@ -636,7 +643,7 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
636
  btn.click(
637
  fn=lambda ip, c, acc, t_mode, t_custom, ow, tw, iw, dw, n=action_name: simulate_click(ip, c, acc, n, t_mode, t_custom, ow, tw, iw, dw),
638
  inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input] + weight_inputs,
639
- outputs=[store_df_all, store_df_abn, abnormal_log_input] # 🎯 同步改為輸出給 State
640
  )
641
 
642
  test_mapping = [
@@ -657,7 +664,7 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
657
  btn.click(
658
  fn=lambda ip, c, acc, ow, tw, iw, dw, n=action_name, t_str=test_time_str: test_anomaly(ip, c, acc, n, t_str, ow, tw, iw, dw),
659
  inputs=[mock_ip, mock_cookie, acc_input, overall_weight, time_weight, ip_weight, device_weight],
660
- outputs=[store_df_all, store_df_abn, abnormal_log_input] # 🎯 同步改為輸出給 State
661
  )
662
 
663
  if __name__ == "__main__":
 
52
  log_history = []
53
  initial_df_abn = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
54
 
55
+ # --- 1. 載入模型與歷史資料 (結合 logger_service 雲端同步) ---
56
  try:
57
  le_action = joblib.load('le_action.pkl')
58
  le_ip = joblib.load('le_ip.pkl')
59
 
60
+ # 🌟 核心升級:啟動時直接從 Hugging Face 雲端拉取最新動態歷史資料庫
61
+ print("🔄 正在從 Hugging Face 雲端同步最新動態歷史資料...")
62
+ baseline_df = logger_service.sync_from_hf()
63
+
64
+ # 防呆機制:如果雲端資料庫為空或下載失敗,退回使用本地端檔案
65
+ if baseline_df.empty and os.path.exists('baseline_logs.csv'):
66
+ print("⚠️ 雲端資料庫為空或讀取失敗,改用本地端 baseline_logs.csv")
67
+ baseline_df = pd.read_csv('baseline_logs.csv')
68
+
69
  baseline_df['timestamp'] = pd.to_datetime(baseline_df['timestamp'])
70
 
71
+ # 這裡的統計數據現在會包含雲端的最新總數與異常數
72
  global_stats["total_count"] = len(baseline_df)
73
  global_stats["abnormal_count"] = baseline_df[baseline_df['status'].str.contains("異常", na=False)].shape[0]
74
  print(f"📊 統計初始化:總監測量 {global_stats['total_count']}, 異常數 {global_stats['abnormal_count']}")
75
 
76
+ # 確保前端表格吃的是正確的字串格式,並且直接抓取雲端最新的 20 筆作為預設顯示
77
  display_df = baseline_df.sort_values(by='timestamp', ascending=False).head(20).copy()
78
  display_df['timestamp'] = display_df['timestamp'].dt.strftime('%Y-%m-%d %H:%M:%S')
79
  log_history = display_df.to_dict('records')
80
 
81
+ # 異常清單也會直接從雲端最新的資料中篩選出來
82
  initial_abnormal_logs = [log for log in log_history if "異常" in str(log.get("status", ""))]
83
  if initial_abnormal_logs:
84
  initial_df_abn = pd.DataFrame(initial_abnormal_logs)
 
96
  ))
97
 
98
  AI_READY = True
99
+ print("✅ AI 模組與動態歷史基準資料載入成功!")
100
  except Exception as e:
101
  AI_READY = False
102
  global_stats["total_count"] = 0
 
126
  <div class="stat-card card-total">
127
  <div class="card-icon">📊</div>
128
  <div class="card-content">
129
+ <div class="card-label">總監測量 (包含雲端資料庫)</div>
130
  <div class="card-value">{total:,} <span class="card-unit">筆 Log</span></div>
131
  <div class="card-sub-text">自系統啟動起統計 (+今日即時)</div>
132
  </div>
 
466
 
467
  with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
468
 
469
+ # 確保 State 初始化時能抓到剛從雲端下載的最新資料
470
  store_df_all = gr.State(value=pd.DataFrame(log_history))
471
  store_df_abn = gr.State(value=initial_df_abn)
472
 
 
482
  custom_time_input = gr.Textbox(label="輸入自訂時間", placeholder="格式: YYYY-MM-DD HH:MM:SS", value="2026-03-17 03:00:00", visible=False)
483
  gr.Markdown("---")
484
  gr.Markdown("### 📊 即時 Log 與 AI 判定區")
 
485
  log_display = gr.Dataframe(value=pd.DataFrame(log_history), headers=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"], datatype=["str", "str", "str", "str", "str", "str", "str"], interactive=False, wrap=True)
486
 
487
  with gr.Column(scale=2):
 
594
  with gr.Row():
595
  t_vdesk_norm = gr.Button("✅ 正常: 軟體雲/WebMail (03-22 18:00)", size="sm"); t_vdesk_anom = gr.Button("⚠️ 異常: 軟體雲/WebMail (08-10 00:00)", size="sm")
596
 
 
597
  def update_dataframes(df_all, df_abn):
598
  return gr.update(value=df_all), gr.update(value=df_abn)
599
 
 
608
 
609
  weight_inputs = [overall_weight, time_weight, ip_weight, device_weight]
610
 
 
611
  update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
612
 
613
  login_btn.click(
 
643
  btn.click(
644
  fn=lambda ip, c, acc, t_mode, t_custom, ow, tw, iw, dw, n=action_name: simulate_click(ip, c, acc, n, t_mode, t_custom, ow, tw, iw, dw),
645
  inputs=[mock_ip, mock_cookie, acc_input, time_mode, custom_time_input] + weight_inputs,
646
+ outputs=[store_df_all, store_df_abn, abnormal_log_input]
647
  )
648
 
649
  test_mapping = [
 
664
  btn.click(
665
  fn=lambda ip, c, acc, ow, tw, iw, dw, n=action_name, t_str=test_time_str: test_anomaly(ip, c, acc, n, t_str, ow, tw, iw, dw),
666
  inputs=[mock_ip, mock_cookie, acc_input, overall_weight, time_weight, ip_weight, device_weight],
667
+ outputs=[store_df_all, store_df_abn, abnormal_log_input]
668
  )
669
 
670
  if __name__ == "__main__":