Showing
12 changed files
with
408 additions
and
15 deletions
ForumEgine/__init__.py
0 → 100644
ForumEgine/monitor.py
0 → 100644
| 1 | +""" | ||
| 2 | +日志监控器 - 实时监控三个log文件中的SummaryNode和ReportFormattingNode输出 | ||
| 3 | +""" | ||
| 4 | + | ||
| 5 | +import os | ||
| 6 | +import time | ||
| 7 | +import threading | ||
| 8 | +from pathlib import Path | ||
| 9 | +from datetime import datetime | ||
| 10 | +import re | ||
| 11 | +from typing import Dict, Optional, List | ||
| 12 | +from threading import Lock | ||
| 13 | + | ||
| 14 | +class LogMonitor: | ||
| 15 | + """基于文件变化的智能日志监控器""" | ||
| 16 | + | ||
| 17 | + def __init__(self, log_dir: str = "logs"): | ||
| 18 | + """初始化日志监控器""" | ||
| 19 | + self.log_dir = Path(log_dir) | ||
| 20 | + self.forum_log_file = self.log_dir / "forum.log" | ||
| 21 | + | ||
| 22 | + # 要监控的日志文件 | ||
| 23 | + self.monitored_logs = { | ||
| 24 | + 'insight': self.log_dir / 'insight.log', | ||
| 25 | + 'media': self.log_dir / 'media.log', | ||
| 26 | + 'query': self.log_dir / 'query.log' | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + # 监控状态 | ||
| 30 | + self.is_monitoring = False | ||
| 31 | + self.monitor_thread = None | ||
| 32 | + self.file_positions = {} # 记录每个文件的读取位置 | ||
| 33 | + self.file_line_counts = {} # 记录每个文件的行数 | ||
| 34 | + self.is_searching = False # 是否正在搜索 | ||
| 35 | + self.search_inactive_count = 0 # 搜索非活跃计数器 | ||
| 36 | + self.write_lock = Lock() # 写入锁,防止并发写入冲突 | ||
| 37 | + | ||
| 38 | + # 目标节点名称 - 直接匹配字符串 | ||
| 39 | + self.target_nodes = [ | ||
| 40 | + 'FirstSummaryNode', | ||
| 41 | + 'ReflectionSummaryNode', | ||
| 42 | + 'ReportFormattingNode' | ||
| 43 | + ] | ||
| 44 | + | ||
| 45 | + # 确保logs目录存在 | ||
| 46 | + self.log_dir.mkdir(exist_ok=True) | ||
| 47 | + | ||
| 48 | + def clear_forum_log(self): | ||
| 49 | + """清空forum.log文件""" | ||
| 50 | + try: | ||
| 51 | + if self.forum_log_file.exists(): | ||
| 52 | + self.forum_log_file.unlink() | ||
| 53 | + | ||
| 54 | + # 创建新的forum.log文件并写入开始标记 | ||
| 55 | + with open(self.forum_log_file, 'w', encoding='utf-8') as f: | ||
| 56 | + start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
| 57 | + f.write(f"=== ForumEgine 监控开始 - {start_time} ===\n") | ||
| 58 | + | ||
| 59 | + print(f"ForumEgine: forum.log 已清空并初始化") | ||
| 60 | + | ||
| 61 | + except Exception as e: | ||
| 62 | + print(f"ForumEgine: 清空forum.log失败: {e}") | ||
| 63 | + | ||
| 64 | + def write_to_forum_log(self, content: str): | ||
| 65 | + """写入内容到forum.log(线程安全)""" | ||
| 66 | + try: | ||
| 67 | + with self.write_lock: # 使用锁确保线程安全 | ||
| 68 | + with open(self.forum_log_file, 'a', encoding='utf-8') as f: | ||
| 69 | + timestamp = datetime.now().strftime('%H:%M:%S') | ||
| 70 | + f.write(f"[{timestamp}] {content}\n") | ||
| 71 | + f.flush() | ||
| 72 | + except Exception as e: | ||
| 73 | + print(f"ForumEgine: 写入forum.log失败: {e}") | ||
| 74 | + | ||
| 75 | + def is_target_log_line(self, line: str) -> bool: | ||
| 76 | + """检查是否是目标日志行(SummaryNode或ReportFormattingNode)""" | ||
| 77 | + # 简单字符串包含检查,更可靠 | ||
| 78 | + for node_name in self.target_nodes: | ||
| 79 | + if node_name in line: | ||
| 80 | + return True | ||
| 81 | + return False | ||
| 82 | + | ||
| 83 | + def extract_node_content(self, line: str) -> Optional[str]: | ||
| 84 | + """提取节点内容""" | ||
| 85 | + # 移除时间戳部分,保留节点名称和消息 | ||
| 86 | + # 格式: [HH:MM:SS] [NodeName] message | ||
| 87 | + match = re.search(r'\[\d{2}:\d{2}:\d{2}\]\s*(.+)', line) | ||
| 88 | + if match: | ||
| 89 | + return match.group(1).strip() | ||
| 90 | + return line.strip() | ||
| 91 | + | ||
| 92 | + def get_file_size(self, file_path: Path) -> int: | ||
| 93 | + """获取文件大小""" | ||
| 94 | + try: | ||
| 95 | + return file_path.stat().st_size if file_path.exists() else 0 | ||
| 96 | + except: | ||
| 97 | + return 0 | ||
| 98 | + | ||
| 99 | + def get_file_line_count(self, file_path: Path) -> int: | ||
| 100 | + """获取文件行数""" | ||
| 101 | + try: | ||
| 102 | + if not file_path.exists(): | ||
| 103 | + return 0 | ||
| 104 | + with open(file_path, 'r', encoding='utf-8') as f: | ||
| 105 | + return sum(1 for _ in f) | ||
| 106 | + except: | ||
| 107 | + return 0 | ||
| 108 | + | ||
| 109 | + # 移除这个方法,逻辑已经合并到monitor_logs中 | ||
| 110 | + | ||
| 111 | + def read_new_lines(self, file_path: Path, app_name: str) -> List[str]: | ||
| 112 | + """读取文件中的新行""" | ||
| 113 | + new_lines = [] | ||
| 114 | + | ||
| 115 | + try: | ||
| 116 | + if not file_path.exists(): | ||
| 117 | + return new_lines | ||
| 118 | + | ||
| 119 | + current_size = self.get_file_size(file_path) | ||
| 120 | + last_position = self.file_positions.get(app_name, 0) | ||
| 121 | + | ||
| 122 | + # 如果文件变小了,说明被清空了,重新从头开始 | ||
| 123 | + if current_size < last_position: | ||
| 124 | + last_position = 0 | ||
| 125 | + | ||
| 126 | + if current_size > last_position: | ||
| 127 | + with open(file_path, 'r', encoding='utf-8') as f: | ||
| 128 | + f.seek(last_position) | ||
| 129 | + new_content = f.read() | ||
| 130 | + new_lines = new_content.split('\n') | ||
| 131 | + | ||
| 132 | + # 更新位置 | ||
| 133 | + self.file_positions[app_name] = f.tell() | ||
| 134 | + | ||
| 135 | + # 过滤空行 | ||
| 136 | + new_lines = [line.strip() for line in new_lines if line.strip()] | ||
| 137 | + | ||
| 138 | + except Exception as e: | ||
| 139 | + print(f"ForumEgine: 读取{app_name}日志失败: {e}") | ||
| 140 | + | ||
| 141 | + return new_lines | ||
| 142 | + | ||
| 143 | + def monitor_logs(self): | ||
| 144 | + """智能监控日志文件""" | ||
| 145 | + print("ForumEgine: 开始智能监控日志文件...") | ||
| 146 | + | ||
| 147 | + # 初始化文件行数和位置 - 记录当前状态作为基线 | ||
| 148 | + for app_name, log_file in self.monitored_logs.items(): | ||
| 149 | + self.file_line_counts[app_name] = self.get_file_line_count(log_file) | ||
| 150 | + self.file_positions[app_name] = self.get_file_size(log_file) | ||
| 151 | + print(f"ForumEgine: {app_name} 基线行数: {self.file_line_counts[app_name]}") | ||
| 152 | + | ||
| 153 | + while self.is_monitoring: | ||
| 154 | + try: | ||
| 155 | + # 同时检测三个log文件的变化 | ||
| 156 | + any_growth = False | ||
| 157 | + any_shrink = False | ||
| 158 | + captured_any = False | ||
| 159 | + | ||
| 160 | + # 为每个log文件独立处理 | ||
| 161 | + for app_name, log_file in self.monitored_logs.items(): | ||
| 162 | + current_lines = self.get_file_line_count(log_file) | ||
| 163 | + previous_lines = self.file_line_counts.get(app_name, 0) | ||
| 164 | + | ||
| 165 | + if current_lines > previous_lines: | ||
| 166 | + any_growth = True | ||
| 167 | + # 立即读取新增内容 | ||
| 168 | + new_lines = self.read_new_lines(log_file, app_name) | ||
| 169 | + | ||
| 170 | + # 先检查是否需要触发搜索(只触发一次) | ||
| 171 | + if not self.is_searching: | ||
| 172 | + for line in new_lines: | ||
| 173 | + if line.strip() and 'FirstSummaryNode' in line: | ||
| 174 | + print(f"ForumEgine: 在{app_name}中检测到FirstSummaryNode,开始监控记录") | ||
| 175 | + self.is_searching = True | ||
| 176 | + self.search_inactive_count = 0 | ||
| 177 | + # 清空forum.log开始新会话 | ||
| 178 | + self.clear_forum_log() | ||
| 179 | + break # 找到一个就够了,跳出循环 | ||
| 180 | + | ||
| 181 | + # 处理所有新增内容(如果正在搜索状态) | ||
| 182 | + if self.is_searching: | ||
| 183 | + for line in new_lines: | ||
| 184 | + if line.strip() and self.is_target_log_line(line): | ||
| 185 | + # 立即记录目标节点输出 | ||
| 186 | + formatted_content = f"[{app_name.upper()}] {line.strip()}" | ||
| 187 | + self.write_to_forum_log(formatted_content) | ||
| 188 | + print(f"ForumEgine: 捕获 - {formatted_content}") | ||
| 189 | + captured_any = True | ||
| 190 | + | ||
| 191 | + elif current_lines < previous_lines: | ||
| 192 | + any_shrink = True | ||
| 193 | + print(f"ForumEgine: 检测到 {app_name} 日志缩短,将重置基线") | ||
| 194 | + # 重置文件位置到新的文件末尾 | ||
| 195 | + self.file_positions[app_name] = self.get_file_size(log_file) | ||
| 196 | + | ||
| 197 | + # 更新行数记录 | ||
| 198 | + self.file_line_counts[app_name] = current_lines | ||
| 199 | + | ||
| 200 | + # 检查是否应该结束当前搜索会话 | ||
| 201 | + if self.is_searching: | ||
| 202 | + if any_shrink: | ||
| 203 | + # log变短,结束当前搜索会话,重置为等待状态 | ||
| 204 | + print("ForumEgine: 日志缩短,结束当前搜索会话,回到等待状态") | ||
| 205 | + self.is_searching = False | ||
| 206 | + self.search_inactive_count = 0 | ||
| 207 | + # 写入结束标记 | ||
| 208 | + end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
| 209 | + self.write_to_forum_log(f"=== ForumEgine 搜索会话结束 - {end_time} ===") | ||
| 210 | + print("ForumEgine: 已重置基线,等待下次FirstSummaryNode触发") | ||
| 211 | + elif not any_growth and not captured_any: | ||
| 212 | + # 没有增长也没有捕获内容,增加非活跃计数 | ||
| 213 | + self.search_inactive_count += 1 | ||
| 214 | + if self.search_inactive_count >= 30: # 30秒无活动才结束 | ||
| 215 | + print("ForumEgine: 长时间无活动,结束搜索会话") | ||
| 216 | + self.is_searching = False | ||
| 217 | + self.search_inactive_count = 0 | ||
| 218 | + # 写入结束标记 | ||
| 219 | + end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
| 220 | + self.write_to_forum_log(f"=== ForumEgine 搜索会话超时结束 - {end_time} ===") | ||
| 221 | + else: | ||
| 222 | + self.search_inactive_count = 0 # 重置计数器 | ||
| 223 | + | ||
| 224 | + # 短暂休眠 | ||
| 225 | + time.sleep(1) | ||
| 226 | + | ||
| 227 | + except Exception as e: | ||
| 228 | + print(f"ForumEgine: 监控过程中出错: {e}") | ||
| 229 | + import traceback | ||
| 230 | + traceback.print_exc() | ||
| 231 | + time.sleep(2) | ||
| 232 | + | ||
| 233 | + print("ForumEgine: 停止监控日志文件") | ||
| 234 | + | ||
| 235 | + def start_monitoring(self): | ||
| 236 | + """开始智能监控""" | ||
| 237 | + if self.is_monitoring: | ||
| 238 | + print("ForumEgine: 监控已经在运行中") | ||
| 239 | + return False | ||
| 240 | + | ||
| 241 | + try: | ||
| 242 | + # 启动监控 | ||
| 243 | + self.is_monitoring = True | ||
| 244 | + self.monitor_thread = threading.Thread(target=self.monitor_logs, daemon=True) | ||
| 245 | + self.monitor_thread.start() | ||
| 246 | + | ||
| 247 | + print("ForumEgine: 智能监控已启动") | ||
| 248 | + return True | ||
| 249 | + | ||
| 250 | + except Exception as e: | ||
| 251 | + print(f"ForumEgine: 启动监控失败: {e}") | ||
| 252 | + self.is_monitoring = False | ||
| 253 | + return False | ||
| 254 | + | ||
| 255 | + def stop_monitoring(self): | ||
| 256 | + """停止监控""" | ||
| 257 | + if not self.is_monitoring: | ||
| 258 | + print("ForumEgine: 监控未运行") | ||
| 259 | + return | ||
| 260 | + | ||
| 261 | + try: | ||
| 262 | + self.is_monitoring = False | ||
| 263 | + | ||
| 264 | + if self.monitor_thread and self.monitor_thread.is_alive(): | ||
| 265 | + self.monitor_thread.join(timeout=2) | ||
| 266 | + | ||
| 267 | + # 写入结束标记 | ||
| 268 | + end_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
| 269 | + self.write_to_forum_log(f"=== ForumEgine 监控结束 - {end_time} ===") | ||
| 270 | + | ||
| 271 | + print("ForumEgine: 监控已停止") | ||
| 272 | + | ||
| 273 | + except Exception as e: | ||
| 274 | + print(f"ForumEgine: 停止监控失败: {e}") | ||
| 275 | + | ||
| 276 | + def get_forum_log_content(self) -> List[str]: | ||
| 277 | + """获取forum.log的内容""" | ||
| 278 | + try: | ||
| 279 | + if not self.forum_log_file.exists(): | ||
| 280 | + return [] | ||
| 281 | + | ||
| 282 | + with open(self.forum_log_file, 'r', encoding='utf-8') as f: | ||
| 283 | + return [line.rstrip('\n\r') for line in f.readlines()] | ||
| 284 | + | ||
| 285 | + except Exception as e: | ||
| 286 | + print(f"ForumEgine: 读取forum.log失败: {e}") | ||
| 287 | + return [] | ||
| 288 | + | ||
| 289 | + | ||
| 290 | +# 全局监控器实例 | ||
| 291 | +_monitor_instance = None | ||
| 292 | + | ||
| 293 | +def get_monitor() -> LogMonitor: | ||
| 294 | + """获取全局监控器实例""" | ||
| 295 | + global _monitor_instance | ||
| 296 | + if _monitor_instance is None: | ||
| 297 | + _monitor_instance = LogMonitor() | ||
| 298 | + return _monitor_instance | ||
| 299 | + | ||
| 300 | +def start_forum_monitoring(): | ||
| 301 | + """启动ForumEgine智能监控""" | ||
| 302 | + return get_monitor().start_monitoring() | ||
| 303 | + | ||
| 304 | +def stop_forum_monitoring(): | ||
| 305 | + """停止ForumEgine监控""" | ||
| 306 | + get_monitor().stop_monitoring() | ||
| 307 | + | ||
| 308 | +def get_forum_log(): | ||
| 309 | + """获取forum.log内容""" | ||
| 310 | + return get_monitor().get_forum_log_content() |
| @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | ||
| 79 | cleaned_output = clean_json_tags(cleaned_output) | 79 | cleaned_output = clean_json_tags(cleaned_output) |
| 80 | 80 | ||
| 81 | # 记录清理后的输出用于调试 | 81 | # 记录清理后的输出用于调试 |
| 82 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 82 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 83 | 83 | ||
| 84 | # 解析JSON | 84 | # 解析JSON |
| 85 | try: | 85 | try: |
| @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | ||
| 93 | cleaned_output = clean_json_tags(cleaned_output) | 93 | cleaned_output = clean_json_tags(cleaned_output) |
| 94 | 94 | ||
| 95 | # 记录清理后的输出用于调试 | 95 | # 记录清理后的输出用于调试 |
| 96 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 96 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 97 | 97 | ||
| 98 | # 解析JSON | 98 | # 解析JSON |
| 99 | try: | 99 | try: |
| @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | ||
| 228 | cleaned_output = clean_json_tags(cleaned_output) | 228 | cleaned_output = clean_json_tags(cleaned_output) |
| 229 | 229 | ||
| 230 | # 记录清理后的输出用于调试 | 230 | # 记录清理后的输出用于调试 |
| 231 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 231 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 232 | 232 | ||
| 233 | # 解析JSON | 233 | # 解析JSON |
| 234 | try: | 234 | try: |
| @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | ||
| 97 | cleaned_output = clean_json_tags(cleaned_output) | 97 | cleaned_output = clean_json_tags(cleaned_output) |
| 98 | 98 | ||
| 99 | # 记录清理后的输出用于调试 | 99 | # 记录清理后的输出用于调试 |
| 100 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 100 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 101 | 101 | ||
| 102 | # 解析JSON | 102 | # 解析JSON |
| 103 | try: | 103 | try: |
| @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | ||
| 243 | cleaned_output = clean_json_tags(cleaned_output) | 243 | cleaned_output = clean_json_tags(cleaned_output) |
| 244 | 244 | ||
| 245 | # 记录清理后的输出用于调试 | 245 | # 记录清理后的输出用于调试 |
| 246 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 246 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 247 | 247 | ||
| 248 | # 解析JSON | 248 | # 解析JSON |
| 249 | try: | 249 | try: |
| @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | ||
| 79 | cleaned_output = clean_json_tags(cleaned_output) | 79 | cleaned_output = clean_json_tags(cleaned_output) |
| 80 | 80 | ||
| 81 | # 记录清理后的输出用于调试 | 81 | # 记录清理后的输出用于调试 |
| 82 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 82 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 83 | 83 | ||
| 84 | # 解析JSON | 84 | # 解析JSON |
| 85 | try: | 85 | try: |
| @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | ||
| 93 | cleaned_output = clean_json_tags(cleaned_output) | 93 | cleaned_output = clean_json_tags(cleaned_output) |
| 94 | 94 | ||
| 95 | # 记录清理后的输出用于调试 | 95 | # 记录清理后的输出用于调试 |
| 96 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 96 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 97 | 97 | ||
| 98 | # 解析JSON | 98 | # 解析JSON |
| 99 | try: | 99 | try: |
| @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | ||
| 228 | cleaned_output = clean_json_tags(cleaned_output) | 228 | cleaned_output = clean_json_tags(cleaned_output) |
| 229 | 229 | ||
| 230 | # 记录清理后的输出用于调试 | 230 | # 记录清理后的输出用于调试 |
| 231 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 231 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 232 | 232 | ||
| 233 | # 解析JSON | 233 | # 解析JSON |
| 234 | try: | 234 | try: |
| @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | ||
| 97 | cleaned_output = clean_json_tags(cleaned_output) | 97 | cleaned_output = clean_json_tags(cleaned_output) |
| 98 | 98 | ||
| 99 | # 记录清理后的输出用于调试 | 99 | # 记录清理后的输出用于调试 |
| 100 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 100 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 101 | 101 | ||
| 102 | # 解析JSON | 102 | # 解析JSON |
| 103 | try: | 103 | try: |
| @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | ||
| 243 | cleaned_output = clean_json_tags(cleaned_output) | 243 | cleaned_output = clean_json_tags(cleaned_output) |
| 244 | 244 | ||
| 245 | # 记录清理后的输出用于调试 | 245 | # 记录清理后的输出用于调试 |
| 246 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 246 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 247 | 247 | ||
| 248 | # 解析JSON | 248 | # 解析JSON |
| 249 | try: | 249 | try: |
| @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | @@ -79,7 +79,7 @@ class ReportStructureNode(StateMutationNode): | ||
| 79 | cleaned_output = clean_json_tags(cleaned_output) | 79 | cleaned_output = clean_json_tags(cleaned_output) |
| 80 | 80 | ||
| 81 | # 记录清理后的输出用于调试 | 81 | # 记录清理后的输出用于调试 |
| 82 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 82 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 83 | 83 | ||
| 84 | # 解析JSON | 84 | # 解析JSON |
| 85 | try: | 85 | try: |
| @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | @@ -93,7 +93,7 @@ class FirstSearchNode(BaseNode): | ||
| 93 | cleaned_output = clean_json_tags(cleaned_output) | 93 | cleaned_output = clean_json_tags(cleaned_output) |
| 94 | 94 | ||
| 95 | # 记录清理后的输出用于调试 | 95 | # 记录清理后的输出用于调试 |
| 96 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 96 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 97 | 97 | ||
| 98 | # 解析JSON | 98 | # 解析JSON |
| 99 | try: | 99 | try: |
| @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | @@ -228,7 +228,7 @@ class ReflectionNode(BaseNode): | ||
| 228 | cleaned_output = clean_json_tags(cleaned_output) | 228 | cleaned_output = clean_json_tags(cleaned_output) |
| 229 | 229 | ||
| 230 | # 记录清理后的输出用于调试 | 230 | # 记录清理后的输出用于调试 |
| 231 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 231 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 232 | 232 | ||
| 233 | # 解析JSON | 233 | # 解析JSON |
| 234 | try: | 234 | try: |
| @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | @@ -97,7 +97,7 @@ class FirstSummaryNode(StateMutationNode): | ||
| 97 | cleaned_output = clean_json_tags(cleaned_output) | 97 | cleaned_output = clean_json_tags(cleaned_output) |
| 98 | 98 | ||
| 99 | # 记录清理后的输出用于调试 | 99 | # 记录清理后的输出用于调试 |
| 100 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 100 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 101 | 101 | ||
| 102 | # 解析JSON | 102 | # 解析JSON |
| 103 | try: | 103 | try: |
| @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | @@ -243,7 +243,7 @@ class ReflectionSummaryNode(StateMutationNode): | ||
| 243 | cleaned_output = clean_json_tags(cleaned_output) | 243 | cleaned_output = clean_json_tags(cleaned_output) |
| 244 | 244 | ||
| 245 | # 记录清理后的输出用于调试 | 245 | # 记录清理后的输出用于调试 |
| 246 | - self.log_info(f"清理后的输出: {cleaned_output[:200]}...") | 246 | + self.log_info(f"清理后的输出: {cleaned_output}") |
| 247 | 247 | ||
| 248 | # 解析JSON | 248 | # 解析JSON |
| 249 | try: | 249 | try: |
| @@ -30,6 +30,39 @@ os.environ['PYTHONUTF8'] = '1' | @@ -30,6 +30,39 @@ os.environ['PYTHONUTF8'] = '1' | ||
| 30 | LOG_DIR = Path('logs') | 30 | LOG_DIR = Path('logs') |
| 31 | LOG_DIR.mkdir(exist_ok=True) | 31 | LOG_DIR.mkdir(exist_ok=True) |
| 32 | 32 | ||
| 33 | +# 初始化ForumEgine的forum.log文件 | ||
| 34 | +def init_forum_log(): | ||
| 35 | + """初始化forum.log文件""" | ||
| 36 | + try: | ||
| 37 | + forum_log_file = LOG_DIR / "forum.log" | ||
| 38 | + if not forum_log_file.exists(): | ||
| 39 | + with open(forum_log_file, 'w', encoding='utf-8') as f: | ||
| 40 | + start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||
| 41 | + f.write(f"=== ForumEgine 系统初始化 - {start_time} ===\n") | ||
| 42 | + print(f"ForumEgine: forum.log 已初始化") | ||
| 43 | + except Exception as e: | ||
| 44 | + print(f"ForumEgine: 初始化forum.log失败: {e}") | ||
| 45 | + | ||
| 46 | +# 初始化forum.log | ||
| 47 | +init_forum_log() | ||
| 48 | + | ||
| 49 | +# 启动ForumEgine智能监控 | ||
| 50 | +def start_forum_engine(): | ||
| 51 | + """启动ForumEgine智能监控""" | ||
| 52 | + try: | ||
| 53 | + from ForumEgine.monitor import start_forum_monitoring | ||
| 54 | + print("ForumEgine: 启动智能监控...") | ||
| 55 | + success = start_forum_monitoring() | ||
| 56 | + if success: | ||
| 57 | + print("ForumEgine: 智能监控已启动,将自动检测搜索活动") | ||
| 58 | + else: | ||
| 59 | + print("ForumEgine: 智能监控启动失败") | ||
| 60 | + except Exception as e: | ||
| 61 | + print(f"ForumEgine: 启动智能监控失败: {e}") | ||
| 62 | + | ||
| 63 | +# 启动ForumEgine | ||
| 64 | +start_forum_engine() | ||
| 65 | + | ||
| 33 | # 全局变量存储进程信息 | 66 | # 全局变量存储进程信息 |
| 34 | processes = { | 67 | processes = { |
| 35 | 'insight': {'process': None, 'port': 8501, 'status': 'stopped', 'output': [], 'log_file': None}, | 68 | 'insight': {'process': None, 'port': 8501, 'status': 'stopped', 'output': [], 'log_file': None}, |
| @@ -382,6 +415,43 @@ def test_log(app_name): | @@ -382,6 +415,43 @@ def test_log(app_name): | ||
| 382 | 'message': f'测试消息已写入 {app_name} 日志' | 415 | 'message': f'测试消息已写入 {app_name} 日志' |
| 383 | }) | 416 | }) |
| 384 | 417 | ||
| 418 | +@app.route('/api/forum/start') | ||
| 419 | +def start_forum_monitoring_api(): | ||
| 420 | + """手动启动ForumEgine监控""" | ||
| 421 | + try: | ||
| 422 | + from ForumEgine.monitor import start_forum_monitoring | ||
| 423 | + success = start_forum_monitoring() | ||
| 424 | + if success: | ||
| 425 | + return jsonify({'success': True, 'message': 'ForumEgine监控已启动'}) | ||
| 426 | + else: | ||
| 427 | + return jsonify({'success': False, 'message': 'ForumEgine监控启动失败'}) | ||
| 428 | + except Exception as e: | ||
| 429 | + return jsonify({'success': False, 'message': f'启动监控失败: {str(e)}'}) | ||
| 430 | + | ||
| 431 | +@app.route('/api/forum/stop') | ||
| 432 | +def stop_forum_monitoring_api(): | ||
| 433 | + """手动停止ForumEgine监控""" | ||
| 434 | + try: | ||
| 435 | + from ForumEgine.monitor import stop_forum_monitoring | ||
| 436 | + stop_forum_monitoring() | ||
| 437 | + return jsonify({'success': True, 'message': 'ForumEgine监控已停止'}) | ||
| 438 | + except Exception as e: | ||
| 439 | + return jsonify({'success': False, 'message': f'停止监控失败: {str(e)}'}) | ||
| 440 | + | ||
| 441 | +@app.route('/api/forum/log') | ||
| 442 | +def get_forum_log(): | ||
| 443 | + """获取ForumEgine的forum.log内容""" | ||
| 444 | + try: | ||
| 445 | + from ForumEgine.monitor import get_forum_log | ||
| 446 | + log_content = get_forum_log() | ||
| 447 | + return jsonify({ | ||
| 448 | + 'success': True, | ||
| 449 | + 'log_lines': log_content, | ||
| 450 | + 'total_lines': len(log_content) | ||
| 451 | + }) | ||
| 452 | + except Exception as e: | ||
| 453 | + return jsonify({'success': False, 'message': f'读取forum.log失败: {str(e)}'}) | ||
| 454 | + | ||
| 385 | @app.route('/api/search', methods=['POST']) | 455 | @app.route('/api/search', methods=['POST']) |
| 386 | def search(): | 456 | def search(): |
| 387 | """统一搜索接口""" | 457 | """统一搜索接口""" |
| @@ -391,6 +461,9 @@ def search(): | @@ -391,6 +461,9 @@ def search(): | ||
| 391 | if not query: | 461 | if not query: |
| 392 | return jsonify({'success': False, 'message': '搜索查询不能为空'}) | 462 | return jsonify({'success': False, 'message': '搜索查询不能为空'}) |
| 393 | 463 | ||
| 464 | + # ForumEgine智能监控已经在后台运行,会自动检测搜索活动 | ||
| 465 | + print("ForumEgine: 搜索请求已收到,智能监控将自动检测日志变化") | ||
| 466 | + | ||
| 394 | # 检查哪些应用正在运行 | 467 | # 检查哪些应用正在运行 |
| 395 | check_app_status() | 468 | check_app_status() |
| 396 | running_apps = [name for name, info in processes.items() if info['status'] == 'running'] | 469 | running_apps = [name for name, info in processes.items() if info['status'] == 'running'] |
| @@ -418,6 +491,9 @@ def search(): | @@ -418,6 +491,9 @@ def search(): | ||
| 418 | except Exception as e: | 491 | except Exception as e: |
| 419 | results[app_name] = {'success': False, 'message': str(e)} | 492 | results[app_name] = {'success': False, 'message': str(e)} |
| 420 | 493 | ||
| 494 | + # 搜索完成后可以选择停止监控,或者让它继续运行以捕获后续的处理日志 | ||
| 495 | + # 这里我们让监控继续运行,用户可以通过其他接口手动停止 | ||
| 496 | + | ||
| 421 | return jsonify({ | 497 | return jsonify({ |
| 422 | 'success': True, | 498 | 'success': True, |
| 423 | 'query': query, | 499 | 'query': query, |
-
Please register or login to post a comment