666ghj

Remove forum host asynchronous strategy and simplify the process.

@@ -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
@@ -135,48 +121,8 @@ class ForumHost: @@ -135,48 +121,8 @@ class ForumHost:
135 'content': content 121 'content': content
136 }) 122 })
137 123
138 - # 提取关键主题(简单的关键词提取)  
139 - self._extract_key_topics(content, parsed['key_topics'])  
140 -  
141 - # 提取时间线信息  
142 - self._extract_timeline(content, parsed['timeline'])  
143 -  
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 171
240 -当前论坛讨论的核心主题:{topics_text}  
241 -  
242 最近的Agent发言记录: 172 最近的Agent发言记录:
243 {speeches_text} 173 {speeches_text}
244 -{timeline_text}  
245 174
246 -请你作为论坛主持人,基于以上agent的发言: 175 +请你作为论坛主持人,基于以上agent的发言进行综合分析,请按以下结构组织你的发言:
  176 +
  177 +**一、事件梳理与时间线分析**
  178 +- 从各agent发言中自动识别关键事件、人物、时间节点
  179 +- 按时间顺序整理事件脉络,梳理因果关系
  180 +- 指出关键转折点和重要节点
  181 +
  182 +**二、观点整合与对比分析**
  183 +- 综合INSIGHT、MEDIA、QUERY三个Agent的视角和发现
  184 +- 指出不同数据源之间的共识与分歧
  185 +- 分析每个Agent的信息价值和互补性
  186 +- 如果发现事实错误或逻辑矛盾,请明确指出并给出理由
247 187
248 -1. **时间线梳理**:如果发现时间线信息,请简要整理关键事件的时间顺序  
249 -2. **观点整合**:综合不同agent的视角,指出共识和分歧  
250 -3. **纠错提醒**:如果发现事实错误或逻辑矛盾,请明确指出  
251 -4. **引导深化**:提出1-2个值得进一步探讨的问题或角度 188 +**三、深层次分析与趋势预测**
  189 +- 基于已有信息分析舆情的深层原因和影响因素
  190 +- 预测舆情发展趋势,指出可能的风险点和机遇
  191 +- 提出需要特别关注的方面和指标
252 192
253 -请发表3000字以内的简洁发言,推动讨论深入。 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 # 间隔太短,跳过  
401 -  
402 - # 获取当前forum.log的内容  
403 - forum_logs = self.get_forum_log_content()  
404 - if not forum_logs: 395 + # 设置生成标志
  396 + self.is_host_generating = True
  397 +
  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: 主持人发言生成失败")
422 418
  419 + # 重置生成标志
  420 + self.is_host_generating = False
  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")
@@ -594,6 +594,18 @@ @@ -594,6 +594,18 @@
594 border-color: #8e6a9f; 594 border-color: #8e6a9f;
595 } 595 }
596 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 + }
  608 +
597 .forum-message-header { 609 .forum-message-header {
598 font-weight: bold; 610 font-weight: bold;
599 margin-bottom: 8px; 611 margin-bottom: 8px;
@@ -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 }