Spaces:
Sleeping
Sleeping
| # 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 |