Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +81 -128
src/streamlit_app.py
CHANGED
|
@@ -517,140 +517,93 @@ elif 'json_data_for_batch' in st.session_state:
|
|
| 517 |
if st.session_state.execute_batch_analysis and 'json_data_for_batch' in st.session_state and st.session_state.json_data_for_batch is not None:
|
| 518 |
st.session_state.execute_batch_analysis = False
|
| 519 |
start_time = time.time()
|
| 520 |
-
|
| 521 |
-
# 執行前確保清空結果
|
| 522 |
-
st.session_state.batch_results = []
|
| 523 |
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 528 |
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
correlated_logs = []
|
| 553 |
-
|
| 554 |
-
# 檢查 IP 是否有效
|
| 555 |
-
if target_ip and target_ip != "-":
|
| 556 |
-
|
| 557 |
-
# 篩選過去的 Log,最多 WINDOW_SIZE - 1 個,且 IP 必須匹配
|
| 558 |
-
# 從 i-1 倒序檢查到 0
|
| 559 |
-
for j in range(i - 1, -1, -1):
|
| 560 |
-
prior_log_entry = logs_list[j]
|
| 561 |
-
prior_ip = (prior_log_entry.get('c_ip') or
|
| 562 |
-
prior_log_entry.get('c_ip') or
|
| 563 |
-
prior_log_entry.get('remote_addr') or
|
| 564 |
-
prior_log_entry.get('source_ip') or
|
| 565 |
-
prior_log_entry.get('client_ip'))
|
| 566 |
-
|
| 567 |
-
# 檢查 IP 是否匹配
|
| 568 |
-
if prior_ip == target_ip:
|
| 569 |
-
# 插入到最前面,保持時間順序
|
| 570 |
-
correlated_logs.insert(0, formatted_logs[j])
|
| 571 |
-
|
| 572 |
-
# 限制累積的 Log 數量(不包含當前 Log)
|
| 573 |
-
if len(correlated_logs) >= WINDOW_SIZE - 1:
|
| 574 |
-
break
|
| 575 |
-
|
| 576 |
-
# 1. 加入相關聯的 Log (時間較早的)
|
| 577 |
-
for log_str in correlated_logs:
|
| 578 |
-
sequence_text.append(f"--- Correlated Log (IP:{target_ip}) ---\n{log_str}")
|
| 579 |
-
|
| 580 |
-
else:
|
| 581 |
-
# 如果沒有找到 IP,只分析當前 Log (確保 sequence_text 不是空的)
|
| 582 |
-
pass # sequence_text 最終只會包含 TARGET LOG
|
| 583 |
-
|
| 584 |
-
# 2. 加入當前的目標 Log
|
| 585 |
-
sequence_text.append(f"--- TARGET LOG TO ANALYZE (Index {i+1}) ---\n{current_log_str}")
|
| 586 |
-
|
| 587 |
-
analysis_sequences.append({
|
| 588 |
-
"sequence_text": "\n\n".join(sequence_text),
|
| 589 |
-
"target_log_id": i + 1,
|
| 590 |
-
"original_log_entry": logs_list[i]
|
| 591 |
-
})
|
| 592 |
-
|
| 593 |
-
# --- LLM 執行迴圈 ---
|
| 594 |
-
total_sequences = len(analysis_sequences)
|
| 595 |
-
st.header(f"⚡ 批量分析執行中 (IP 關聯視窗 $N={WINDOW_SIZE}$)...")
|
| 596 |
-
progress_bar = st.progress(0, text=f"準備處理 {total_sequences} 個序列...")
|
| 597 |
-
|
| 598 |
-
# 使用一個佔位符來顯示即時進度或警告,而不是結果
|
| 599 |
-
status_placeholder = st.empty()
|
| 600 |
-
|
| 601 |
-
for i, seq_data in enumerate(analysis_sequences):
|
| 602 |
-
log_id = seq_data["target_log_id"]
|
| 603 |
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
user_prompt=analysis_prompt,
|
| 614 |
-
sys_prompt=system_prompt,
|
| 615 |
-
vector_store=vs,
|
| 616 |
-
threshold=similarity_threshold,
|
| 617 |
-
max_output_tokens=max_output_tokens,
|
| 618 |
-
temperature=temperature,
|
| 619 |
-
top_p=top_p
|
| 620 |
-
)
|
| 621 |
-
|
| 622 |
-
item = {
|
| 623 |
-
"log_id": log_id,
|
| 624 |
-
"log_content": seq_data["original_log_entry"],
|
| 625 |
-
"sequence_analyzed": seq_data["sequence_text"],
|
| 626 |
-
"analysis_result": response,
|
| 627 |
-
"context": retrieved_ctx
|
| 628 |
-
}
|
| 629 |
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 653 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 |
# === 顯示結果 (歷史紀錄) - 已修改為持久顯示結果,而非僅在執行時顯示 ===
|
| 655 |
if st.session_state.get("batch_results") and isinstance(st.session_state.batch_results, list) and st.session_state.batch_results:
|
| 656 |
st.header("⚡ 歷史分析結果")
|
|
|
|
| 517 |
if st.session_state.execute_batch_analysis and 'json_data_for_batch' in st.session_state and st.session_state.json_data_for_batch is not None:
|
| 518 |
st.session_state.execute_batch_analysis = False
|
| 519 |
start_time = time.time()
|
|
|
|
|
|
|
|
|
|
| 520 |
|
| 521 |
+
# ... (前面的初始化和序列建構邏輯保持不變) ...
|
| 522 |
+
|
| 523 |
+
if logs_list:
|
| 524 |
+
# ... (序列建構邏輯保持不變) ...
|
| 525 |
+
|
| 526 |
+
# --- LLM 執行迴圈 ---
|
| 527 |
+
total_sequences = len(analysis_sequences)
|
| 528 |
+
st.header(f"⚡ 批量分析執行中 (IP 關聯視窗 $N={WINDOW_SIZE}$)...")
|
| 529 |
+
progress_bar = st.progress(0, text=f"準備處理 {total_sequences} 個序列...")
|
| 530 |
|
| 531 |
+
# 【修改點 1】創建一個佔位符來顯示即時結果
|
| 532 |
+
st.subheader("即時���析結果")
|
| 533 |
+
results_placeholder = st.empty() # 使用 st.empty() 或 st.container()
|
| 534 |
+
|
| 535 |
+
# 【修改點 2】使用一個清單來累積即時顯示的內容 (Markdown 格式)
|
| 536 |
+
# 這樣可以避免每次都重畫整個容器,但 Streamlit 的限制是 'empty' 每次都會覆蓋
|
| 537 |
+
# 最好的方式是使用 st.container() 並在其內部 append 內容
|
| 538 |
+
|
| 539 |
+
real_time_container = st.container() # 創建一個新的容器用於即時輸出
|
| 540 |
+
|
| 541 |
+
for i, seq_data in enumerate(analysis_sequences):
|
| 542 |
+
log_id = seq_data["target_log_id"]
|
| 543 |
+
|
| 544 |
+
# 顯示進度
|
| 545 |
+
progress_bar.progress((i + 1) / total_sequences, text=f"Processing {i + 1}/{total_sequences} (Log #{log_id})...")
|
| 546 |
+
# results_placeholder.text(f"正在分析 Log #{log_id} (IP 序列長度: {seq_data['sequence_text'].count('---')})...")
|
| 547 |
+
# 移除 text 狀態顯示,改用容器顯示結果
|
| 548 |
+
|
| 549 |
+
try:
|
| 550 |
+
# ... (模型呼叫邏輯保持不變) ...
|
| 551 |
+
response, retrieved_ctx = generate_rag_response_hf_for_log(
|
| 552 |
+
# ... (參數保持不變) ...
|
| 553 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
|
| 555 |
+
item = {
|
| 556 |
+
"log_id": log_id,
|
| 557 |
+
"log_content": seq_data["original_log_entry"],
|
| 558 |
+
"sequence_analyzed": seq_data["sequence_text"],
|
| 559 |
+
"analysis_result": response,
|
| 560 |
+
"context": retrieved_ctx
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
st.session_state.batch_results.append(item)
|
| 564 |
|
| 565 |
+
# 【修改點 3】即時渲染當前 Log 的分析結果到 real_time_container 內
|
| 566 |
+
with real_time_container:
|
| 567 |
+
response_lower = response.lower()
|
| 568 |
+
is_high = 'high-risk detected!' in response_lower
|
| 569 |
+
is_medium = 'medium-risk detected!' in response_lower
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 570 |
|
| 571 |
+
if is_high:
|
| 572 |
+
header_text = f"Log/Alert #{log_id} (HIGH RISK DETECTED) 🔴"
|
| 573 |
+
st.subheader(header_text)
|
| 574 |
+
st.error(response)
|
| 575 |
+
elif is_medium:
|
| 576 |
+
header_text = f"Log/Alert #{log_id} (MEDIUM RISK DETECTED) 🟠"
|
| 577 |
+
st.subheader(header_text)
|
| 578 |
+
st.warning(response)
|
| 579 |
+
else:
|
| 580 |
+
header_text = f"Log/Alert #{log_id} (Low/No Risk Detected) ⚪"
|
| 581 |
+
st.subheader(header_text)
|
| 582 |
+
st.info(response) # 使用 info ��顯示不具備高/中風險的結果
|
| 583 |
+
|
| 584 |
+
# 為了視覺區隔
|
| 585 |
+
st.markdown("---")
|
| 586 |
+
|
| 587 |
+
except Exception as e:
|
| 588 |
+
# ... (錯誤處理邏輯保持不變) ...
|
| 589 |
+
with real_time_container:
|
| 590 |
+
st.subheader(f"Log/Alert #{log_id} (Execution Error) ❌")
|
| 591 |
+
st.exception(e)
|
| 592 |
+
st.markdown("---")
|
| 593 |
+
|
| 594 |
+
# ... (迴圈結束後的清理邏輯) ...
|
| 595 |
+
end_time = time.time()
|
| 596 |
+
progress_bar.empty()
|
| 597 |
+
# status_placeholder.empty() # 由於我們移除了 status_placeholder,這裡也移除
|
| 598 |
+
st.success(f"完成!耗時 {end_time - start_time:.2f} 秒。")
|
| 599 |
|
| 600 |
+
# 【修改點 4】移除 st.rerun()。因為結果已經即時顯示,不需要額外的重新運行。
|
| 601 |
+
# st.rerun() # <--- 移除此行
|
| 602 |
+
|
| 603 |
+
else:
|
| 604 |
+
st.error("無法提取有效 Log,請檢查檔案格式。")
|
| 605 |
+
|
| 606 |
+
|
| 607 |
# === 顯示結果 (歷史紀錄) - 已修改為持久顯示結果,而非僅在執行時顯示 ===
|
| 608 |
if st.session_state.get("batch_results") and isinstance(st.session_state.batch_results, list) and st.session_state.batch_results:
|
| 609 |
st.header("⚡ 歷史分析結果")
|