Spaces:
Sleeping
Sleeping
File size: 3,993 Bytes
26b9faa 79df050 26b9faa 79df050 26b9faa 79df050 26b9faa 79df050 | 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import os
import logging
from typing import Optional
# ANSI 轉義序列
class LogColor:
DEBUG = "\x1b[38;20m" # 灰色
INFO = "\x1b[32;20m" # 綠色
WARNING = "\x1b[33;20m" # 黃色
ERROR = "\x1b[31;20m" # 紅色
CRITICAL = "\x1b[31;1m" # 粗體紅
RESET = "\x1b[0m"
GRAY = "\x1b[90m" # 淺灰色
CYAN = "\x1b[36;20m" # 青色
BLUE = "\x1b[34;20m" # 藍色
MAGENTA = "\x1b[35;20m" # 品紅
class ColoredFormatter(logging.Formatter):
"""自定義彩色日誌格式化器"""
LEVEL_COLORS = {
logging.DEBUG: LogColor.GRAY,
logging.INFO: LogColor.INFO,
logging.WARNING: LogColor.WARNING,
logging.ERROR: LogColor.ERROR,
logging.CRITICAL: LogColor.CRITICAL
}
def format(self, record):
level_color = self.LEVEL_COLORS.get(record.levelno, LogColor.RESET)
# 格式化時間(淡灰色)
asctime = self.formatTime(record, self.datefmt)
asctime_colored = f"{LogColor.GRAY}{asctime}{LogColor.RESET}"
# 格式化名稱(青色)
name_colored = f"{LogColor.CYAN}{record.name}{LogColor.RESET}"
# 格式化等級(根據等級變色)
levelname_colored = f"{level_color}{record.levelname:8}{LogColor.RESET}"
# 格式化訊息
message = record.getMessage()
# 自動截斷過長的訊息(如工具調用的完整原始數據)
if len(message) > 500:
message = message[:500] + f"{LogColor.GRAY}... [已截斷,共 {len(message)} 字元]{LogColor.RESET}"
if "✅" in message:
message = f"{LogColor.INFO}{message}{LogColor.RESET}"
elif "❌" in message or "⚠️" in message:
message = f"{LogColor.ERROR}{message}{LogColor.RESET}"
elif "🎙️" in message or "🔊" in message:
message = f"{LogColor.BLUE}{message}{LogColor.RESET}"
elif "🌐" in message or "MCP" in message:
message = f"{LogColor.MAGENTA}{message}{LogColor.RESET}"
else:
message = f"{level_color}{message}{LogColor.RESET}"
return f"{asctime_colored} | {name_colored} | {levelname_colored} | {message}"
# 全域日誌等級
_LOG_LEVEL_NAME = os.getenv("BLOOMWARE_LOG_LEVEL", "INFO").upper()
_LOG_LEVEL = getattr(logging, _LOG_LEVEL_NAME, logging.INFO)
def get_log_level() -> int:
return _LOG_LEVEL
def setup_logging(
name: Optional[str] = None,
level: Optional[int] = None,
) -> logging.Logger:
if level is None:
level = _LOG_LEVEL
logger = logging.getLogger(name)
logger.setLevel(level)
if not logger.handlers:
console_handler = logging.StreamHandler()
console_handler.setLevel(level)
console_handler.setFormatter(ColoredFormatter())
logger.addHandler(console_handler)
logger.propagate = False
return logger
def get_logger(name: str) -> logging.Logger:
return setup_logging(name)
def get_level_name() -> str:
return _LOG_LEVEL_NAME
# 預設配置 root logger
_root_configured = False
def configure_root_logger():
global _root_configured
if not _root_configured:
root = logging.getLogger()
root.setLevel(get_log_level())
# 清除現有的 handlers
for handler in root.handlers[:]:
root.removeHandler(handler)
console_handler = logging.StreamHandler()
console_handler.setFormatter(ColoredFormatter())
root.addHandler(console_handler)
_root_configured = True
# 自動配置
configure_root_logger()
# 關閉 Speechbrain 等吵雜的日誌
logging.getLogger("speechbrain").setLevel(logging.WARNING)
logging.getLogger("werkzeug").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)
|