[debug] 调试语句

This commit is contained in:
SXP-Simon
2025-10-10 16:27:23 +08:00
parent e06605de4c
commit 791073b8bf
3 changed files with 130 additions and 144 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ class BaseAnalyzer(ABC):
return [], token_usage
except Exception as e:
logger.error(f"{self.get_data_type()}分析失败: {e}")
logger.error(f"{self.get_data_type()}分析失败: {e}", exc_info=True)
return [], TokenUsage()
def get_max_tokens(self) -> int:
+116 -64
View File
@@ -44,32 +44,49 @@ class TopicAnalyzer(BaseAnalyzer):
Returns:
提示词字符串
"""
logger.debug(f"build_prompt 开始处理,输入消息数量: {len(messages) if messages else 0}")
logger.debug(f"输入消息类型: {type(messages)}")
# 验证输入数据格式
if not isinstance(messages, list):
logger.error(f"build_prompt 期望列表,但收到: {type(messages)}")
return ""
# 提取文本消息
text_messages = []
for msg in messages:
for i, msg in enumerate(messages):
logger.debug(f"build_prompt 处理第 {i+1} 条消息,类型: {type(msg)}")
# 确保msg是字典类型,避免'str' object has no attribute 'get'错误
if not isinstance(msg, dict):
logger.warning(f"build_prompt 跳过非字典类型的消息: {type(msg)} - {msg}")
continue
sender = msg.get("sender", {})
nickname = sender.get("nickname", "") or sender.get("card", "")
msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M")
for content in msg.get("message", []):
if content.get("type") == "text":
text = content.get("data", {}).get("text", "").strip()
if text and len(text) > 2 and not text.startswith("/"):
# 清理消息内容
text = text.replace('', '"').replace('', '"')
text = text.replace('', "'").replace('', "'")
text = text.replace('\n', ' ').replace('\r', ' ')
text = text.replace('\t', ' ')
text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
text_messages.append({
"sender": nickname,
"time": msg_time,
"content": text.strip()
})
try:
sender = msg.get("sender", {})
nickname = sender.get("nickname", "") or sender.get("card", "")
msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M")
for content in msg.get("message", []):
if content.get("type") == "text":
text = content.get("data", {}).get("text", "").strip()
if text and len(text) > 2 and not text.startswith("/"):
# 清理消息内容
text = text.replace('', '"').replace('', '"')
text = text.replace('', "'").replace('', "'")
text = text.replace('\n', ' ').replace('\r', ' ')
text = text.replace('\t', ' ')
text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
text_messages.append({
"sender": nickname,
"time": msg_time,
"content": text.strip()
})
except Exception as e:
logger.error(f"build_prompt 处理第 {i+1} 条消息时出错: {e}", exc_info=True)
continue
logger.debug(f"build_prompt 提取到 {len(text_messages)} 条文本消息")
if not text_messages:
return ""
@@ -147,43 +164,57 @@ class TopicAnalyzer(BaseAnalyzer):
Returns:
SummaryTopic对象列表
"""
logger.debug(f"create_data_objects 开始处理,输入数据数量: {len(topics_data) if topics_data else 0}")
logger.debug(f"输入数据类型: {type(topics_data)}")
try:
topics = []
max_topics = self.get_max_count()
for topic_data in topics_data[:max_topics]:
logger.debug(f"处理前 {max_topics} 条话题数据")
for i, topic_data in enumerate(topics_data[:max_topics]):
logger.debug(f"处理第 {i+1} 条话题数据,类型: {type(topic_data)}")
# 确保topic_data是字典类型,避免'str' object has no attribute 'get'错误
if not isinstance(topic_data, dict):
logger.warning(f"跳过非字典类型的话题数据: {type(topic_data)} - {topic_data}")
continue
# 确保数据格式正确
topic_name = topic_data.get("topic", "").strip()
contributors = topic_data.get("contributors", [])
detail = topic_data.get("detail", "").strip()
# 验证必要字段
if not topic_name or not detail:
logger.warning(f"话题数据格式不完整,跳过: {topic_data}")
try:
# 确保数据格式正确
topic_name = topic_data.get("topic", "").strip()
contributors = topic_data.get("contributors", [])
detail = topic_data.get("detail", "").strip()
logger.debug(f"话题数据 - 名称: {topic_name}, 参与者: {contributors}, 详情: {detail[:50]}...")
# 验证必要字段
if not topic_name or not detail:
logger.warning(f"话题数据格式不完整,跳过: {topic_data}")
continue
# 确保参与者列表有效
if not contributors or not isinstance(contributors, list):
contributors = ["群友"]
else:
# 清理参与者名称
contributors = [str(c).strip() for c in contributors if c and str(c).strip()] or ["群友"]
topics.append(SummaryTopic(
topic=topic_name,
contributors=contributors[:5], # 最多5个参与者
detail=detail
))
except Exception as e:
logger.error(f"处理第 {i+1} 条话题数据时出错: {e}", exc_info=True)
continue
# 确保参与者列表有效
if not contributors or not isinstance(contributors, list):
contributors = ["群友"]
else:
# 清理参与者名称
contributors = [str(c).strip() for c in contributors if c and str(c).strip()] or ["群友"]
topics.append(SummaryTopic(
topic=topic_name,
contributors=contributors[:5], # 最多5个参与者
detail=detail
))
logger.debug(f"create_data_objects 完成,创建了 {len(topics)} 个话题对象")
return topics
except Exception as e:
logger.error(f"创建话题对象失败: {e}")
logger.error(f"创建话题对象失败: {e}", exc_info=True)
return []
def extract_text_messages(self, messages: List[Dict]) -> List[Dict]:
@@ -196,32 +227,41 @@ class TopicAnalyzer(BaseAnalyzer):
Returns:
提取的文本消息列表
"""
logger.debug(f"extract_text_messages 开始处理,输入消息数量: {len(messages) if messages else 0}")
text_messages = []
for msg in messages:
for i, msg in enumerate(messages):
logger.debug(f"处理第 {i+1} 条消息,类型: {type(msg)}")
# 确保msg是字典类型,避免'str' object has no attribute 'get'错误
if not isinstance(msg, dict):
logger.warning(f"跳过非字典类型的消息: {type(msg)} - {msg}")
continue
sender = msg.get("sender", {})
nickname = sender.get("nickname", "") or sender.get("card", "")
msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M")
for content in msg.get("message", []):
if content.get("type") == "text":
text = content.get("data", {}).get("text", "").strip()
if text and len(text) > 2 and not text.startswith("/"):
# 清理消息内容
text = text.replace('""', '"').replace('""', '"')
text = text.replace(''', "'").replace(''', "'")
text = text.replace('\n', ' ').replace('\r', ' ')
text = text.replace('\t', ' ')
text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
text_messages.append({
"sender": nickname,
"time": msg_time,
"content": text.strip()
})
try:
sender = msg.get("sender", {})
nickname = sender.get("nickname", "") or sender.get("card", "")
msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M")
for content in msg.get("message", []):
if content.get("type") == "text":
text = content.get("data", {}).get("text", "").strip()
if text and len(text) > 2 and not text.startswith("/"):
# 清理消息内容
text = text.replace('""', '"').replace('""', '"')
text = text.replace(''', "'").replace(''', "'")
text = text.replace('\n', ' ').replace('\r', ' ')
text = text.replace('\t', ' ')
text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
text_messages.append({
"sender": nickname,
"time": msg_time,
"content": text.strip()
})
except Exception as e:
logger.error(f"处理第 {i+1} 条消息时出错: {e}", exc_info=True)
continue
logger.debug(f"extract_text_messages 完成,提取到 {len(text_messages)} 条文本消息")
return text_messages
async def analyze_topics(self, messages: List[Dict], umo: str = None) -> Tuple[List[SummaryTopic], TokenUsage]:
@@ -236,16 +276,28 @@ class TopicAnalyzer(BaseAnalyzer):
(话题列表, Token使用统计)
"""
try:
logger.debug(f"analyze_topics 开始处理,消息数量: {len(messages) if messages else 0}")
logger.debug(f"消息类型: {type(messages)}")
if messages:
logger.debug(f"第一条消息类型: {type(messages[0]) if messages else ''}")
logger.debug(f"第一条消息内容: {messages[0] if messages else ''}")
# 提取文本消息
text_messages = self.extract_text_messages(messages)
logger.debug(f"提取到 {len(text_messages)} 条文本消息")
if not text_messages:
logger.info("没有有效的文本消息,返回空结果")
return [], TokenUsage()
logger.info(f"开始分析 {len(text_messages)} 条文本消息中的话题")
logger.debug(f"文本消息类型: {type(text_messages)}")
if text_messages:
logger.debug(f"第一条文本消息类型: {type(text_messages[0])}")
logger.debug(f"第一条文本消息内容: {text_messages[0]}")
return await self.analyze(text_messages, umo)
except Exception as e:
logger.error(f"话题分析失败: {e}")
logger.error(f"话题分析失败: {e}", exc_info=True)
return [], TokenUsage()
+13 -79
View File
@@ -298,14 +298,14 @@ class ReportGenerator:
# 尝试启动浏览器,如果 Chromium 不存在会自动下载
logger.info("启动浏览器进行 PDF 转换")
# 配置浏览器启动参数,提高稳定性,避免意外关闭
# 配置浏览器启动参数,解决Docker环境中的沙盒问题
launch_options = {
'headless': True,
'args': [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--no-sandbox', # Docker环境必需 - 禁用沙盒
'--disable-setuid-sandbox', # Docker环境必需 - 禁用setuid沙盒
'--disable-dev-shm-usage', # 避免共享内存问题
'--disable-gpu', # 禁用GPU加速
'--no-first-run',
'--disable-extensions',
'--disable-default-apps',
@@ -328,18 +328,6 @@ class ReportGenerator:
'--disable-web-security',
'--disable-features=VizDisplayCompositor',
'--disable-blink-features=AutomationControlled', # 隐藏自动化特征
'--memory-pressure-off', # 禁用内存压力检测
'--max_old_space_size=4096', # 限制内存使用
'--disable-background-mode', # 禁用后台模式
'--disable-ipc-flooding-protection', # 禁用IPC洪水保护
'--disable-logging', # 禁用日志记录以减少资源使用
'--disable-permissions-api', # 禁用权限API
'--disable-notifications', # 禁用通知
'--disable-web-bluetooth', # 禁用蓝牙
'--disable-web-usb', # 禁用USB
'--disable-webgl', # 禁用WebGL
'--disable-webgl2', # 禁用WebGL2
'--disable-webrtc', # 禁用WebRTC
]
}
@@ -373,10 +361,8 @@ class ReportGenerator:
]
# 查找可用的浏览器
logger.info(f"正在检查 {len(chrome_paths)} 个可能的浏览器路径...")
found_browser = False
for chrome_path in chrome_paths:
logger.debug(f"检查浏览器路径: {chrome_path}")
if Path(chrome_path).exists():
launch_options['executablePath'] = chrome_path
logger.info(f"使用系统浏览器: {chrome_path}")
@@ -384,67 +370,15 @@ class ReportGenerator:
break
if not found_browser:
logger.warning("未找到系统浏览器,将使用 pyppeteer 默认下载的 Chromium")
logger.info("未找到系统浏览器,将使用 pyppeteer 默认下载的 Chromium")
# 尝试启动浏览器,最多重试3次
max_retries = 3
browser = None
for attempt in range(max_retries):
try:
logger.info(f"尝试启动浏览器 (第 {attempt + 1} 次)")
# 添加更多内存友好的启动选项
launch_options.update({
'dumpio': True, # 输出浏览器日志以便调试
'autoClose': False, # 防止自动关闭
'handleSIGINT': False,
'handleSIGTERM': False,
'handleSIGHUP': False
})
browser = await launch(**launch_options)
logger.info("浏览器启动成功")
break
except Exception as e:
logger.warning(f"{attempt + 1} 次启动浏览器失败: {e}", exc_info=True)
if attempt < max_retries - 1:
await asyncio.sleep(3) # 增加等待时间到3秒
# 尝试减少内存占用的启动选项
launch_options['args'].extend([
'--disable-images',
'--disable-javascript',
'--disable-plugins',
'--disable-webgl',
'--disable-threaded-animation',
'--disable-threaded-scrolling',
'--disable-sync',
'--disable-default-apps',
'--mute-audio',
'--no-zygote',
'--disable-gpu-sandbox',
'--disable-software-rasterizer',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--disable-client-side-phishing-detection',
'--disable-component-extensions-with-background-pages',
'--disable-default-apps',
'--disable-extensions',
'--disable-features=TranslateUI',
'--disable-ipc-flooding-protection',
'--disable-background-mode',
'--disable-logging',
'--disable-permissions-api',
'--disable-web-bluetooth',
'--disable-web-usb',
'--disable-webrtc',
'--max_old_space_size=1024', # 进一步限制内存
'--memory-pressure-off'
])
else:
logger.error(f"多次尝试后浏览器启动失败,无法生成 PDF, {e}", exc_info=True)
return False
if not browser:
logger.error("浏览器启动失败,无法继续")
# 尝试启动浏览器
try:
logger.info("正在启动浏览器...")
browser = await launch(**launch_options)
logger.info("浏览器启动成功")
except Exception as e:
logger.error(f"浏览器启动失败: {e}", exc_info=True)
return False
try: