Remove forum host asynchronous strategy and simplify the process.
Showing
3 changed files
with
106 additions
and
156 deletions
| @@ -28,7 +28,7 @@ from retry_helper import with_graceful_retry, SEARCH_API_RETRY_CONFIG | @@ -28,7 +28,7 @@ from retry_helper import with_graceful_retry, SEARCH_API_RETRY_CONFIG | ||
| 28 | class ForumHost: | 28 | class ForumHost: |
| 29 | """ | 29 | """ |
| 30 | 论坛主持人类 | 30 | 论坛主持人类 |
| 31 | - 使用硅基流动的Qwen3-235B模型作为智能主持人 | 31 | + 使用Qwen3-235B模型作为智能主持人 |
| 32 | """ | 32 | """ |
| 33 | 33 | ||
| 34 | def __init__(self, api_key: str = None): | 34 | def __init__(self, api_key: str = None): |
| @@ -88,17 +88,13 @@ class ForumHost: | @@ -88,17 +88,13 @@ class ForumHost: | ||
| 88 | 88 | ||
| 89 | def _parse_forum_logs(self, forum_logs: List[str]) -> Dict[str, Any]: | 89 | def _parse_forum_logs(self, forum_logs: List[str]) -> Dict[str, Any]: |
| 90 | """ | 90 | """ |
| 91 | - 解析论坛日志,提取结构化信息 | 91 | + 解析论坛日志,提取agent发言 |
| 92 | 92 | ||
| 93 | Returns: | 93 | Returns: |
| 94 | - 包含agent发言、时间线等信息的字典 | 94 | + 包含agent发言的字典 |
| 95 | """ | 95 | """ |
| 96 | parsed = { | 96 | parsed = { |
| 97 | - 'agent_speeches': [], | ||
| 98 | - 'timeline': [], | ||
| 99 | - 'key_topics': set(), | ||
| 100 | - 'session_start': None, | ||
| 101 | - 'session_end': None | 97 | + 'agent_speeches': [] |
| 102 | } | 98 | } |
| 103 | 99 | ||
| 104 | for line in forum_logs: | 100 | for line in forum_logs: |
| @@ -110,16 +106,6 @@ class ForumHost: | @@ -110,16 +106,6 @@ class ForumHost: | ||
| 110 | if match: | 106 | if match: |
| 111 | timestamp, speaker, content = match.groups() | 107 | timestamp, speaker, content = match.groups() |
| 112 | 108 | ||
| 113 | - # 记录会话开始 | ||
| 114 | - if 'ForumEngine 监控开始' in content: | ||
| 115 | - parsed['session_start'] = timestamp | ||
| 116 | - continue | ||
| 117 | - | ||
| 118 | - # 记录会话结束 | ||
| 119 | - if 'ForumEngine 论坛结束' in content: | ||
| 120 | - parsed['session_end'] = timestamp | ||
| 121 | - continue | ||
| 122 | - | ||
| 123 | # 跳过系统消息和HOST自己的发言 | 109 | # 跳过系统消息和HOST自己的发言 |
| 124 | if speaker in ['SYSTEM', 'HOST']: | 110 | if speaker in ['SYSTEM', 'HOST']: |
| 125 | continue | 111 | continue |
| @@ -134,49 +120,9 @@ class ForumHost: | @@ -134,49 +120,9 @@ class ForumHost: | ||
| 134 | 'speaker': speaker, | 120 | 'speaker': speaker, |
| 135 | 'content': content | 121 | 'content': content |
| 136 | }) | 122 | }) |
| 137 | - | ||
| 138 | - # 提取关键主题(简单的关键词提取) | ||
| 139 | - self._extract_key_topics(content, parsed['key_topics']) | ||
| 140 | - | ||
| 141 | - # 提取时间线信息 | ||
| 142 | - self._extract_timeline(content, parsed['timeline']) | ||
| 143 | 123 | ||
| 144 | return parsed | 124 | return parsed |
| 145 | 125 | ||
| 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 | 126 | ||
| 181 | def _build_system_prompt(self) -> str: | 127 | def _build_system_prompt(self) -> str: |
| 182 | """构建系统prompt""" | 128 | """构建系统prompt""" |
| @@ -184,73 +130,72 @@ class ForumHost: | @@ -184,73 +130,72 @@ class ForumHost: | ||
| 184 | 130 | ||
| 185 | 你是一个多agent舆情分析系统的论坛主持人。你的职责是: | 131 | 你是一个多agent舆情分析系统的论坛主持人。你的职责是: |
| 186 | 132 | ||
| 187 | -1. **引导讨论**:根据各agent的发言,引导深入讨论关键问题 | ||
| 188 | -2. **纠正错误**:结合不同agent的视角以及言论来纠正错误 | ||
| 189 | -3. **整合观点**:综合不同agent的视角,形成更全面的认识 | ||
| 190 | -4. **推进分析**:提出新的分析角度或需要关注的问题 | 133 | +1. **事件梳理**:从各agent的发言中自动识别关键事件、人物、时间节点,按时间顺序整理事件脉络 |
| 134 | +2. **引导讨论**:根据各agent的发言,引导深入讨论关键问题,探究深层原因 | ||
| 135 | +3. **纠正错误**:结合不同agent的视角以及言论,如果发现事实错误或逻辑矛盾,请明确指出 | ||
| 136 | +4. **整合观点**:综合不同agent的视角,形成更全面的认识,找出共识和分歧 | ||
| 137 | +5. **趋势预测**:基于已有信息分析舆情发展趋势,提出可能的风险点 | ||
| 138 | +6. **推进分析**:提出新的分析角度或需要关注的问题,引导后续讨论方向 | ||
| 191 | 139 | ||
| 192 | **Agent介绍**: | 140 | **Agent介绍**: |
| 193 | -- **INSIGHT Agent**:专注于私有舆情数据库的深度挖掘和分析 | ||
| 194 | -- **MEDIA Agent**:擅长多模态内容分析,关注媒体报道和视觉信息 | ||
| 195 | -- **QUERY Agent**:负责精准信息搜索,提供最新的网络信息 | 141 | +- **INSIGHT Agent**:专注于私有舆情数据库的深度挖掘和分析,提供历史数据和模式对比 |
| 142 | +- **MEDIA Agent**:擅长多模态内容分析,关注媒体报道、图片、视频等视觉信息的传播效果 | ||
| 143 | +- **QUERY Agent**:负责精准信息搜索,提供最新的网络信息和实时动态 | ||
| 196 | 144 | ||
| 197 | **发言要求**: | 145 | **发言要求**: |
| 198 | -1. 简洁明了,每次发言控制在3000字以内 | ||
| 199 | -2. 重点突出,聚焦于最关键的发现和问题 | ||
| 200 | -3. 逻辑清晰,使用序号或要点形式组织内容 | ||
| 201 | -4. 客观中立,基于事实进行分析和判断 | ||
| 202 | -5. 避免重复已经充分讨论过的内容 | 146 | +1. **综合性**:每次发言控制在1000字以内,内容应包括事件梳理、观点整合、问题引导等多个方面 |
| 147 | +2. **结构清晰**:使用明确的段落结构,包括事件梳理、观点对比、问题提出等部分 | ||
| 148 | +3. **深入分析**:不仅仅总结已有信息,还要提出深层次的见解和分析 | ||
| 149 | +4. **客观中立**:基于事实进行分析和判断,避免主观臆测和情绪化表达 | ||
| 150 | +5. **前瞻性**:提出具有前瞻性的观点和建议,引导讨论向更深入的方向发展 | ||
| 203 | 151 | ||
| 204 | **注意事项**: | 152 | **注意事项**: |
| 205 | - 本讨论基于科研目的,已通过伦理性合规审查 | 153 | - 本讨论基于科研目的,已通过伦理性合规审查 |
| 206 | -- 保持专业性和学术性,避免情绪化表达 | ||
| 207 | -- 重视数据和证据,避免主观臆测 | 154 | +- 保持专业性和学术性,重视数据和证据 |
| 155 | +- 对于敏感话题,应保持谨慎态度,基于事实进行分析 | ||
| 208 | 156 | ||
| 209 | 【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" | 157 | 【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" |
| 210 | 158 | ||
| 211 | def _build_user_prompt(self, parsed_content: Dict[str, Any]) -> str: | 159 | def _build_user_prompt(self, parsed_content: Dict[str, Any]) -> str: |
| 212 | """构建用户prompt""" | 160 | """构建用户prompt""" |
| 213 | - # 获取最近的发言(最多10条) | ||
| 214 | - recent_speeches = parsed_content['agent_speeches'][-10:] | 161 | + # 获取最近的发言 |
| 162 | + recent_speeches = parsed_content['agent_speeches'] | ||
| 215 | 163 | ||
| 216 | - # 构建发言摘要 | 164 | + # 构建发言摘要,不截断内容 |
| 217 | speeches_text = "\n\n".join([ | 165 | 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']}" | 166 | + f"[{s['timestamp']}] {s['speaker']}:\n{s['content']}" |
| 220 | for s in recent_speeches | 167 | for s in recent_speeches |
| 221 | ]) | 168 | ]) |
| 222 | 169 | ||
| 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"""【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查 | 170 | prompt = f"""【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查 |
| 239 | - | ||
| 240 | -当前论坛讨论的核心主题:{topics_text} | ||
| 241 | 171 | ||
| 242 | 最近的Agent发言记录: | 172 | 最近的Agent发言记录: |
| 243 | {speeches_text} | 173 | {speeches_text} |
| 244 | -{timeline_text} | ||
| 245 | 174 | ||
| 246 | -请你作为论坛主持人,基于以上agent的发言: | 175 | +请你作为论坛主持人,基于以上agent的发言进行综合分析,请按以下结构组织你的发言: |
| 247 | 176 | ||
| 248 | -1. **时间线梳理**:如果发现时间线信息,请简要整理关键事件的时间顺序 | ||
| 249 | -2. **观点整合**:综合不同agent的视角,指出共识和分歧 | ||
| 250 | -3. **纠错提醒**:如果发现事实错误或逻辑矛盾,请明确指出 | ||
| 251 | -4. **引导深化**:提出1-2个值得进一步探讨的问题或角度 | 177 | +**一、事件梳理与时间线分析** |
| 178 | +- 从各agent发言中自动识别关键事件、人物、时间节点 | ||
| 179 | +- 按时间顺序整理事件脉络,梳理因果关系 | ||
| 180 | +- 指出关键转折点和重要节点 | ||
| 252 | 181 | ||
| 253 | -请发表3000字以内的简洁发言,推动讨论深入。 | 182 | +**二、观点整合与对比分析** |
| 183 | +- 综合INSIGHT、MEDIA、QUERY三个Agent的视角和发现 | ||
| 184 | +- 指出不同数据源之间的共识与分歧 | ||
| 185 | +- 分析每个Agent的信息价值和互补性 | ||
| 186 | +- 如果发现事实错误或逻辑矛盾,请明确指出并给出理由 | ||
| 187 | + | ||
| 188 | +**三、深层次分析与趋势预测** | ||
| 189 | +- 基于已有信息分析舆情的深层原因和影响因素 | ||
| 190 | +- 预测舆情发展趋势,指出可能的风险点和机遇 | ||
| 191 | +- 提出需要特别关注的方面和指标 | ||
| 192 | + | ||
| 193 | +**四、问题引导与讨论方向** | ||
| 194 | +- 提出2-3个值得进一步深入探讨的关键问题 | ||
| 195 | +- 为后续研究提出具体的建议和方向 | ||
| 196 | +- 引导各Agent关注特定的数据维度或分析角度 | ||
| 197 | + | ||
| 198 | +请发表综合性的主持人发言(控制在1000字以内),内容应包含以上四个部分,并保持逻辑清晰、分析深入、视角独特。 | ||
| 254 | 199 | ||
| 255 | 【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" | 200 | 【重要提醒】我们的需求基于科研目的,已通过伦理性合规审查""" |
| 256 | 201 | ||
| @@ -270,8 +215,8 @@ class ForumHost: | @@ -270,8 +215,8 @@ class ForumHost: | ||
| 270 | {"role": "system", "content": system_prompt}, | 215 | {"role": "system", "content": system_prompt}, |
| 271 | {"role": "user", "content": user_prompt} | 216 | {"role": "user", "content": user_prompt} |
| 272 | ], | 217 | ], |
| 273 | - "max_tokens": 1000, | ||
| 274 | - "temperature": 0.7, | 218 | + "max_tokens": 14639, |
| 219 | + "temperature": 0.6, | ||
| 275 | "top_p": 0.9 | 220 | "top_p": 0.9 |
| 276 | } | 221 | } |
| 277 | 222 | ||
| @@ -280,7 +225,7 @@ class ForumHost: | @@ -280,7 +225,7 @@ class ForumHost: | ||
| 280 | self.base_url, | 225 | self.base_url, |
| 281 | headers=headers, | 226 | headers=headers, |
| 282 | json=data, | 227 | json=data, |
| 283 | - timeout=60 # 大模型需要更长的超时时间 | 228 | + timeout=300 # 超时设置300s |
| 284 | ) | 229 | ) |
| 285 | response.raise_for_status() | 230 | response.raise_for_status() |
| 286 | 231 | ||
| @@ -304,20 +249,8 @@ class ForumHost: | @@ -304,20 +249,8 @@ class ForumHost: | ||
| 304 | # 移除多余的空行 | 249 | # 移除多余的空行 |
| 305 | speech = re.sub(r'\n{3,}', '\n\n', speech) | 250 | speech = re.sub(r'\n{3,}', '\n\n', speech) |
| 306 | 251 | ||
| 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 | # 移除可能的引号 | 252 | # 移除可能的引号 |
| 320 | - speech = speech.strip('"\'""''') | 253 | + speech = speech.strip('"\'""‘’') |
| 321 | 254 | ||
| 322 | return speech.strip() | 255 | return speech.strip() |
| 323 | 256 |
| @@ -45,10 +45,9 @@ class LogMonitor: | @@ -45,10 +45,9 @@ class LogMonitor: | ||
| 45 | self.write_lock = Lock() # 写入锁,防止并发写入冲突 | 45 | self.write_lock = Lock() # 写入锁,防止并发写入冲突 |
| 46 | 46 | ||
| 47 | # 主持人相关状态 | 47 | # 主持人相关状态 |
| 48 | - self.agent_speech_count = 0 # agent发言计数器 | 48 | + self.agent_speeches_buffer = [] # agent发言缓冲区 |
| 49 | self.host_speech_threshold = 5 # 每5条agent发言触发一次主持人发言 | 49 | self.host_speech_threshold = 5 # 每5条agent发言触发一次主持人发言 |
| 50 | - self.last_host_speech_time = None # 上次主持人发言时间 | ||
| 51 | - self.min_host_interval = 30 # 主持人发言最小间隔(秒) | 50 | + self.is_host_generating = False # 主持人是否正在生成发言 |
| 52 | 51 | ||
| 53 | # 目标节点名称 - 直接匹配字符串 | 52 | # 目标节点名称 - 直接匹配字符串 |
| 54 | self.target_nodes = [ | 53 | self.target_nodes = [ |
| @@ -85,8 +84,8 @@ class LogMonitor: | @@ -85,8 +84,8 @@ class LogMonitor: | ||
| 85 | self.json_start_line = {} | 84 | self.json_start_line = {} |
| 86 | 85 | ||
| 87 | # 重置主持人相关状态 | 86 | # 重置主持人相关状态 |
| 88 | - self.agent_speech_count = 0 | ||
| 89 | - self.last_host_speech_time = None | 87 | + self.agent_speeches_buffer = [] |
| 88 | + self.is_host_generating = False | ||
| 90 | 89 | ||
| 91 | except Exception as e: | 90 | except Exception as e: |
| 92 | print(f"ForumEngine: 清空forum.log失败: {e}") | 91 | print(f"ForumEngine: 清空forum.log失败: {e}") |
| @@ -388,40 +387,41 @@ class LogMonitor: | @@ -388,40 +387,41 @@ class LogMonitor: | ||
| 388 | return captured_contents | 387 | return captured_contents |
| 389 | 388 | ||
| 390 | def _trigger_host_speech(self): | 389 | def _trigger_host_speech(self): |
| 391 | - """触发主持人发言""" | ||
| 392 | - if not HOST_AVAILABLE: | 390 | + """触发主持人发言(同步执行)""" |
| 391 | + if not HOST_AVAILABLE or self.is_host_generating: | ||
| 393 | return | 392 | return |
| 394 | 393 | ||
| 395 | try: | 394 | 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 # 间隔太短,跳过 | 395 | + # 设置生成标志 |
| 396 | + self.is_host_generating = True | ||
| 401 | 397 | ||
| 402 | - # 获取当前forum.log的内容 | ||
| 403 | - forum_logs = self.get_forum_log_content() | ||
| 404 | - if not forum_logs: | 398 | + # 获取缓冲区的5条发言 |
| 399 | + recent_speeches = self.agent_speeches_buffer[:5] | ||
| 400 | + if len(recent_speeches) < 5: | ||
| 401 | + self.is_host_generating = False | ||
| 405 | return | 402 | return |
| 406 | 403 | ||
| 407 | print("ForumEngine: 正在生成主持人发言...") | 404 | print("ForumEngine: 正在生成主持人发言...") |
| 408 | 405 | ||
| 409 | - # 调用主持人生成发言 | ||
| 410 | - host_speech = generate_host_speech(forum_logs) | 406 | + # 调用主持人生成发言(传入最近5条) |
| 407 | + host_speech = generate_host_speech(recent_speeches) | ||
| 411 | 408 | ||
| 412 | if host_speech: | 409 | if host_speech: |
| 413 | # 写入主持人发言到forum.log | 410 | # 写入主持人发言到forum.log |
| 414 | self.write_to_forum_log(host_speech, "HOST") | 411 | self.write_to_forum_log(host_speech, "HOST") |
| 415 | - self.last_host_speech_time = current_time | ||
| 416 | print(f"ForumEngine: 主持人发言已记录") | 412 | print(f"ForumEngine: 主持人发言已记录") |
| 417 | 413 | ||
| 418 | - # 重置计数器 | ||
| 419 | - self.agent_speech_count = 0 | 414 | + # 清空已处理的5条发言 |
| 415 | + self.agent_speeches_buffer = self.agent_speeches_buffer[5:] | ||
| 420 | else: | 416 | else: |
| 421 | print("ForumEngine: 主持人发言生成失败") | 417 | print("ForumEngine: 主持人发言生成失败") |
| 418 | + | ||
| 419 | + # 重置生成标志 | ||
| 420 | + self.is_host_generating = False | ||
| 422 | 421 | ||
| 423 | except Exception as e: | 422 | except Exception as e: |
| 424 | print(f"ForumEngine: 触发主持人发言时出错: {e}") | 423 | print(f"ForumEngine: 触发主持人发言时出错: {e}") |
| 424 | + self.is_host_generating = False | ||
| 425 | 425 | ||
| 426 | def _clean_content_tags(self, content: str, app_name: str) -> str: | 426 | def _clean_content_tags(self, content: str, app_name: str) -> str: |
| 427 | """清理内容中的重复标签和多余前缀""" | 427 | """清理内容中的重复标签和多余前缀""" |
| @@ -498,17 +498,15 @@ class LogMonitor: | @@ -498,17 +498,15 @@ class LogMonitor: | ||
| 498 | # print(f"ForumEngine: 捕获 - {content}") | 498 | # print(f"ForumEngine: 捕获 - {content}") |
| 499 | captured_any = True | 499 | captured_any = True |
| 500 | 500 | ||
| 501 | - # 增加agent发言计数 | ||
| 502 | - self.agent_speech_count += 1 | 501 | + # 将发言添加到缓冲区(格式化为完整的日志行) |
| 502 | + timestamp = datetime.now().strftime('%H:%M:%S') | ||
| 503 | + log_line = f"[{timestamp}] [{source_tag}] {content}" | ||
| 504 | + self.agent_speeches_buffer.append(log_line) | ||
| 503 | 505 | ||
| 504 | # 检查是否需要触发主持人发言 | 506 | # 检查是否需要触发主持人发言 |
| 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() | 507 | + if len(self.agent_speeches_buffer) >= self.host_speech_threshold and not self.is_host_generating: |
| 508 | + # 同步触发主持人发言 | ||
| 509 | + self._trigger_host_speech() | ||
| 512 | 510 | ||
| 513 | elif current_lines < previous_lines: | 511 | elif current_lines < previous_lines: |
| 514 | any_shrink = True | 512 | any_shrink = True |
| @@ -530,8 +528,8 @@ class LogMonitor: | @@ -530,8 +528,8 @@ class LogMonitor: | ||
| 530 | self.is_searching = False | 528 | self.is_searching = False |
| 531 | self.search_inactive_count = 0 | 529 | self.search_inactive_count = 0 |
| 532 | # 重置主持人相关状态 | 530 | # 重置主持人相关状态 |
| 533 | - self.agent_speech_count = 0 | ||
| 534 | - self.last_host_speech_time = None | 531 | + self.agent_speeches_buffer = [] |
| 532 | + self.is_host_generating = False | ||
| 535 | # 写入结束标记 | 533 | # 写入结束标记 |
| 536 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 534 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
| 537 | self.write_to_forum_log(f"=== ForumEngine 论坛结束 - {end_time} ===", "SYSTEM") | 535 | self.write_to_forum_log(f"=== ForumEngine 论坛结束 - {end_time} ===", "SYSTEM") |
| @@ -544,8 +542,8 @@ class LogMonitor: | @@ -544,8 +542,8 @@ class LogMonitor: | ||
| 544 | self.is_searching = False | 542 | self.is_searching = False |
| 545 | self.search_inactive_count = 0 | 543 | self.search_inactive_count = 0 |
| 546 | # 重置主持人相关状态 | 544 | # 重置主持人相关状态 |
| 547 | - self.agent_speech_count = 0 | ||
| 548 | - self.last_host_speech_time = None | 545 | + self.agent_speeches_buffer = [] |
| 546 | + self.is_host_generating = False | ||
| 549 | # 写入结束标记 | 547 | # 写入结束标记 |
| 550 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 548 | end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
| 551 | self.write_to_forum_log(f"=== ForumEngine 论坛结束 - {end_time} ===", "SYSTEM") | 549 | self.write_to_forum_log(f"=== ForumEngine 论坛结束 - {end_time} ===", "SYSTEM") |
| @@ -593,6 +593,18 @@ | @@ -593,6 +593,18 @@ | ||
| 593 | background-color: #f2ebf3; | 593 | background-color: #f2ebf3; |
| 594 | border-color: #8e6a9f; | 594 | border-color: #8e6a9f; |
| 595 | } | 595 | } |
| 596 | + | ||
| 597 | + /* HOST主持人样式 */ | ||
| 598 | + .forum-message.host { | ||
| 599 | + align-self: stretch; | ||
| 600 | + background-color: #fff8dc; /* 浅黄色背景 */ | ||
| 601 | + border-color: #daa520; /* 金色边框 */ | ||
| 602 | + color: #000000; | ||
| 603 | + width: 100%; | ||
| 604 | + max-width: 100%; | ||
| 605 | + margin: 0 0 20px 0; | ||
| 606 | + font-style: italic; /* 斜体字体显示主持人发言 */ | ||
| 607 | + } | ||
| 596 | 608 | ||
| 597 | .forum-message-header { | 609 | .forum-message-header { |
| 598 | font-weight: bold; | 610 | font-weight: bold; |
| @@ -847,7 +859,7 @@ | @@ -847,7 +859,7 @@ | ||
| 847 | insight: 'Insight Agent - 私有数据库挖掘', | 859 | insight: 'Insight Agent - 私有数据库挖掘', |
| 848 | media: 'Media Agent - 多模态内容分析', | 860 | media: 'Media Agent - 多模态内容分析', |
| 849 | query: 'Query Agent - 精准信息搜索', | 861 | query: 'Query Agent - 精准信息搜索', |
| 850 | - forum: 'Forum Agent - 多智能体交流', | 862 | + forum: 'Forum Engine - 多智能体交流', |
| 851 | report: 'Report Agent - 最终报告生成' | 863 | report: 'Report Agent - 最终报告生成' |
| 852 | }; | 864 | }; |
| 853 | 865 | ||
| @@ -1033,7 +1045,7 @@ | @@ -1033,7 +1045,7 @@ | ||
| 1033 | // 根据应用类型处理不同的显示逻辑 | 1045 | // 根据应用类型处理不同的显示逻辑 |
| 1034 | if (app === 'forum') { | 1046 | if (app === 'forum') { |
| 1035 | // 切换到论坛模式 | 1047 | // 切换到论坛模式 |
| 1036 | - document.getElementById('embeddedHeader').textContent = 'Forum Agent - 多智能体交流'; | 1048 | + document.getElementById('embeddedHeader').textContent = 'Forum Engine - 多智能体交流'; |
| 1037 | 1049 | ||
| 1038 | // 显示论坛容器,隐藏其他内容 | 1050 | // 显示论坛容器,隐藏其他内容 |
| 1039 | document.getElementById('forumContainer').classList.add('active'); | 1051 | document.getElementById('forumContainer').classList.add('active'); |
| @@ -1222,7 +1234,7 @@ | @@ -1222,7 +1234,7 @@ | ||
| 1222 | 1234 | ||
| 1223 | // 如果是Forum Engine,直接显示论坛界面 | 1235 | // 如果是Forum Engine,直接显示论坛界面 |
| 1224 | if (app === 'forum') { | 1236 | if (app === 'forum') { |
| 1225 | - header.textContent = 'Forum Agent - 多智能体交流'; | 1237 | + header.textContent = 'Forum Engine - 多智能体交流'; |
| 1226 | 1238 | ||
| 1227 | // 隐藏所有iframe | 1239 | // 隐藏所有iframe |
| 1228 | if (typeof preloadedIframes !== 'undefined') { | 1240 | if (typeof preloadedIframes !== 'undefined') { |
| @@ -1699,14 +1711,14 @@ | @@ -1699,14 +1711,14 @@ | ||
| 1699 | const source = sourceMatch[1]; | 1711 | const source = sourceMatch[1]; |
| 1700 | const content = sourceMatch[2]; | 1712 | const content = sourceMatch[2]; |
| 1701 | 1713 | ||
| 1702 | - // 只处理三个Engine的消息,过滤掉系统消息和空内容 | ||
| 1703 | - if (!['QUERY', 'INSIGHT', 'MEDIA'].includes(source.toUpperCase()) || | 1714 | + // 处理四种消息类型:三个Engine和HOST,过滤掉系统消息和空内容 |
| 1715 | + if (!['QUERY', 'INSIGHT', 'MEDIA', 'HOST'].includes(source.toUpperCase()) || | ||
| 1704 | !content || content.includes('=== ForumEngine')) { | 1716 | !content || content.includes('=== ForumEngine')) { |
| 1705 | return null; | 1717 | return null; |
| 1706 | } | 1718 | } |
| 1707 | 1719 | ||
| 1708 | // 根据源类型确定消息类型 | 1720 | // 根据源类型确定消息类型 |
| 1709 | - const messageType = 'agent'; | 1721 | + let messageType = 'agent'; |
| 1710 | let displayName = ''; | 1722 | let displayName = ''; |
| 1711 | 1723 | ||
| 1712 | switch(source.toUpperCase()) { | 1724 | switch(source.toUpperCase()) { |
| @@ -1719,6 +1731,10 @@ | @@ -1719,6 +1731,10 @@ | ||
| 1719 | case 'QUERY': | 1731 | case 'QUERY': |
| 1720 | displayName = 'Query Engine'; | 1732 | displayName = 'Query Engine'; |
| 1721 | break; | 1733 | break; |
| 1734 | + case 'HOST': | ||
| 1735 | + messageType = 'host'; | ||
| 1736 | + displayName = 'Forum Host'; | ||
| 1737 | + break; | ||
| 1722 | } | 1738 | } |
| 1723 | 1739 | ||
| 1724 | // 处理内容中的转义字符 | 1740 | // 处理内容中的转义字符 |
| @@ -1758,6 +1774,8 @@ | @@ -1758,6 +1774,8 @@ | ||
| 1758 | messageDiv.classList.add('insight-engine'); | 1774 | messageDiv.classList.add('insight-engine'); |
| 1759 | } else if (data.source.toLowerCase().includes('media')) { | 1775 | } else if (data.source.toLowerCase().includes('media')) { |
| 1760 | messageDiv.classList.add('media-engine'); | 1776 | messageDiv.classList.add('media-engine'); |
| 1777 | + } else if (data.source.toLowerCase().includes('host')) { | ||
| 1778 | + messageDiv.classList.add('host'); | ||
| 1761 | } | 1779 | } |
| 1762 | } | 1780 | } |
| 1763 | 1781 | ||
| @@ -1790,6 +1808,7 @@ | @@ -1790,6 +1808,7 @@ | ||
| 1790 | case 'user': return '用户'; | 1808 | case 'user': return '用户'; |
| 1791 | case 'agent': return 'AI助手'; | 1809 | case 'agent': return 'AI助手'; |
| 1792 | case 'system': return '系统'; | 1810 | case 'system': return '系统'; |
| 1811 | + case 'host': return '论坛主持人'; | ||
| 1793 | default: return '未知'; | 1812 | default: return '未知'; |
| 1794 | } | 1813 | } |
| 1795 | } | 1814 | } |
-
Please register or login to post a comment