Spaces:
Sleeping
Sleeping
feat: overhaul MCP architecture with structured tool schemas, comprehensive care-mode skill definitions, and enhanced test coverage for pipelines and service integration.
79df050 | 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) | |