File size: 3,189 Bytes
7d67a69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# utils.py
# 此檔案包含各種工具函數
# 包括字型下載、IP 分類、繪圖輔助等

import os
import urllib.request
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import pandas as pd
import numpy as np
import seaborn as sns
import io
import base64
import datetime
import warnings

from config import FONT_PATH

# --- 解決 Matplotlib 中文顯示問題 ---
def setup_chinese_font():
    """下載並設定中文字型"""
    if not os.path.exists(FONT_PATH):
        try:
            print("📥 正在下載中文字型...")
            urllib.request.urlretrieve('https://github.com/StellarCN/scp_zh/raw/master/fonts/SimHei.ttf', FONT_PATH)
        except Exception as e:
            print(f"⚠️ 字型下載失敗: {e}")

    if os.path.exists(FONT_PATH):
        fm.fontManager.addfont(FONT_PATH)
        plt.rc('font', family='SimHei')
    plt.rcParams['axes.unicode_minus'] = False

# Seaborn 近期會對舊的 pandas option 發出 FutureWarning(純警告、非功能錯誤)
# 重整前端會觸發繪圖端點,因此你會在 terminal 看到重複訊息。
def suppress_warnings():
    """抑制不必要的警告"""
    warnings.filterwarnings(
        "ignore",
        category=FutureWarning,
        message="use_inf_as_na option is deprecated*",
    )

# --- IP 分類函數 ---
def get_ip_category(ip_str):
    """根據 IP 地址分類"""
    ip = str(ip_str).split(" ")[0]
    if ip.startswith("140.124."): return 0.0
    elif ip.startswith("61.228."): return 1.0
    elif ip.startswith("210.61."): return 2.0
    elif ip.startswith("45.33."): return 3.0
    else: return 4.0

def get_geo_level(ip_str):
    """根據 IP 地址獲取地理等級"""
    ip = str(ip_str).split(" ")[0]
    if ip == "140.124.71.55": return 0
    elif ip == "140.124.18.22": return 1
    elif ip.startswith("61.228."): return 2
    elif ip.startswith("210.61."): return 3
    elif ip.startswith("45.33."): return 4
    else: return 5

def update_system_weights(ow, tw, iw, dw, gw, fw):
    """更新系統權重"""
    from config import SYSTEM_WEIGHTS
    SYSTEM_WEIGHTS.update({
        "ow": float(ow), "tw": float(tw), "iw": float(iw),
        "dw": float(dw), "gw": float(gw), "fw": float(fw)
    })
    return f"✅ 系統權重已更新 - 總體: {ow}%, 時間: {tw}%, IP: {iw}%, 裝置: {dw}%, 地理: {gw}%, 頻率: {fw}%"

def _extract_gr_update_value(update_obj):
    """
    Gradio 的 gr.update(...) 可能回傳 dict 形式或物件形式。
    這裡統一抓出其中的 `value`,否則回傳 None。
    """
    if update_obj is None:
        return None
    if isinstance(update_obj, dict):
        return update_obj.get("value")
    # Fallback: try attribute access
    try:
        return getattr(update_obj, "value", None)
    except Exception:
        return None

def get_current_time():
    """獲取當前時間(台灣時區)"""
    return datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S")

def validate_time_format(time_str):
    """驗證時間格式"""
    try:
        pd.to_datetime(str(time_str))
        return True
    except Exception:
        return False