Files
tw2/qingjian_cs/app/logger.py
jimi 1f28dc4630
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
fix: prevent stale-turn double replies and suppress thinking noise
2026-03-03 13:03:52 +08:00

119 lines
3.8 KiB
Python

import logging
import sys
class _StreamColorizer:
RESET = "\033[0m"
C_AI_THINK = "\033[33m" # yellow
C_INBOUND = "\033[36m" # cyan
C_OUTBOUND = "\033[32m" # green
def __init__(self, stream):
self.stream = stream
def write(self, data):
if not data:
return
out = str(data)
if "Unsupported block type thinking" in out:
return
if "\x1b[" in out:
self.stream.write(out)
return
if "(thinking):" in out:
out = f"{self.C_AI_THINK}{out}{self.RESET}"
elif "[收消息]" in out:
out = f"{self.C_INBOUND}{out}{self.RESET}"
elif "[发送]" in out:
out = f"{self.C_OUTBOUND}{out}{self.RESET}"
self.stream.write(out)
def flush(self):
self.stream.flush()
def isatty(self):
return getattr(self.stream, "isatty", lambda: False)()
@property
def encoding(self):
return getattr(self.stream, "encoding", "utf-8")
_stream_color_installed = False
def install_stream_colorizer() -> None:
global _stream_color_installed
if _stream_color_installed:
return
try:
sys.stdout = _StreamColorizer(sys.stdout)
sys.stderr = _StreamColorizer(sys.stderr)
_stream_color_installed = True
except Exception:
pass
class _ColorFormatter(logging.Formatter):
RESET = "\033[0m"
C_INFO = "\033[36m" # cyan
C_WARN = "\033[33m" # yellow
C_ERR = "\033[31m" # red
C_EVENT = "\033[35m" # magenta
C_DRAW = "\033[34m" # blue
C_PRICE = "\033[32m" # green
def format(self, record: logging.LogRecord) -> str:
base = super().format(record)
msg = str(record.getMessage() or "")
if msg.startswith("[活动日志]"):
return f"{self.C_EVENT}{base}{self.RESET}"
if msg.startswith("[作图]"):
return f"{self.C_DRAW}{base}{self.RESET}"
if msg.startswith("[价格]"):
return f"{self.C_PRICE}{base}{self.RESET}"
if record.levelno >= logging.ERROR:
return f"{self.C_ERR}{base}{self.RESET}"
if record.levelno >= logging.WARNING:
return f"{self.C_WARN}{base}{self.RESET}"
return f"{self.C_INFO}{base}{self.RESET}"
def setup_logger() -> logging.Logger:
install_stream_colorizer()
logger = logging.getLogger("qingjian_cs")
if logger.handlers:
return logger
logger.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
formatter = _ColorFormatter("[%(asctime)s] %(levelname)s: %(message)s", "%H:%M:%S")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.propagate = False
# 降低 AgentScope 内部推理/格式器日志噪音,保留本项目活动日志。
logging.getLogger("agentscope").setLevel(logging.ERROR)
logging.getLogger("agentscope.formatter").setLevel(logging.ERROR)
logging.getLogger("agentscope.agent").setLevel(logging.ERROR)
fmt_logger = logging.getLogger("_openai_formatter")
fmt_logger.setLevel(logging.CRITICAL)
fmt_logger.propagate = False
fmt_logger.disabled = True
fmt_logger.handlers.clear()
fmt_logger.addHandler(logging.NullHandler())
logging.getLogger("_react_agent").setLevel(logging.ERROR)
logging.getLogger("httpx").setLevel(logging.ERROR)
logging.getLogger("urllib3").setLevel(logging.ERROR)
# 兜底:把当前已注册的同类噪声 logger 一并禁掉
for name in list(logging.root.manager.loggerDict.keys()):
if "_openai_formatter" in name:
lg = logging.getLogger(name)
lg.setLevel(logging.CRITICAL)
lg.propagate = False
lg.disabled = True
lg.handlers.clear()
lg.addHandler(logging.NullHandler())
return logger