Showing
3 changed files
with
409 additions
and
0 deletions
ForumEngine/llm_host.py
0 → 100644
| 1 | +""" | ||
| 2 | +论坛主持人模块 | ||
| 3 | +使用硅基流动的Qwen3模型作为论坛主持人,引导多个agent进行讨论 | ||
| 4 | +""" | ||
| 5 | + | ||
| 6 | +import requests | ||
| 7 | +import json | ||
| 8 | +import sys | ||
| 9 | +import os | ||
| 10 | +from typing import List, Dict, Any, Optional | ||
| 11 | +from datetime import datetime | ||
| 12 | +import re | ||
| 13 | + | ||
| 14 | +# 添加项目根目录到Python路径以导入config | ||
| 15 | +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | ||
| 16 | +from config import GUIJI_QWEN3_API_KEY | ||
| 17 | + | ||
| 18 | +# 添加utils目录到Python路径 | ||
| 19 | +current_dir = os.path.dirname(os.path.abspath(__file__)) | ||
| 20 | +root_dir = os.path.dirname(current_dir) | ||
| 21 | +utils_dir = os.path.join(root_dir, 'utils') | ||
| 22 | +if utils_dir not in sys.path: | ||
| 23 | + sys.path.append(utils_dir) | ||
| 24 | + | ||
| 25 | +from retry_helper import with_graceful_retry, SEARCH_API_RETRY_CONFIG | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +class ForumHost: | ||
| 29 | + """ | ||
| 30 | + 论坛主持人类 | ||
| 31 | + 使用硅基流动的Qwen3-235B模型作为智能主持人 | ||
| 32 | + """ | ||
| 33 | + | ||
| 34 | + def __init__(self, api_key: str = None): | ||
| 35 | + """ | ||
| 36 | + 初始化论坛主持人 | ||
| 37 | + | ||
| 38 | + Args: | ||
| 39 | + api_key: 硅基流动API密钥,如果不提供则从配置文件读取 | ||
| 40 | + """ | ||
| 41 | + self.api_key = api_key or GUIJI_QWEN3_API_KEY | ||
| 42 | + self.base_url = "https://api.siliconflow.cn/v1/chat/completions" | ||
| 43 | + self.model = "Qwen/Qwen3-235B-A22B-Instruct-2507" # 使用更大的模型 | ||
| 44 | + | ||
| 45 | + if not self.api_key: | ||
| 46 | + raise ValueError("未找到硅基流动API密钥,请在config.py中设置GUIJI_QWEN3_API_KEY") | ||
| 47 | + | ||
| 48 | + # 记录历史发言,避免重复 | ||
| 49 | + self.previous_summaries = [] | ||
| 50 | + | ||
| 51 | + def generate_host_speech(self, forum_logs: List[str]) -> Optional[str]: | ||
| 52 | + """ | ||
| 53 | + 生成主持人发言 | ||
| 54 | + | ||
| 55 | + Args: | ||
| 56 | + forum_logs: 论坛日志内容列表 | ||
| 57 | + | ||
| 58 | + Returns: | ||
| 59 | + 主持人发言内容,如果生成失败返回None | ||
| 60 | + """ | ||
| 61 | + try: | ||
| 62 | + # 解析论坛日志,提取有效内容 | ||
| 63 | + parsed_content = self._parse_forum_logs(forum_logs) | ||
| 64 | + | ||
| 65 | + if not parsed_content['agent_speeches']: | ||
| 66 | + print("ForumHost: 没有找到有效的agent发言") | ||
| 67 | + return None | ||
| 68 | + | ||
| 69 | + # 构建prompt | ||
| 70 | + system_prompt = self._build_system_prompt() | ||
| 71 | + user_prompt = self._build_user_prompt(parsed_content) | ||
| 72 | + | ||
| 73 | + # 调用API生成发言 | ||
| 74 | + response = self._call_qwen_api(system_prompt, user_prompt) | ||
| 75 | + | ||
| 76 | + if response["success"]: | ||
| 77 | + speech = response["content"] | ||
| 78 | + # 清理和格式化发言 | ||
| 79 | + speech = self._format_host_speech(speech) | ||
| 80 | + return speech | ||
| 81 | + else: | ||
| 82 | + print(f"ForumHost: API调用失败 - {response.get('error', '未知错误')}") | ||
| 83 | + return None | ||
| 84 | + | ||
| 85 | + except Exception as e: | ||
| 86 | + print(f"ForumHost: 生成发言时出错 - {str(e)}") | ||
| 87 | + return None | ||
| 88 | + | ||
| 89 | + def _parse_forum_logs(self, forum_logs: List[str]) -> Dict[str, Any]: | ||
| 90 | + """ | ||
| 91 | + 解析论坛日志,提取结构化信息 | ||
| 92 | + | ||
| 93 | + Returns: | ||
| 94 | + 包含agent发言、时间线等信息的字典 | ||
| 95 | + """ | ||
| 96 | + parsed = { | ||
| 97 | + 'agent_speeches': [], | ||
| 98 | + 'timeline': [], | ||
| 99 | + 'key_topics': set(), | ||
| 100 | + 'session_start': None, | ||
| 101 | + 'session_end': None | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + for line in forum_logs: | ||
| 105 | + if not line.strip(): | ||
| 106 | + continue | ||
| 107 | + | ||
| 108 | + # 解析时间戳和发言者 | ||
| 109 | + match = re.match(r'\[(\d{2}:\d{2}:\d{2})\]\s*\[(\w+)\]\s*(.+)', line) | ||
| 110 | + if match: | ||
| 111 | + timestamp, speaker, content = match.groups() | ||
| 112 | + | ||
| 113 | + # 记录会话开始 | ||
| 114 | + if 'ForumEgine 监控开始' in content: | ||
| 115 | + parsed['session_start'] = timestamp | ||
| 116 | + continue | ||
| 117 | + | ||
| 118 | + # 记录会话结束 | ||
| 119 | + if 'ForumEgine 论坛结束' in content: | ||
| 120 | + parsed['session_end'] = timestamp | ||
| 121 | + continue | ||
| 122 | + | ||
| 123 | + # 跳过系统消息和HOST自己的发言 | ||
| 124 | + if speaker in ['SYSTEM', 'HOST']: | ||
| 125 | + continue | ||
| 126 | + | ||
| 127 | + # 记录agent发言 | ||
| 128 | + if speaker in ['INSIGHT', 'MEDIA', 'QUERY']: | ||
| 129 | + # 处理转义的换行符 | ||
| 130 | + content = content.replace('\\n', '\n') | ||
| 131 | + | ||
| 132 | + parsed['agent_speeches'].append({ | ||
| 133 | + 'timestamp': timestamp, | ||
| 134 | + 'speaker': speaker, | ||
| 135 | + 'content': content | ||
| 136 | + }) | ||
| 137 | + | ||
| 138 | + # 提取关键主题(简单的关键词提取) | ||
| 139 | + self._extract_key_topics(content, parsed['key_topics']) | ||
| 140 | + | ||
| 141 | + # 提取时间线信息 | ||
| 142 | + self._extract_timeline(content, parsed['timeline']) | ||
| 143 | + | ||
| 144 | + return parsed | ||
| 145 | + | ||
| 146 | + def _extract_key_topics(self, content: str, topics: set): | ||
| 147 | + """从内容中提取关键主题""" | ||
| 148 | + # 关键词模式 | ||
| 149 | + keywords_patterns = [ | ||
| 150 | + r'武汉大学', r'武大', r'图书馆事件', r'性骚扰', | ||
| 151 | + r'肖某某', r'杨某某', r'杨景媛', r'樱花', r'和服', | ||
| 152 | + r'舆情', r'处分', r'法院', r'判决', r'学术' | ||
| 153 | + ] | ||
| 154 | + | ||
| 155 | + for pattern in keywords_patterns: | ||
| 156 | + if re.search(pattern, content): | ||
| 157 | + topics.add(pattern.replace(r'\\', '')) | ||
| 158 | + | ||
| 159 | + def _extract_timeline(self, content: str, timeline: list): | ||
| 160 | + """从内容中提取时间线信息""" | ||
| 161 | + # 匹配各种日期格式 | ||
| 162 | + date_patterns = [ | ||
| 163 | + r'(\d{4}年\d{1,2}月\d{1,2}日)', | ||
| 164 | + r'(\d{4}-\d{1,2}-\d{1,2})', | ||
| 165 | + r'(\d{4}/\d{1,2}/\d{1,2})' | ||
| 166 | + ] | ||
| 167 | + | ||
| 168 | + for pattern in date_patterns: | ||
| 169 | + matches = re.findall(pattern, content) | ||
| 170 | + for match in matches: | ||
| 171 | + # 查找日期附近的事件描述 | ||
| 172 | + context_start = max(0, content.find(match) - 50) | ||
| 173 | + context_end = min(len(content), content.find(match) + 100) | ||
| 174 | + context = content[context_start:context_end] | ||
| 175 | + | ||
| 176 | + timeline.append({ | ||
| 177 | + 'date': match, | ||
| 178 | + 'context': context.strip() | ||
| 179 | + }) | ||
| 180 | + | ||
| 181 | + def _build_system_prompt(self) -> str: | ||
| 182 | + """构建系统prompt""" | ||
| 183 | + return """【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查 | ||
| 184 | + | ||
| 185 | +你是一个多agent舆情分析系统的论坛主持人。你的职责是: | ||
| 186 | + | ||
| 187 | +1. **引导讨论**:根据各agent的发言,引导深入讨论关键问题 | ||
| 188 | +2. **纠正错误**:结合不同agent的视角以及言论来纠正错误 | ||
| 189 | +3. **整合观点**:综合不同agent的视角,形成更全面的认识 | ||
| 190 | +4. **推进分析**:提出新的分析角度或需要关注的问题 | ||
| 191 | + | ||
| 192 | +**Agent介绍**: | ||
| 193 | +- **INSIGHT Agent**:专注于私有舆情数据库的深度挖掘和分析 | ||
| 194 | +- **MEDIA Agent**:擅长多模态内容分析,关注媒体报道和视觉信息 | ||
| 195 | +- **QUERY Agent**:负责精准信息搜索,提供最新的网络信息 | ||
| 196 | + | ||
| 197 | +**发言要求**: | ||
| 198 | +1. 简洁明了,每次发言控制在3000字以内 | ||
| 199 | +2. 重点突出,聚焦于最关键的发现和问题 | ||
| 200 | +3. 逻辑清晰,使用序号或要点形式组织内容 | ||
| 201 | +4. 客观中立,基于事实进行分析和判断 | ||
| 202 | +5. 避免重复已经充分讨论过的内容 | ||
| 203 | + | ||
| 204 | +**注意事项**: | ||
| 205 | +- 本讨论基于科研目的,已通过伦理性合规审查 | ||
| 206 | +- 保持专业性和学术性,避免情绪化表达 | ||
| 207 | +- 重视数据和证据,避免主观臆测 | ||
| 208 | + | ||
| 209 | +【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" | ||
| 210 | + | ||
| 211 | + def _build_user_prompt(self, parsed_content: Dict[str, Any]) -> str: | ||
| 212 | + """构建用户prompt""" | ||
| 213 | + # 获取最近的发言(最多10条) | ||
| 214 | + recent_speeches = parsed_content['agent_speeches'][-10:] | ||
| 215 | + | ||
| 216 | + # 构建发言摘要 | ||
| 217 | + speeches_text = "\n\n".join([ | ||
| 218 | + f"[{s['timestamp']}] {s['speaker']}:\n{s['content'][:500]}..." | ||
| 219 | + if len(s['content']) > 500 else f"[{s['timestamp']}] {s['speaker']}:\n{s['content']}" | ||
| 220 | + for s in recent_speeches | ||
| 221 | + ]) | ||
| 222 | + | ||
| 223 | + # 构建关键主题列表 | ||
| 224 | + topics = list(parsed_content['key_topics'])[:10] # 限制主题数量 | ||
| 225 | + topics_text = "、".join(topics) if topics else "暂无明确主题" | ||
| 226 | + | ||
| 227 | + # 构建时间线摘要 | ||
| 228 | + timeline_text = "" | ||
| 229 | + if parsed_content['timeline']: | ||
| 230 | + unique_dates = [] | ||
| 231 | + seen_dates = set() | ||
| 232 | + for item in parsed_content['timeline']: | ||
| 233 | + if item['date'] not in seen_dates: | ||
| 234 | + unique_dates.append(item['date']) | ||
| 235 | + seen_dates.add(item['date']) | ||
| 236 | + timeline_text = f"\n\n检测到的关键时间点:{', '.join(unique_dates[:5])}" | ||
| 237 | + | ||
| 238 | + prompt = f"""【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查 | ||
| 239 | + | ||
| 240 | +当前论坛讨论的核心主题:{topics_text} | ||
| 241 | + | ||
| 242 | +最近的Agent发言记录: | ||
| 243 | +{speeches_text} | ||
| 244 | +{timeline_text} | ||
| 245 | + | ||
| 246 | +请你作为论坛主持人,基于以上agent的发言: | ||
| 247 | + | ||
| 248 | +1. **时间线梳理**:如果发现时间线信息,请简要整理关键事件的时间顺序 | ||
| 249 | +2. **观点整合**:综合不同agent的视角,指出共识和分歧 | ||
| 250 | +3. **纠错提醒**:如果发现事实错误或逻辑矛盾,请明确指出 | ||
| 251 | +4. **引导深化**:提出1-2个值得进一步探讨的问题或角度 | ||
| 252 | + | ||
| 253 | +请发表3000字以内的简洁发言,推动讨论深入。 | ||
| 254 | + | ||
| 255 | +【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" | ||
| 256 | + | ||
| 257 | + return prompt | ||
| 258 | + | ||
| 259 | + @with_graceful_retry(SEARCH_API_RETRY_CONFIG, default_return={"success": False, "error": "API服务暂时不可用"}) | ||
| 260 | + def _call_qwen_api(self, system_prompt: str, user_prompt: str) -> Dict[str, Any]: | ||
| 261 | + """调用Qwen API""" | ||
| 262 | + headers = { | ||
| 263 | + "Authorization": f"Bearer {self.api_key}", | ||
| 264 | + "Content-Type": "application/json" | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + data = { | ||
| 268 | + "model": self.model, | ||
| 269 | + "messages": [ | ||
| 270 | + {"role": "system", "content": system_prompt}, | ||
| 271 | + {"role": "user", "content": user_prompt} | ||
| 272 | + ], | ||
| 273 | + "max_tokens": 1000, | ||
| 274 | + "temperature": 0.7, | ||
| 275 | + "top_p": 0.9 | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + try: | ||
| 279 | + response = requests.post( | ||
| 280 | + self.base_url, | ||
| 281 | + headers=headers, | ||
| 282 | + json=data, | ||
| 283 | + timeout=60 # 大模型需要更长的超时时间 | ||
| 284 | + ) | ||
| 285 | + response.raise_for_status() | ||
| 286 | + | ||
| 287 | + result = response.json() | ||
| 288 | + | ||
| 289 | + if "choices" in result and len(result["choices"]) > 0: | ||
| 290 | + content = result["choices"][0]["message"]["content"] | ||
| 291 | + return {"success": True, "content": content} | ||
| 292 | + else: | ||
| 293 | + return {"success": False, "error": "API返回格式异常"} | ||
| 294 | + | ||
| 295 | + except requests.exceptions.Timeout: | ||
| 296 | + return {"success": False, "error": "API请求超时"} | ||
| 297 | + except requests.exceptions.RequestException as e: | ||
| 298 | + return {"success": False, "error": f"网络请求错误: {str(e)}"} | ||
| 299 | + except Exception as e: | ||
| 300 | + return {"success": False, "error": f"API调用异常: {str(e)}"} | ||
| 301 | + | ||
| 302 | + def _format_host_speech(self, speech: str) -> str: | ||
| 303 | + """格式化主持人发言""" | ||
| 304 | + # 移除多余的空行 | ||
| 305 | + speech = re.sub(r'\n{3,}', '\n\n', speech) | ||
| 306 | + | ||
| 307 | + # 确保发言不会太长 | ||
| 308 | + if len(speech) > 500: | ||
| 309 | + # 尝试在句号处截断 | ||
| 310 | + sentences = speech.split('。') | ||
| 311 | + truncated = "" | ||
| 312 | + for sentence in sentences: | ||
| 313 | + if len(truncated) + len(sentence) < 450: | ||
| 314 | + truncated += sentence + "。" | ||
| 315 | + else: | ||
| 316 | + break | ||
| 317 | + speech = truncated.rstrip("。") + "。" | ||
| 318 | + | ||
| 319 | + # 移除可能的引号 | ||
| 320 | + speech = speech.strip('"\'""''') | ||
| 321 | + | ||
| 322 | + return speech.strip() | ||
| 323 | + | ||
| 324 | + | ||
| 325 | +# 创建全局实例 | ||
| 326 | +_host_instance = None | ||
| 327 | + | ||
| 328 | +def get_forum_host() -> ForumHost: | ||
| 329 | + """获取全局论坛主持人实例""" | ||
| 330 | + global _host_instance | ||
| 331 | + if _host_instance is None: | ||
| 332 | + _host_instance = ForumHost() | ||
| 333 | + return _host_instance | ||
| 334 | + | ||
| 335 | +def generate_host_speech(forum_logs: List[str]) -> Optional[str]: | ||
| 336 | + """生成主持人发言的便捷函数""" | ||
| 337 | + return get_forum_host().generate_host_speech(forum_logs) |
| @@ -12,6 +12,14 @@ import json | @@ -12,6 +12,14 @@ import json | ||
| 12 | from typing import Dict, Optional, List | 12 | from typing import Dict, Optional, List |
| 13 | from threading import Lock | 13 | from threading import Lock |
| 14 | 14 | ||
| 15 | +# 导入论坛主持人模块 | ||
| 16 | +try: | ||
| 17 | + from .llm_host import generate_host_speech | ||
| 18 | + HOST_AVAILABLE = True | ||
| 19 | +except ImportError: | ||
| 20 | + print("ForumEgine: 论坛主持人模块未找到,将以纯监控模式运行") | ||
| 21 | + HOST_AVAILABLE = False | ||
| 22 | + | ||
| 15 | class LogMonitor: | 23 | class LogMonitor: |
| 16 | """基于文件变化的智能日志监控器""" | 24 | """基于文件变化的智能日志监控器""" |
| 17 | 25 | ||
| @@ -35,6 +43,12 @@ class LogMonitor: | @@ -35,6 +43,12 @@ class LogMonitor: | ||
| 35 | self.is_searching = False # 是否正在搜索 | 43 | self.is_searching = False # 是否正在搜索 |
| 36 | self.search_inactive_count = 0 # 搜索非活跃计数器 | 44 | self.search_inactive_count = 0 # 搜索非活跃计数器 |
| 37 | self.write_lock = Lock() # 写入锁,防止并发写入冲突 | 45 | self.write_lock = Lock() # 写入锁,防止并发写入冲突 |
| 46 | + | ||
| 47 | + # 主持人相关状态 | ||
| 48 | + self.agent_speech_count = 0 # agent发言计数器 | ||
| 49 | + self.host_speech_threshold = 5 # 每5条agent发言触发一次主持人发言 | ||
| 50 | + self.last_host_speech_time = None # 上次主持人发言时间 | ||
| 51 | + self.min_host_interval = 30 # 主持人发言最小间隔(秒) | ||
| 38 | 52 | ||
| 39 | # 目标节点名称 - 直接匹配字符串 | 53 | # 目标节点名称 - 直接匹配字符串 |
| 40 | self.target_nodes = [ | 54 | self.target_nodes = [ |
| @@ -69,6 +83,10 @@ class LogMonitor: | @@ -69,6 +83,10 @@ class LogMonitor: | ||
| 69 | self.capturing_json = {} | 83 | self.capturing_json = {} |
| 70 | self.json_buffer = {} | 84 | self.json_buffer = {} |
| 71 | self.json_start_line = {} | 85 | self.json_start_line = {} |
| 86 | + | ||
| 87 | + # 重置主持人相关状态 | ||
| 88 | + self.agent_speech_count = 0 | ||
| 89 | + self.last_host_speech_time = None | ||
| 72 | 90 | ||
| 73 | except Exception as e: | 91 | except Exception as e: |
| 74 | print(f"ForumEgine: 清空forum.log失败: {e}") | 92 | print(f"ForumEgine: 清空forum.log失败: {e}") |
| @@ -369,6 +387,42 @@ class LogMonitor: | @@ -369,6 +387,42 @@ class LogMonitor: | ||
| 369 | 387 | ||
| 370 | return captured_contents | 388 | return captured_contents |
| 371 | 389 | ||
| 390 | + def _trigger_host_speech(self): | ||
| 391 | + """触发主持人发言""" | ||
| 392 | + if not HOST_AVAILABLE: | ||
| 393 | + return | ||
| 394 | + | ||
| 395 | + try: | ||
| 396 | + # 检查时间间隔 | ||
| 397 | + current_time = time.time() | ||
| 398 | + if self.last_host_speech_time: | ||
| 399 | + if current_time - self.last_host_speech_time < self.min_host_interval: | ||
| 400 | + return # 间隔太短,跳过 | ||
| 401 | + | ||
| 402 | + # 获取当前forum.log的内容 | ||
| 403 | + forum_logs = self.get_forum_log_content() | ||
| 404 | + if not forum_logs: | ||
| 405 | + return | ||
| 406 | + | ||
| 407 | + print("ForumEgine: 正在生成主持人发言...") | ||
| 408 | + | ||
| 409 | + # 调用主持人生成发言 | ||
| 410 | + host_speech = generate_host_speech(forum_logs) | ||
| 411 | + | ||
| 412 | + if host_speech: | ||
| 413 | + # 写入主持人发言到forum.log | ||
| 414 | + self.write_to_forum_log(host_speech, "HOST") | ||
| 415 | + self.last_host_speech_time = current_time | ||
| 416 | + print(f"ForumEgine: 主持人发言已记录") | ||
| 417 | + | ||
| 418 | + # 重置计数器 | ||
| 419 | + self.agent_speech_count = 0 | ||
| 420 | + else: | ||
| 421 | + print("ForumEgine: 主持人发言生成失败") | ||
| 422 | + | ||
| 423 | + except Exception as e: | ||
| 424 | + print(f"ForumEgine: 触发主持人发言时出错: {e}") | ||
| 425 | + | ||
| 372 | def _clean_content_tags(self, content: str, app_name: str) -> str: | 426 | def _clean_content_tags(self, content: str, app_name: str) -> str: |
| 373 | """清理内容中的重复标签和多余前缀""" | 427 | """清理内容中的重复标签和多余前缀""" |
| 374 | if not content: | 428 | if not content: |
| @@ -443,6 +497,18 @@ class LogMonitor: | @@ -443,6 +497,18 @@ class LogMonitor: | ||
| 443 | self.write_to_forum_log(content, source_tag) | 497 | self.write_to_forum_log(content, source_tag) |
| 444 | # print(f"ForumEgine: 捕获 - {content}") | 498 | # print(f"ForumEgine: 捕获 - {content}") |
| 445 | captured_any = True | 499 | captured_any = True |
| 500 | + | ||
| 501 | + # 增加agent发言计数 | ||
| 502 | + self.agent_speech_count += 1 | ||
| 503 | + | ||
| 504 | + # 检查是否需要触发主持人发言 | ||
| 505 | + if self.agent_speech_count >= self.host_speech_threshold: | ||
| 506 | + # 在单独的线程中触发主持人发言,避免阻塞监控 | ||
| 507 | + host_thread = threading.Thread( | ||
| 508 | + target=self._trigger_host_speech, | ||
| 509 | + daemon=True | ||
| 510 | + ) | ||
| 511 | + host_thread.start() | ||
| 446 | 512 | ||
| 447 | elif current_lines < previous_lines: | 513 | elif current_lines < previous_lines: |
| 448 | any_shrink = True | 514 | any_shrink = True |
| @@ -463,6 +529,9 @@ class LogMonitor: | @@ -463,6 +529,9 @@ class LogMonitor: | ||
| 463 | # print("ForumEgine: 日志缩短,结束当前搜索会话,回到等待状态") | 529 | # print("ForumEgine: 日志缩短,结束当前搜索会话,回到等待状态") |
| 464 | self.is_searching = False | 530 | self.is_searching = False |
| 465 | self.search_inactive_count = 0 | 531 | self.search_inactive_count = 0 |
| 532 | + # 重置主持人相关状态 | ||
| 533 | + self.agent_speech_count = 0 | ||
| 534 | + self.last_host_speech_time = None | ||
| 466 | # 写入结束标记 | 535 | # 写入结束标记 |
| 467 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 536 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
| 468 | self.write_to_forum_log(f"=== ForumEgine 论坛结束 - {end_time} ===", "SYSTEM") | 537 | self.write_to_forum_log(f"=== ForumEgine 论坛结束 - {end_time} ===", "SYSTEM") |
| @@ -474,6 +543,9 @@ class LogMonitor: | @@ -474,6 +543,9 @@ class LogMonitor: | ||
| 474 | print("ForumEgine: 长时间无活动,结束论坛") | 543 | print("ForumEgine: 长时间无活动,结束论坛") |
| 475 | self.is_searching = False | 544 | self.is_searching = False |
| 476 | self.search_inactive_count = 0 | 545 | self.search_inactive_count = 0 |
| 546 | + # 重置主持人相关状态 | ||
| 547 | + self.agent_speech_count = 0 | ||
| 548 | + self.last_host_speech_time = None | ||
| 477 | # 写入结束标记 | 549 | # 写入结束标记 |
| 478 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 550 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
| 479 | self.write_to_forum_log(f"=== ForumEgine 论坛结束 - {end_time} ===", "SYSTEM") | 551 | self.write_to_forum_log(f"=== ForumEgine 论坛结束 - {end_time} ===", "SYSTEM") |
-
Please register or login to post a comment