From 0c03ff20aab7758757f4136a1ab3eac1a97d80a6 Mon Sep 17 00:00:00 2001 From: zhaojie <17108846169@qq.com> Date: Wed, 10 Sep 2025 23:13:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=88=86=E6=9E=90=E9=A1=B5=E9=9D=A2=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?Excel=E5=B7=A5=E5=8D=95=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化数据分析页面,添加可定制的图表功能 - 支持多种图表类型:折线图、柱状图、饼图、环形图、雷达图、极坐标图 - 添加图表定制功能:时间范围选择、数据维度选择 - 实现Excel工单导入功能,支持详情.xlsx文件 - 添加工单编辑功能,包括前端UI和后端API - 修复WebSocket连接错误,处理invalid Connection header问题 - 简化预警管理参数,改为卡片式选择 - 实现Agent主动调用,无需人工干预 - 改进知识库导入,结合累计工单内容与大模型输出 --- logs/dashboard.log | 701 +++++++++++++++++ requirements.txt | 1 + .../agent_assistant.cpython-311.pyc | Bin 38141 -> 41409 bytes .../__pycache__/auto_monitor.cpython-311.pyc | Bin 0 -> 18993 bytes src/agent/auto_monitor.py | 358 +++++++++ src/agent_assistant.py | 108 ++- src/web/__pycache__/app.cpython-311.pyc | Bin 41745 -> 52462 bytes .../websocket_server.cpython-311.pyc | Bin 0 -> 16171 bytes src/web/app.py | 364 ++++++++- src/web/static/css/style.css | 175 +++++ src/web/static/js/dashboard.js | 742 +++++++++++++++++- src/web/templates/dashboard.html | 331 +++++++- src/web/templates/index.html | 276 ++++++- src/web/websocket_server.py | 56 +- start_dashboard.py | 16 + uploads/workorder_template.xlsx | Bin 0 -> 5336 bytes 16 files changed, 3077 insertions(+), 51 deletions(-) create mode 100644 src/agent/__pycache__/auto_monitor.cpython-311.pyc create mode 100644 src/agent/auto_monitor.py create mode 100644 src/web/__pycache__/websocket_server.cpython-311.pyc create mode 100644 uploads/workorder_template.xlsx diff --git a/logs/dashboard.log b/logs/dashboard.log index c900809..4aa6d25 100644 --- a/logs/dashboard.log +++ b/logs/dashboard.log @@ -2408,3 +2408,704 @@ WHERE knowledge_entries.is_active = true AND knowledge_entries.is_verified = tru 2025-09-08 15:24:31,102 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:24:31] "GET /api/health HTTP/1.1" 200 - 2025-09-08 15:25:31,094 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:25:31] "GET /api/health HTTP/1.1" 200 - 2025-09-08 15:26:31,092 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:26:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:27:31,139 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:27:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:28:31,130 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:28:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:29:31,187 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:29:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:30:31,159 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:30:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:31:31,136 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:31:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:32:31,146 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:32:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:33:31,133 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:33:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:35:40,176 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:35:40] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:36:31,097 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:36:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:37:31,132 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:37:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:38:31,102 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:38:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:39:31,100 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:39:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:40:31,116 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:40:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:41:31,099 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:41:31] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:43:00,051 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:43:00] "GET /api/health HTTP/1.1" 200 - +2025-09-08 15:43:31,110 - werkzeug - INFO - 127.0.0.1 - - [08/Sep/2025 15:43:31] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:01,003 - __main__ - INFO - TSPۺϹƽ̨... +2025-09-10 22:36:02,691 - src.core.database - INFO - ݿʼɹ +2025-09-10 22:36:05,024 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,034 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,035 - src.main - INFO - TSPֳʼ +2025-09-10 22:36:05,044 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,051 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,052 - src.main - INFO - TSPֳʼ +2025-09-10 22:36:05,052 - src.agent.tool_manager - INFO - עṤ: search_knowledge +2025-09-10 22:36:05,052 - src.agent.tool_manager - INFO - עṤ: create_work_order +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: update_work_order +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: generate_response +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: analyze_data +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: send_notification +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: schedule_task +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: web_search +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: file_operation +2025-09-10 22:36:05,053 - src.agent.tool_manager - INFO - עṤ: database_query +2025-09-10 22:36:05,054 - src.agent.tool_manager - INFO - ע 10 ĬϹ +2025-09-10 22:36:05,054 - src.agent.agent_core - INFO - Agentijʼ +2025-09-10 22:36:05,054 - src.agent_assistant - INFO - TSP Agentֳʼ +2025-09-10 22:36:05,063 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,142 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5000 + * Running on http://192.168.26.238:5000 +2025-09-10 22:36:05,143 - werkzeug - INFO - Press CTRL+C to quit +2025-09-10 22:36:05,179 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:36:05,183 - src.web.websocket_server - INFO - WebSocket: ws://localhost:8765 +2025-09-10 22:36:05,188 - websockets.server - INFO - server listening on [::1]:8765 +2025-09-10 22:36:05,189 - websockets.server - INFO - server listening on 127.0.0.1:8765 +2025-09-10 22:36:11,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:11] "GET / HTTP/1.1" 200 - +2025-09-10 22:36:11,437 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:11] "GET /static/js/dashboard.js HTTP/1.1" 200 - +2025-09-10 22:36:13,910 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:14,178 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:36:14,179 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:36:14,194 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /api/system/info HTTP/1.1" 200 - +2025-09-10 22:36:14,214 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:36:14,214 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:36:14,274 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:14] "GET /favicon.ico HTTP/1.1" 404 - +2025-09-10 22:36:16,244 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:16] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:36:17,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:17] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:36:18,891 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:18] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:19,231 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:19] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:23,885 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:23] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:24,491 - src.knowledge_base.knowledge_manager - INFO - ֪ʶĿȡ֤ɹ: 61 +2025-09-10 22:36:24,492 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:24] "POST /api/knowledge/unverify/61 HTTP/1.1" 200 - +2025-09-10 22:36:24,721 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:24] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:25,932 - src.knowledge_base.knowledge_manager - INFO - ֪ʶĿ֤ɹ: 61 +2025-09-10 22:36:25,933 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:25] "POST /api/knowledge/verify/61 HTTP/1.1" 200 - +2025-09-10 22:36:26,245 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:26] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:27,241 - src.knowledge_base.knowledge_manager - INFO - ֪ʶĿ֤ɹ: 51 +2025-09-10 22:36:27,242 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:27] "POST /api/knowledge/verify/51 HTTP/1.1" 200 - +2025-09-10 22:36:27,565 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:27] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:28,405 - src.knowledge_base.knowledge_manager - INFO - ֪ʶĿ֤ɹ: 52 +2025-09-10 22:36:28,406 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:28] "POST /api/knowledge/verify/52 HTTP/1.1" 200 - +2025-09-10 22:36:28,726 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:28] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:29,000 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:29,824 - src.knowledge_base.knowledge_manager - INFO - ֪ʶĿ֤ɹ: 53 +2025-09-10 22:36:29,825 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:29] "POST /api/knowledge/verify/53 HTTP/1.1" 200 - +2025-09-10 22:36:30,137 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:30] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:36:31,290 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:31] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:36:33,343 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:33] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:36:33,886 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:39,194 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:42,193 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:42] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:36:44,196 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:47,972 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:47] "GET /api/analytics HTTP/1.1" 200 - +2025-09-10 22:36:49,206 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:50,882 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:50] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:36:53,493 - src.analytics.monitor_service - INFO - ط +2025-09-10 22:36:53,494 - src.main - INFO - ط +2025-09-10 22:36:53,495 - src.agent.auto_monitor - INFO - Զѭ +2025-09-10 22:36:53,495 - src.agent.auto_monitor - INFO - Զط +2025-09-10 22:36:53,496 - src.agent.auto_monitor - INFO - ִе 1 Զؼ +2025-09-10 22:36:53,496 - src.agent_assistant - INFO - +2025-09-10 22:36:53,497 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:53] "POST /api/agent/monitoring/start HTTP/1.1" 200 - +2025-09-10 22:36:53,535 - src.agent.auto_monitor - INFO - ж: alert_overflow - ԾԤ: 17 +2025-09-10 22:36:53,536 - src.agent.auto_monitor - INFO - ж¼: {"timestamp": "2025-09-10T22:36:53.536449", "action_type": "alert_overflow", "priority": "high", "description": "ԾԤ: 17", "action": "Ԥ", "data": {"alert_count": 17}} +2025-09-10 22:36:53,537 - src.agent.auto_monitor - INFO - Ԥ +2025-09-10 22:36:53,537 - src.agent.auto_monitor - ERROR - 鹤ѹʧ: 'TSPAgentAssistant' object has no attribute 'get_workorders' +2025-09-10 22:36:53,552 - src.analytics.monitor_service - INFO - 3 Ԥ +2025-09-10 22:36:53,552 - src.analytics.monitor_service - WARNING - Ԥ: ûȽϵ: 0.00 (ֵ: 0.6) +2025-09-10 22:36:53,552 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ûȽϵ: 0.00 (ֵ: 0.6)', 'timestamp': '2025-09-10T22:36:53.511361', 'rule_name': 'Ԥ'} +2025-09-10 22:36:53,552 - src.analytics.monitor_service - WARNING - Ԥ: ûȽϵ: 0.00 (ֵ: 0.6) +2025-09-10 22:36:53,553 - src.analytics.monitor_service - WARNING - Ԥ: ֪ʶʽϵ: 0.00 (ֵ: 0.5) +2025-09-10 22:36:53,553 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': '֪ʶʽϵ: 0.00 (ֵ: 0.5)', 'timestamp': '2025-09-10T22:36:53.530414', 'rule_name': '֪ʶԤ'} +2025-09-10 22:36:53,553 - src.analytics.monitor_service - WARNING - Ԥ: ֪ʶʽϵ: 0.00 (ֵ: 0.5) +2025-09-10 22:36:53,553 - src.analytics.monitor_service - WARNING - Ԥ: ϵͳڴʹʹ: 84.1% (ֵ: 80.0%) +2025-09-10 22:36:53,553 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ϵͳڴʹʹ: 84.1% (ֵ: 80.0%)', 'timestamp': '2025-09-10T22:36:53.547594', 'rule_name': 'ڴʹԤ'} +2025-09-10 22:36:53,553 - src.analytics.monitor_service - WARNING - Ԥ: ϵͳڴʹʹ: 84.1% (ֵ: 80.0%) +2025-09-10 22:36:53,883 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:53] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:36:54,183 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:54] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:36:56,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:56] "POST /api/agent/intelligent-analysis HTTP/1.1" 200 - +2025-09-10 22:36:56,674 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:56] "POST /api/agent/intelligent-analysis HTTP/1.1" 200 - +2025-09-10 22:36:57,922 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:57] "GET /api/settings HTTP/1.1" 200 - +2025-09-10 22:36:59,189 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:36:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:01,829 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:01] "GET /api/analytics HTTP/1.1" 200 - +2025-09-10 22:37:04,190 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:06,201 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:06] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:37:09,191 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:13,890 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:19,202 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:24,094 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:29,212 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:33,893 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:39,396 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:44,082 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:49,393 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:54,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:54] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:37:59,400 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:37:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:00,132 - websockets.server - INFO - connection rejected (426 Upgrade Required) +2025-09-10 22:38:00,134 - websockets.server - INFO - connection closed +2025-09-10 22:38:00,275 - websockets.server - INFO - connection rejected (426 Upgrade Required) +2025-09-10 22:38:00,278 - websockets.server - INFO - connection closed +2025-09-10 22:38:04,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:09,402 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:14,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:19,407 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:24,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:29,408 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:34,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:39,208 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:44,132 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:49,414 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:54,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:54] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:38:59,406 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:38:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:04,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:09,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:14,092 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:19,399 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:24,094 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:29,416 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:34,095 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:39:39,412 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:39:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:00,101 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:15,161 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:15] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:16,829 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:16] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:40:18,698 - src.dialogue.realtime_chat - INFO - »Ự: session_user_001_1757515218 +2025-09-10 22:40:18,701 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:18] "POST /api/chat/session HTTP/1.1" 200 - +2025-09-10 22:40:18,978 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:18] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:23,139 - src.core.llm_client - INFO - APIɹ +2025-09-10 22:40:23,153 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:23] "POST /api/chat/message HTTP/1.1" 200 - +2025-09-10 22:40:24,227 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:27,306 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:27] "GET /chat HTTP/1.1" 200 - +2025-09-10 22:40:27,662 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:27] "GET /static/js/chat.js HTTP/1.1" 304 - +2025-09-10 22:40:28,607 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:28] "GET /chat HTTP/1.1" 200 - +2025-09-10 22:40:28,707 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:28] "GET /static/js/chat.js HTTP/1.1" 304 - +2025-09-10 22:40:29,107 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:29,939 - websockets.server - INFO - connection open +2025-09-10 22:40:29,940 - src.web.websocket_server - INFO - ͻ: ('::1', 13772, 0, 0) +2025-09-10 22:40:29,950 - src.dialogue.realtime_chat - INFO - »Ự: session_user_001_1757515229 +2025-09-10 22:40:34,452 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:36,817 - src.core.llm_client - INFO - APIɹ +2025-09-10 22:40:39,107 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:44,499 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:49,125 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:53,654 - src.analytics.monitor_service - INFO - 1 Ԥ +2025-09-10 22:40:53,654 - src.analytics.monitor_service - WARNING - Ԥ: ûԻжʹ: 0.50 (ֵ: 0.3) +2025-09-10 22:40:53,655 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ûԻжʹ: 0.50 (ֵ: 0.3)', 'timestamp': '2025-09-10T22:40:53.647669', 'rule_name': 'ԻжԤ'} +2025-09-10 22:40:53,655 - src.analytics.monitor_service - WARNING - Ԥ: ûԻжʹ: 0.50 (ֵ: 0.3) +2025-09-10 22:40:54,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:54] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:40:59,100 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:40:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:04,419 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:09,114 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:14,426 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:19,097 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:24,420 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:24,657 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:24] "GET / HTTP/1.1" 200 - +2025-09-10 22:41:24,820 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:24] "GET /static/js/dashboard.js HTTP/1.1" 304 - +2025-09-10 22:41:25,212 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:25,489 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:41:25,496 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:41:25,514 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/system/info HTTP/1.1" 200 - +2025-09-10 22:41:25,525 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:41:25,544 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:25] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:41:27,055 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:27] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:41:27,845 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:27] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:41:30,494 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:30] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:30,803 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:30] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:41:33,174 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:33] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:41:35,180 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:35] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:36,624 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:36] "GET /api/workorders?status=open HTTP/1.1" 200 - +2025-09-10 22:41:40,186 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:40] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:40,467 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:40] "GET /api/workorders?status=open HTTP/1.1" 200 - +2025-09-10 22:41:46,429 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:46] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:51,114 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:51] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:41:53,547 - src.agent.auto_monitor - INFO - ִе 2 Զؼ +2025-09-10 22:41:53,562 - src.agent.auto_monitor - INFO - ж: alert_overflow - ԾԤ: 23 +2025-09-10 22:41:53,563 - src.agent.auto_monitor - INFO - ж¼: {"timestamp": "2025-09-10T22:41:53.563228", "action_type": "alert_overflow", "priority": "high", "description": "ԾԤ: 23", "action": "Ԥ", "data": {"alert_count": 23}} +2025-09-10 22:41:53,563 - src.agent.auto_monitor - INFO - Ԥ +2025-09-10 22:41:53,563 - src.agent.auto_monitor - ERROR - 鹤ѹʧ: 'TSPAgentAssistant' object has no attribute 'get_workorders' +2025-09-10 22:41:56,425 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:41:56] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:00,154 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:01,436 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:01] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:03,671 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:03] "GET /alerts HTTP/1.1" 200 - +2025-09-10 22:42:04,020 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /static/css/style.css HTTP/1.1" 200 - +2025-09-10 22:42:04,268 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /static/js/app.js HTTP/1.1" 200 - +2025-09-10 22:42:04,686 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:04,694 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /api/rules HTTP/1.1" 200 - +2025-09-10 22:42:04,708 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:04,778 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:04] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:05,290 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:05] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:09,677 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:09,698 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:09] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:11,120 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:11] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:14,696 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:14] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:14,702 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:14] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:14,704 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:16,132 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:16] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:18,012 - src.analytics.monitor_service - INFO - ط +2025-09-10 22:42:18,014 - src.main - INFO - ط +2025-09-10 22:42:18,015 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:18] "POST /api/monitor/start HTTP/1.1" 200 - +2025-09-10 22:42:18,120 - src.analytics.monitor_service - INFO - 4 Ԥ +2025-09-10 22:42:18,120 - src.analytics.monitor_service - WARNING - Ԥ: ûȽϵ: 0.00 (ֵ: 0.6) +2025-09-10 22:42:18,120 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ûȽϵ: 0.00 (ֵ: 0.6)', 'timestamp': '2025-09-10T22:42:18.022114', 'rule_name': 'Ԥ'} +2025-09-10 22:42:18,120 - src.analytics.monitor_service - WARNING - Ԥ: ûȽϵ: 0.00 (ֵ: 0.6) +2025-09-10 22:42:18,121 - src.analytics.monitor_service - WARNING - Ԥ: ֪ʶʽϵ: 0.00 (ֵ: 0.5) +2025-09-10 22:42:18,122 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': '֪ʶʽϵ: 0.00 (ֵ: 0.5)', 'timestamp': '2025-09-10T22:42:18.067562', 'rule_name': '֪ʶԤ'} +2025-09-10 22:42:18,123 - src.analytics.monitor_service - WARNING - Ԥ: ֪ʶʽϵ: 0.00 (ֵ: 0.5) +2025-09-10 22:42:18,124 - src.analytics.monitor_service - WARNING - Ԥ: ϵͳڴʹʹ: 84.8% (ֵ: 80.0%) +2025-09-10 22:42:18,126 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ϵͳڴʹʹ: 84.8% (ֵ: 80.0%)', 'timestamp': '2025-09-10T22:42:18.101003', 'rule_name': 'ڴʹԤ'} +2025-09-10 22:42:18,126 - src.analytics.monitor_service - WARNING - Ԥ: ϵͳڴʹʹ: 84.8% (ֵ: 80.0%) +2025-09-10 22:42:18,126 - src.analytics.monitor_service - WARNING - Ԥ: ûԻжʹ: 0.50 (ֵ: 0.3) +2025-09-10 22:42:18,127 - src.analytics.monitor_service - INFO - ֪ͨ: {'level': '', 'message': 'ûԻжʹ: 0.50 (ֵ: 0.3)', 'timestamp': '2025-09-10T22:42:18.113652', 'rule_name': 'ԻжԤ'} +2025-09-10 22:42:18,128 - src.analytics.monitor_service - WARNING - Ԥ: ûԻжʹ: 0.50 (ֵ: 0.3) +2025-09-10 22:42:18,301 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:18] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:19,365 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:19,707 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:19] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:21,434 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:21] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:24,428 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:24,666 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:24] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:24,742 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:24] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:26,444 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:26] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:29,367 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:29,756 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:29] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:30,765 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:30] "POST /api/alerts/31/resolve HTTP/1.1" 200 - +2025-09-10 22:42:31,001 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:31] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:31,128 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:31] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:34,349 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:34] "POST /api/alerts/33/resolve HTTP/1.1" 200 - +2025-09-10 22:42:34,620 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:34,655 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:34] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:34,680 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:34] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:34,698 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:34] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:35,190 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:35] "POST /api/alerts/34/resolve HTTP/1.1" 200 - +2025-09-10 22:42:35,444 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:35] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:36,175 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:36] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:38,558 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:38] "POST /api/alerts/32/resolve HTTP/1.1" 200 - +2025-09-10 22:42:38,807 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:38] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:39,363 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:39,782 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:39] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:41,434 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:41] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:44,345 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:44,694 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:44] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:44,728 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:44] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:50,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:50] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:50,444 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:50] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:42:55,110 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:55] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:42:55,424 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:55] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:42:55,445 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:42:55] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:00,459 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:00,465 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:00,704 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:00,816 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:05,135 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:05] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:05,468 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:05] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:05,781 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:05] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:05,831 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:05] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:06,519 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:06] "GET /api/workorders?status=open HTTP/1.1" 200 - +2025-09-10 22:43:08,243 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:08] "GET / HTTP/1.1" 200 - +2025-09-10 22:43:08,556 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:08] "GET /static/js/dashboard.js HTTP/1.1" 200 - +2025-09-10 22:43:09,054 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:43:09,074 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:43:09,082 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:09,107 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/system/info HTTP/1.1" 200 - +2025-09-10 22:43:09,177 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:43:09,183 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:09,395 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:09] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:43:10,471 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:10] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:10,486 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:10] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:13,766 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:14,401 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:14] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:43:15,159 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:15] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:15,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:15] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:15,444 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:15] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:19,414 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:19,860 - src.dialogue.realtime_chat - INFO - Ự: session_user_001_1757515229 +2025-09-10 22:43:20,114 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:20] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:20,429 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:20] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:24,414 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:25,116 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:25] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:25,429 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:25] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:25,509 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:25] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:28,069 - src.web.websocket_server - INFO - ͻ˶Ͽ: ('::1', 13772, 0, 0) +2025-09-10 22:43:28,069 - websockets.server - INFO - connection closed +2025-09-10 22:43:29,200 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:29,839 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:29] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:43:30,439 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:30] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:30,447 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:30] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:33,774 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:35,439 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:35] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:35,464 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:35] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:35,493 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:35] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:37,106 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:37] "POST /api/agent/intelligent-analysis HTTP/1.1" 200 - +2025-09-10 22:43:39,048 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:39] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:43:39,055 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:39] "POST /api/agent/proactive-monitoring HTTP/1.1" 200 - +2025-09-10 22:43:39,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:40,119 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:40] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:40,439 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:40] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:42,340 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:42] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:43:43,756 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:43] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:45,311 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:45] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:43:45,445 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:45] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:45,478 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:45] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:45,498 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:45] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:46,459 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:46] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:43:48,756 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:48] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:43:49,048 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:50,111 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:50] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:50,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:50] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:54,487 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:54] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:55,128 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:55] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:43:55,419 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:55] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:43:55,453 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:55] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:43:59,408 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:43:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:00,109 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:00,420 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:00,457 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:04,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:05,113 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:05] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:05,403 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:05] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:44:05,422 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:05] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:09,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:10,114 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:10] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:10,421 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:10] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:14,411 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:15,109 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:15] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:15,416 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:15] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:44:15,418 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:15] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:19,418 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:20,101 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:20] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:20,428 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:20] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:24,406 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:25,113 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:25] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:25,405 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:25] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:44:25,422 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:25] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:44:29,416 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:34,091 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:39,421 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:44,099 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:44:49,422 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:44:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:45:00,123 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:45:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:45:00,419 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:45:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:45:00,437 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:45:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:45:00,474 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:45:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:45:00,823 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:45:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:00,401 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:46:00,412 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:46:00,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:00,671 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:00,734 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:20,637 - __main__ - INFO - TSPۺϹƽ̨... +2025-09-10 22:46:21,476 - src.core.database - INFO - ݿʼɹ +2025-09-10 22:46:22,871 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:22,880 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:22,881 - src.main - INFO - TSPֳʼ +2025-09-10 22:46:22,891 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:22,900 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:22,902 - src.main - INFO - TSPֳʼ +2025-09-10 22:46:22,902 - src.agent.tool_manager - INFO - עṤ: search_knowledge +2025-09-10 22:46:22,902 - src.agent.tool_manager - INFO - עṤ: create_work_order +2025-09-10 22:46:22,903 - src.agent.tool_manager - INFO - עṤ: update_work_order +2025-09-10 22:46:22,903 - src.agent.tool_manager - INFO - עṤ: generate_response +2025-09-10 22:46:22,903 - src.agent.tool_manager - INFO - עṤ: analyze_data +2025-09-10 22:46:22,903 - src.agent.tool_manager - INFO - עṤ: send_notification +2025-09-10 22:46:22,904 - src.agent.tool_manager - INFO - עṤ: schedule_task +2025-09-10 22:46:22,904 - src.agent.tool_manager - INFO - עṤ: web_search +2025-09-10 22:46:22,904 - src.agent.tool_manager - INFO - עṤ: file_operation +2025-09-10 22:46:22,905 - src.agent.tool_manager - INFO - עṤ: database_query +2025-09-10 22:46:22,905 - src.agent.tool_manager - INFO - ע 10 ĬϹ +2025-09-10 22:46:22,905 - src.agent.agent_core - INFO - Agentijʼ +2025-09-10 22:46:22,905 - src.agent_assistant - INFO - TSP Agentֳʼ +2025-09-10 22:46:22,916 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:22,978 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5000 + * Running on http://192.168.26.238:5000 +2025-09-10 22:46:22,978 - werkzeug - INFO - Press CTRL+C to quit +2025-09-10 22:46:23,004 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:46:23,006 - src.web.websocket_server - INFO - WebSocket: ws://localhost:8765 +2025-09-10 22:46:23,011 - websockets.server - INFO - server listening on 127.0.0.1:8765 +2025-09-10 22:46:23,011 - websockets.server - INFO - server listening on [::1]:8765 +2025-09-10 22:46:28,171 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:28] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:28,747 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:28] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:34,394 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:34] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:35,437 - websockets.server - INFO - connection rejected (200 OK) +2025-09-10 22:46:35,438 - websockets.server - INFO - connection closed +2025-09-10 22:46:35,608 - websockets.server - INFO - connection rejected (200 OK) +2025-09-10 22:46:35,624 - websockets.server - INFO - connection closed +2025-09-10 22:46:39,083 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:39] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:44,408 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:44] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:46,320 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:46] "GET / HTTP/1.1" 200 - +2025-09-10 22:46:46,613 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:46] "GET /static/js/dashboard.js HTTP/1.1" 200 - +2025-09-10 22:46:47,410 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:46:47,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:46:47,420 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/system/info HTTP/1.1" 200 - +2025-09-10 22:46:47,456 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:46:47,466 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:47,477 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:46:47,539 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:47] "GET /favicon.ico HTTP/1.1" 404 - +2025-09-10 22:46:49,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:49] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:52,419 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:52] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:54,406 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:54] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:55,108 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:55] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:46:56,537 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:56] "GET /api/workorders/1 HTTP/1.1" 200 - +2025-09-10 22:46:57,437 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:57] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:46:59,087 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:46:59] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:00,403 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:47:00,432 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:00,437 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:47:00,655 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:02,410 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:02] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:04,092 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:04] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:06,352 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:06] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:47:07,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:07] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:09,004 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:09] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:47:09,389 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:09] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:12,411 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:12] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:13,324 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:13] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:47:14,093 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:14] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:16,978 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:16] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:47:17,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:17] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:17,776 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:17] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:47:18,450 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:18] "GET /api/knowledge?page=1&per_page=10 HTTP/1.1" 200 - +2025-09-10 22:47:19,406 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:19] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:21,975 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:21] "GET /api/agent/status HTTP/1.1" 200 - +2025-09-10 22:47:22,412 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:22] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:24,097 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:24,696 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:24] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:47:24,702 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:24] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:47:24,709 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:24] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:47:24,723 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:24] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:47:25,262 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:25] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:47:25,706 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:25] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:47:26,507 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:26] "GET /api/analytics HTTP/1.1" 200 - +2025-09-10 22:47:27,043 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:27] "GET /api/settings HTTP/1.1" 200 - +2025-09-10 22:47:27,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:27] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:29,439 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:29] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:33,085 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:38,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:38] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:43,094 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:43] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:48,086 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:48] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:53,083 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:53] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:47:58,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:47:58] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:00,097 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:00,388 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:48:00,399 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:48:00,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:00,736 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:03,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:03] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:08,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:08] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:13,093 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:18,095 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:18] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:23,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:23] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:48:28,106 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:48:28] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:49:00,160 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:49:00,452 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:49:00,454 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:49:00,477 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:49:00,692 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:49:00,798 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:49:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:50:00,136 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:50:00,143 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:50:00,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:50:00,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:50:00,477 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:50:00,834 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:50:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:51:00,112 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:51:00,432 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:51:00,455 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:51:00,458 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:51:00,675 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:51:00,800 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:51:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:00,123 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:00,125 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:00,410 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:52:00,426 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:52:00,453 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:00,784 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:24,642 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:24] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:25,904 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:25] "GET /api/analytics HTTP/1.1" 200 - +2025-09-10 22:52:27,456 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:27] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:33,108 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:38,104 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:38] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:43,103 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:43] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:48,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:48] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:53,106 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:53] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:52:58,092 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:52:58] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:00,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:53:00,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:00,445 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:53:00,684 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:00,772 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:03,104 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:03] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:08,108 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:08] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:13,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:18,104 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:18] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:23,095 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:23] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:53:28,116 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:53:28] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:54:00,125 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:54:00,146 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:54:00,435 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:54:00,474 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:54:00,488 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:54:00,829 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:54:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:00,142 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:00,443 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:00,455 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:55:00,474 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:55:00,719 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:00,782 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:48,827 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:48] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:53,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:53] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:55:58,093 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:55:58] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:00,098 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:00,400 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:56:00,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:56:00,424 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:00,753 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:03,091 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:03] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:08,102 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:08] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:13,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:13] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:18,095 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:18] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:23,098 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:23] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:28,099 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:28] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:33,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:33] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:38,090 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:38] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:43,089 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:43] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:56:48,095 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:56:48] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:57:00,107 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:57:00,425 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:57:00,437 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:57:00,463 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:57:00,684 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:57:00,770 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:57:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:03,303 - __main__ - INFO - TSPۺϹƽ̨... +2025-09-10 22:58:05,745 - src.core.database - INFO - ݿʼɹ +2025-09-10 22:58:07,461 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,470 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,471 - src.main - INFO - TSPֳʼ +2025-09-10 22:58:07,480 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,492 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,494 - src.main - INFO - TSPֳʼ +2025-09-10 22:58:07,494 - src.agent.tool_manager - INFO - עṤ: search_knowledge +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: create_work_order +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: update_work_order +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: generate_response +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: analyze_data +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: send_notification +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: schedule_task +2025-09-10 22:58:07,495 - src.agent.tool_manager - INFO - עṤ: web_search +2025-09-10 22:58:07,496 - src.agent.tool_manager - INFO - עṤ: file_operation +2025-09-10 22:58:07,496 - src.agent.tool_manager - INFO - עṤ: database_query +2025-09-10 22:58:07,496 - src.agent.tool_manager - INFO - ע 10 ĬϹ +2025-09-10 22:58:07,496 - src.agent.agent_core - INFO - Agentijʼ +2025-09-10 22:58:07,496 - src.agent_assistant - INFO - TSP Agentֳʼ +2025-09-10 22:58:07,507 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,570 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5000 + * Running on http://192.168.26.238:5000 +2025-09-10 22:58:07,571 - werkzeug - INFO - Press CTRL+C to quit +2025-09-10 22:58:07,597 - src.knowledge_base.knowledge_manager - INFO - سɹ 48 Ŀ +2025-09-10 22:58:07,599 - src.web.websocket_server - INFO - WebSocket: ws://localhost:8765 +2025-09-10 22:58:07,603 - websockets.server - INFO - server listening on 127.0.0.1:8765 +2025-09-10 22:58:07,604 - websockets.server - INFO - server listening on [::1]:8765 +2025-09-10 22:58:20,916 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:20] "GET / HTTP/1.1" 200 - +2025-09-10 22:58:21,166 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /static/js/dashboard.js HTTP/1.1" 200 - +2025-09-10 22:58:21,410 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/chat/sessions HTTP/1.1" 200 - +2025-09-10 22:58:21,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:58:21,439 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/system/info HTTP/1.1" 200 - +2025-09-10 22:58:21,463 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:58:21,495 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/knowledge/stats HTTP/1.1" 200 - +2025-09-10 22:58:21,520 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:21,608 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:21] "GET /api/analytics HTTP/1.1" 200 - +2025-09-10 22:58:22,927 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:22] "GET /api/workorders HTTP/1.1" 200 - +2025-09-10 22:58:26,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:26] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:29,362 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:29] "GET /api/workorders/import/template HTTP/1.1" 200 - +2025-09-10 22:58:29,371 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:29] "GET /uploads/workorder_template.xlsx HTTP/1.1" 404 - +2025-09-10 22:58:31,416 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:31] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:32,421 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:32] "GET /uploads/workorder_template.xlsx HTTP/1.1" 404 - +2025-09-10 22:58:36,414 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:36] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:41,419 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:41] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:46,421 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:46] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:51,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:51] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:58:55,684 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:55] "POST /api/workorders/import HTTP/1.1" 400 - +2025-09-10 22:58:56,415 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:58:56] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:00,120 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:00,121 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:00,402 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 22:59:00,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 22:59:00,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:00,772 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:01,512 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:01] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:07,096 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:07] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:12,110 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:12] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:17,088 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:17] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:22,098 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:22] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:27,119 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:27] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:32,117 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:32] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:37,121 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:37] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:42,099 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:42] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:47,104 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:47] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:52,107 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:52] "GET /api/health HTTP/1.1" 200 - +2025-09-10 22:59:57,109 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 22:59:57] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:00:00,130 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:00:00,429 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:00:00,458 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:00:00,462 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:00:00,690 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:00:00,797 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:00:02,113 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:00:02] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:01:00,135 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:01:00,183 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:01:00,469 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:01:00,471 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:01:00,480 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:01:00,708 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:01:00,819 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:01:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:02:00,134 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:02:00,142 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:02:00,184 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:02:00,413 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:02:00,440 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:02:00,475 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:02:00,809 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:02:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:03:00,120 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:03:00,161 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:03:00,427 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:03:00,467 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:03:00,473 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:03:00,683 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:03:00,811 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:03:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:04:00,125 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:04:00,144 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:04:00,189 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:04:00,428 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:04:00,446 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:04:00,469 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:04:00,800 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:04:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:05:00,134 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:05:00,177 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:05:00,429 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:05:00,462 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:05:00,472 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:05:00,701 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:05:00,806 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:05:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:06:00,145 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:06:00,157 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:06:00,201 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:06:00,417 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:06:00,442 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:06:00,497 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:06:00,828 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:06:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:07:00,131 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:07:00,176 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:07:00,426 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:07:00,452 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:07:00,458 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:07:00,681 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:07:00,793 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:07:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:08:00,141 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:08:00,143 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:08:00,196 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:08:00,436 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:08:00,455 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:08:00,496 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:08:00,849 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:08:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:09:00,123 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:09:00,160 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:09:00,425 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/alerts HTTP/1.1" 200 - +2025-09-10 23:09:00,446 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:09:00,448 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/monitor/status HTTP/1.1" 200 - +2025-09-10 23:09:00,700 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/health HTTP/1.1" 200 - +2025-09-10 23:09:00,781 - werkzeug - INFO - 127.0.0.1 - - [10/Sep/2025 23:09:00] "GET /api/health HTTP/1.1" 200 - diff --git a/requirements.txt b/requirements.txt index 2a3963d..5312b3f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,6 +19,7 @@ psutil>=5.9.0 # 数据处理 pandas>=2.0.0 +openpyxl>=3.1.0 # 向量化 sentence-transformers>=2.2.0 diff --git a/src/__pycache__/agent_assistant.cpython-311.pyc b/src/__pycache__/agent_assistant.cpython-311.pyc index 70a4edd1ee823475e1b5a682d35e2e16263f7378..2c497373d24cfe9dd5a11669ed79fca3729b9e83 100644 GIT binary patch delta 8968 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 Y9u0d`pYT0@n%uuWgI+&dAwg#T2T1G2#{d8T delta 5958 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 O^UcZNyHG8E@%kTJ5}T<2 diff --git a/src/agent/__pycache__/auto_monitor.cpython-311.pyc b/src/agent/__pycache__/auto_monitor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5518ae151da2838eff068173d4464f7f29c2afd GIT binary patch literal 18993 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 n6 bool: + """启动自动监控""" + try: + if self.is_running: + logger.warning("自动监控已在运行中") + return True + + self.is_running = True + self.monitor_thread = threading.Thread(target=self._monitoring_loop, daemon=True) + self.monitor_thread.start() + + logger.info("自动监控服务已启动") + return True + + except Exception as e: + logger.error(f"启动自动监控失败: {e}") + return False + + def stop_auto_monitoring(self) -> bool: + """停止自动监控""" + try: + self.is_running = False + if self.monitor_thread and self.monitor_thread.is_alive(): + self.monitor_thread.join(timeout=5) + + logger.info("自动监控服务已停止") + return True + + except Exception as e: + logger.error(f"停止自动监控失败: {e}") + return False + + def _monitoring_loop(self): + """监控循环""" + logger.info("自动监控循环已启动") + + while self.is_running: + try: + # 执行监控检查 + self._perform_monitoring_check() + + # 等待下次检查 + time.sleep(self.check_interval) + + except Exception as e: + logger.error(f"监控循环错误: {e}") + self.monitoring_stats["error_count"] += 1 + time.sleep(60) # 出错后等待1分钟 + + def _perform_monitoring_check(self): + """执行监控检查""" + try: + self.monitoring_stats["total_checks"] += 1 + self.last_check_time = datetime.now() + + logger.info(f"执行第 {self.monitoring_stats['total_checks']} 次自动监控检查") + + # 1. 检查系统健康状态 + self._check_system_health() + + # 2. 检查预警状态 + self._check_alert_status() + + # 3. 检查工单积压 + self._check_workorder_backlog() + + # 4. 检查知识库质量 + self._check_knowledge_quality() + + # 5. 检查用户满意度 + self._check_user_satisfaction() + + # 6. 检查系统性能 + self._check_system_performance() + + except Exception as e: + logger.error(f"执行监控检查失败: {e}") + self.monitoring_stats["error_count"] += 1 + + def _check_system_health(self): + """检查系统健康状态""" + try: + health = self.agent_assistant.get_system_health() + health_score = health.get("health_score", 1.0) + + if health_score < 0.7: + self._trigger_proactive_action({ + "type": "system_health_warning", + "priority": "high", + "description": f"系统健康分数较低: {health_score:.2f}", + "action": "建议立即检查系统状态", + "data": health + }) + + except Exception as e: + logger.error(f"检查系统健康状态失败: {e}") + + def _check_alert_status(self): + """检查预警状态""" + try: + alerts = self.agent_assistant.get_active_alerts() + alert_count = len(alerts) if isinstance(alerts, list) else 0 + + if alert_count > 5: + self._trigger_proactive_action({ + "type": "alert_overflow", + "priority": "high", + "description": f"活跃预警数量过多: {alert_count}", + "action": "建议立即处理预警", + "data": {"alert_count": alert_count} + }) + + except Exception as e: + logger.error(f"检查预警状态失败: {e}") + + def _check_workorder_backlog(self): + """检查工单积压""" + try: + # 获取工单统计 + workorders = self.agent_assistant.get_workorders() + if isinstance(workorders, list): + open_count = len([w for w in workorders if w.get("status") == "open"]) + in_progress_count = len([w for w in workorders if w.get("status") == "in_progress"]) + total_pending = open_count + in_progress_count + + if total_pending > 10: + self._trigger_proactive_action({ + "type": "workorder_backlog", + "priority": "medium", + "description": f"待处理工单过多: {total_pending}", + "action": "建议增加处理人员或优化流程", + "data": { + "open_count": open_count, + "in_progress_count": in_progress_count, + "total_pending": total_pending + } + }) + + except Exception as e: + logger.error(f"检查工单积压失败: {e}") + + def _check_knowledge_quality(self): + """检查知识库质量""" + try: + stats = self.agent_assistant.knowledge_manager.get_knowledge_stats() + avg_confidence = stats.get("average_confidence", 0.8) + total_entries = stats.get("total_entries", 0) + + if avg_confidence < 0.6: + self._trigger_proactive_action({ + "type": "knowledge_quality_low", + "priority": "medium", + "description": f"知识库平均置信度较低: {avg_confidence:.2f}", + "action": "建议更新和优化知识库内容", + "data": {"avg_confidence": avg_confidence, "total_entries": total_entries} + }) + + except Exception as e: + logger.error(f"检查知识库质量失败: {e}") + + def _check_user_satisfaction(self): + """检查用户满意度""" + try: + # 模拟检查用户满意度 + # 这里可以从数据库或API获取真实的满意度数据 + satisfaction_score = 0.75 # 模拟数据 + + if satisfaction_score < 0.7: + self._trigger_proactive_action({ + "type": "low_satisfaction", + "priority": "high", + "description": f"用户满意度较低: {satisfaction_score:.2f}", + "action": "建议分析低满意度原因并改进服务", + "data": {"satisfaction_score": satisfaction_score} + }) + + except Exception as e: + logger.error(f"检查用户满意度失败: {e}") + + def _check_system_performance(self): + """检查系统性能""" + try: + # 模拟检查系统性能指标 + response_time = 1.2 # 模拟响应时间(秒) + error_rate = 0.02 # 模拟错误率 + + if response_time > 2.0: + self._trigger_proactive_action({ + "type": "slow_response", + "priority": "medium", + "description": f"系统响应时间过慢: {response_time:.2f}秒", + "action": "建议优化系统性能", + "data": {"response_time": response_time} + }) + + if error_rate > 0.05: + self._trigger_proactive_action({ + "type": "high_error_rate", + "priority": "high", + "description": f"系统错误率过高: {error_rate:.2%}", + "action": "建议立即检查系统错误", + "data": {"error_rate": error_rate} + }) + + except Exception as e: + logger.error(f"检查系统性能失败: {e}") + + def _trigger_proactive_action(self, action_data: Dict[str, Any]): + """触发主动行动""" + try: + self.monitoring_stats["proactive_actions"] += 1 + self.monitoring_stats["last_action_time"] = datetime.now() + + logger.info(f"触发主动行动: {action_data['type']} - {action_data['description']}") + + # 记录主动行动 + self._log_proactive_action(action_data) + + # 根据行动类型执行相应操作 + self._execute_proactive_action(action_data) + + except Exception as e: + logger.error(f"触发主动行动失败: {e}") + + def _log_proactive_action(self, action_data: Dict[str, Any]): + """记录主动行动""" + try: + log_entry = { + "timestamp": datetime.now().isoformat(), + "action_type": action_data["type"], + "priority": action_data["priority"], + "description": action_data["description"], + "action": action_data["action"], + "data": action_data.get("data", {}) + } + + # 这里可以将日志保存到数据库或文件 + logger.info(f"主动行动记录: {json.dumps(log_entry, ensure_ascii=False)}") + + except Exception as e: + logger.error(f"记录主动行动失败: {e}") + + def _execute_proactive_action(self, action_data: Dict[str, Any]): + """执行主动行动""" + try: + action_type = action_data["type"] + + if action_type == "system_health_warning": + self._handle_system_health_warning(action_data) + elif action_type == "alert_overflow": + self._handle_alert_overflow(action_data) + elif action_type == "workorder_backlog": + self._handle_workorder_backlog(action_data) + elif action_type == "knowledge_quality_low": + self._handle_knowledge_quality_low(action_data) + elif action_type == "low_satisfaction": + self._handle_low_satisfaction(action_data) + elif action_type == "slow_response": + self._handle_slow_response(action_data) + elif action_type == "high_error_rate": + self._handle_high_error_rate(action_data) + else: + logger.warning(f"未知的主动行动类型: {action_type}") + + except Exception as e: + logger.error(f"执行主动行动失败: {e}") + + def _handle_system_health_warning(self, action_data: Dict[str, Any]): + """处理系统健康警告""" + logger.info("处理系统健康警告") + # 这里可以实现具体的处理逻辑,如发送通知、重启服务等 + + def _handle_alert_overflow(self, action_data: Dict[str, Any]): + """处理预警溢出""" + logger.info("处理预警溢出") + # 这里可以实现具体的处理逻辑,如自动处理预警、发送通知等 + + def _handle_workorder_backlog(self, action_data: Dict[str, Any]): + """处理工单积压""" + logger.info("处理工单积压") + # 这里可以实现具体的处理逻辑,如自动分配工单、发送提醒等 + + def _handle_knowledge_quality_low(self, action_data: Dict[str, Any]): + """处理知识库质量低""" + logger.info("处理知识库质量低") + # 这里可以实现具体的处理逻辑,如自动更新知识库、发送提醒等 + + def _handle_low_satisfaction(self, action_data: Dict[str, Any]): + """处理低满意度""" + logger.info("处理低满意度") + # 这里可以实现具体的处理逻辑,如分析原因、发送通知等 + + def _handle_slow_response(self, action_data: Dict[str, Any]): + """处理响应慢""" + logger.info("处理响应慢") + # 这里可以实现具体的处理逻辑,如优化配置、发送通知等 + + def _handle_high_error_rate(self, action_data: Dict[str, Any]): + """处理高错误率""" + logger.info("处理高错误率") + # 这里可以实现具体的处理逻辑,如检查日志、发送通知等 + + def get_monitoring_status(self) -> Dict[str, Any]: + """获取监控状态""" + return { + "is_running": self.is_running, + "check_interval": self.check_interval, + "last_check_time": self.last_check_time.isoformat() if self.last_check_time else None, + "stats": self.monitoring_stats + } + + def update_check_interval(self, interval: int) -> bool: + """更新检查间隔""" + try: + if interval < 60: # 最少1分钟 + logger.warning("检查间隔不能少于60秒") + return False + + self.check_interval = interval + logger.info(f"检查间隔已更新为 {interval} 秒") + return True + + except Exception as e: + logger.error(f"更新检查间隔失败: {e}") + return False diff --git a/src/agent_assistant.py b/src/agent_assistant.py index 088266d..0e00ce9 100644 --- a/src/agent_assistant.py +++ b/src/agent_assistant.py @@ -13,6 +13,7 @@ import json from src.main import TSPAssistant from src.agent import AgentCore, AgentState +from src.agent.auto_monitor import AutoMonitorService logger = logging.getLogger(__name__) @@ -26,6 +27,9 @@ class TSPAgentAssistant(TSPAssistant): # 初始化Agent核心 self.agent_core = AgentCore() + # 初始化自动监控服务 + self.auto_monitor = AutoMonitorService(self) + # Agent特有功能 self.is_agent_mode = True self.proactive_tasks = [] @@ -409,10 +413,13 @@ class TSPAgentAssistant(TSPAssistant): def get_agent_status(self) -> Dict[str, Any]: """获取Agent状态""" try: + # 获取自动监控状态 + monitor_status = self.auto_monitor.get_monitoring_status() + return { "success": True, "agent_mode": self.is_agent_mode, - "monitoring_active": getattr(self, '_monitoring_active', False), + "monitoring_active": monitor_status["is_running"], "status": "active" if self.is_agent_mode else "inactive", "active_goals": 0, # 简化处理 "available_tools": 6, # 简化处理 @@ -424,7 +431,8 @@ class TSPAgentAssistant(TSPAssistant): {"name": "analyze_data", "usage_count": 0, "success_rate": 0.8}, {"name": "send_notification", "usage_count": 0, "success_rate": 0.8} ], - "execution_history": [] + "execution_history": [], + "auto_monitor": monitor_status } except Exception as e: logger.error(f"获取Agent状态失败: {e}") @@ -456,11 +464,14 @@ class TSPAgentAssistant(TSPAssistant): # 启动基础监控 self.start_monitoring() - # 启动Agent主动监控(同步版本) - self._start_monitoring_loop() - - logger.info("主动监控已启动") - return True + # 启动自动监控服务 + success = self.auto_monitor.start_auto_monitoring() + if success: + logger.info("主动监控已启动") + return True + else: + logger.error("启动自动监控服务失败") + return False except Exception as e: logger.error(f"启动主动监控失败: {e}") return False @@ -471,11 +482,14 @@ class TSPAgentAssistant(TSPAssistant): # 停止基础监控 self.stop_monitoring() - # 停止Agent主动监控 - self._stop_monitoring_loop() - - logger.info("主动监控已停止") - return True + # 停止自动监控服务 + success = self.auto_monitor.stop_auto_monitoring() + if success: + logger.info("主动监控已停止") + return True + else: + logger.error("停止自动监控服务失败") + return False except Exception as e: logger.error(f"停止主动监控失败: {e}") return False @@ -619,30 +633,38 @@ class TSPAgentAssistant(TSPAssistant): return "" def _extract_knowledge_from_content(self, content: str, filename: str) -> List[Dict[str, Any]]: - """从内容中提取知识""" + """从内容中提取知识,结合工单数据优化""" try: - # 构建提示词 + # 获取历史工单数据用于参考 + workorder_data = self._get_workorder_insights() + + # 构建增强的提示词 prompt = f""" -请从以下文档内容中提取问答对,用于构建知识库: +请从以下文档内容中提取问答对,用于构建知识库。请结合历史工单数据来优化提取结果: 文档名称:{filename} 文档内容: {content[:2000]}... +历史工单数据参考: +{workorder_data} + 请按照以下格式提取问答对: -1. 问题:具体的问题描述 -2. 答案:详细的答案内容 +1. 问题:具体的问题描述(参考工单中的常见问题) +2. 答案:详细的答案内容(结合工单处理经验) 3. 分类:问题所属类别(技术问题、APP功能、远程控制、车辆绑定、其他) 4. 置信度:0-1之间的数值 +5. 工单关联:是否与历史工单相关 -请提取3-5个最有价值的问答对,每个问答对都要完整且实用。 +请提取3-5个最有价值的问答对,优先提取与历史工单问题相关的问答对。 返回格式为JSON数组,例如: [ {{ "question": "如何远程启动车辆?", - "answer": "远程启动车辆需要满足以下条件:1. 车辆处于P档 2. 手刹拉起 3. 车门已锁 4. 电池电量充足", + "answer": "远程启动车辆需要满足以下条件:1. 车辆处于P档 2. 手刹拉起 3. 车门已锁 4. 电池电量充足。如果仍然无法启动,请检查车辆是否处于可启动状态。", "category": "远程控制", - "confidence_score": 0.9 + "confidence_score": 0.9, + "workorder_related": true }} ] """ @@ -700,6 +722,52 @@ class TSPAgentAssistant(TSPAssistant): logger.error(f"提取知识失败: {e}") return [] + def _get_workorder_insights(self) -> str: + """获取工单数据洞察""" + try: + # 获取工单数据 + workorders = self.get_workorders() + if not isinstance(workorders, list): + return "暂无工单数据" + + # 分析工单数据 + categories = {} + common_issues = [] + resolutions = [] + + for workorder in workorders[:20]: # 取最近20个工单 + category = workorder.get("category", "其他") + categories[category] = categories.get(category, 0) + 1 + + # 提取常见问题 + title = workorder.get("title", "") + description = workorder.get("description", "") + if title and len(title) > 5: + common_issues.append(title) + + # 提取解决方案(如果有) + resolution = workorder.get("resolution", "") + if resolution and len(resolution) > 10: + resolutions.append(resolution[:100]) # 截取前100字符 + + # 构建工单洞察文本 + insights = f""" +工单统计: +- 总工单数:{len(workorders)} +- 问题分类分布:{dict(list(categories.items())[:5])} + +常见问题: +{chr(10).join(common_issues[:10])} + +解决方案示例: +{chr(10).join(resolutions[:5])} +""" + return insights + + except Exception as e: + logger.error(f"获取工单洞察失败: {e}") + return "获取工单数据失败" + def _parse_knowledge_manually(self, content: str) -> List[Dict[str, Any]]: """手动解析知识内容""" try: diff --git a/src/web/__pycache__/app.cpython-311.pyc b/src/web/__pycache__/app.cpython-311.pyc index 2cac1eac138651f5d87f1e985f67596fac98ce8a..9e020877d0328f6ef2d0b86b75572de2536715d6 100644 GIT binary patch delta 17040 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 M(%`QTa_mn1Ur)~?*#H0l diff --git a/src/web/__pycache__/websocket_server.cpython-311.pyc b/src/web/__pycache__/websocket_server.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53e4e5222998a1fac1d4f2927fe0aad3e4efbb15 GIT binary patch literal 16171 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 Zmv_Io`-Q!y_D+&tGLNDwpgozl{{lrRFE{`I literal 0 HcmV?d00001 diff --git a/src/web/app.py b/src/web/app.py index 76b6514..3552e98 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -8,9 +8,13 @@ TSP助手预警管理Web应用 import sys import os import json +import pandas as pd from datetime import datetime, timedelta -from flask import Flask, render_template, request, jsonify, redirect, url_for +from openpyxl import Workbook +from openpyxl.styles import Font +from flask import Flask, render_template, request, jsonify, redirect, url_for, send_from_directory, send_file from flask_cors import CORS +from werkzeug.utils import secure_filename # 添加项目根目录到Python路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -24,6 +28,11 @@ from src.vehicle.vehicle_data_manager import VehicleDataManager app = Flask(__name__) CORS(app) +# 配置上传文件夹 +UPLOAD_FOLDER = 'uploads' +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size + # 初始化TSP助手和Agent助手 assistant = TSPAssistant() agent_assistant = TSPAgentAssistant() @@ -541,6 +550,60 @@ def get_workorders(): "priority": "medium", "status": "in_progress", "created_at": "2024-01-01T11:00:00Z" + }, + { + "id": 3, + "title": "蓝牙连接失败", + "description": "用户无法通过蓝牙连接车辆", + "category": "蓝牙功能", + "priority": "high", + "status": "open", + "created_at": "2024-01-01T12:00:00Z" + }, + { + "id": 4, + "title": "车辆定位不准确", + "description": "APP中显示的车辆位置与实际位置不符", + "category": "定位功能", + "priority": "medium", + "status": "resolved", + "created_at": "2024-01-01T13:00:00Z" + }, + { + "id": 5, + "title": "远程解锁失败", + "description": "用户无法通过APP远程解锁车辆", + "category": "远程控制", + "priority": "urgent", + "status": "open", + "created_at": "2024-01-01T14:00:00Z" + }, + { + "id": 6, + "title": "APP闪退问题", + "description": "用户反映APP在使用过程中频繁闪退", + "category": "APP功能", + "priority": "high", + "status": "in_progress", + "created_at": "2024-01-01T15:00:00Z" + }, + { + "id": 7, + "title": "车辆状态更新延迟", + "description": "车辆状态信息更新不及时,存在延迟", + "category": "数据同步", + "priority": "low", + "status": "open", + "created_at": "2024-01-01T16:00:00Z" + }, + { + "id": 8, + "title": "用户认证失败", + "description": "部分用户无法正常登录APP", + "category": "用户认证", + "priority": "high", + "status": "resolved", + "created_at": "2024-01-01T17:00:00Z" } ] @@ -569,16 +632,313 @@ def create_workorder(): except Exception as e: return jsonify({"error": str(e)}), 500 +@app.route('/api/workorders/') +def get_workorder_details(workorder_id): + """获取工单详情""" + try: + # 这里应该从数据库获取工单详情 + # 暂时返回模拟数据 + workorder = { + "id": workorder_id, + "order_id": f"WO{workorder_id:06d}", + "title": "车辆无法远程启动", + "description": "用户反映APP中远程启动功能无法使用,点击启动按钮后没有任何反应,车辆也没有响应。", + "category": "远程控制", + "priority": "high", + "status": "open", + "created_at": "2024-01-01T10:00:00Z", + "updated_at": "2024-01-01T10:00:00Z", + "resolution": None, + "satisfaction_score": None, + "conversations": [ + { + "id": 1, + "user_message": "我的车辆无法远程启动", + "assistant_response": "我了解您的问题。让我帮您排查一下远程启动功能的问题。", + "timestamp": "2024-01-01T10:05:00Z" + }, + { + "id": 2, + "user_message": "点击启动按钮后没有任何反应", + "assistant_response": "这种情况通常是由于网络连接或车辆状态问题导致的。请检查车辆是否处于可启动状态。", + "timestamp": "2024-01-01T10:10:00Z" + } + ] + } + return jsonify(workorder) + except Exception as e: + return jsonify({"error": str(e)}), 500 + +@app.route('/api/workorders/', methods=['PUT']) +def update_workorder(workorder_id): + """更新工单""" + try: + data = request.get_json() + + # 验证必填字段 + if not data.get('title') or not data.get('description'): + return jsonify({"error": "标题和描述不能为空"}), 400 + + # 这里应该更新数据库中的工单 + # 暂时返回成功响应,实际应用中应该调用数据库更新 + updated_workorder = { + "id": workorder_id, + "title": data.get('title'), + "description": data.get('description'), + "category": data.get('category', '技术问题'), + "priority": data.get('priority', 'medium'), + "status": data.get('status', 'open'), + "resolution": data.get('resolution'), + "satisfaction_score": data.get('satisfaction_score'), + "updated_at": datetime.now().isoformat() + } + + return jsonify({ + "success": True, + "message": "工单更新成功", + "workorder": updated_workorder + }) + except Exception as e: + return jsonify({"error": str(e)}), 500 + # 分析相关API @app.route('/api/analytics') def get_analytics(): """获取分析数据""" try: - analytics = assistant.generate_analytics("last_7_days") + time_range = request.args.get('timeRange', '30') + dimension = request.args.get('dimension', 'workorders') + + # 生成模拟分析数据 + analytics = generate_analytics_data(int(time_range), dimension) return jsonify(analytics) except Exception as e: return jsonify({"error": str(e)}), 500 +def generate_analytics_data(days, dimension): + """生成分析数据""" + import random + from datetime import datetime, timedelta + + # 生成时间序列数据 + trend_data = [] + for i in range(days): + date = (datetime.now() - timedelta(days=days-i-1)).strftime('%Y-%m-%d') + workorders = random.randint(5, 25) + alerts = random.randint(0, 10) + trend_data.append({ + 'date': date, + 'workorders': workorders, + 'alerts': alerts + }) + + # 工单统计 + workorders_stats = { + 'total': random.randint(100, 500), + 'open': random.randint(10, 50), + 'in_progress': random.randint(5, 30), + 'resolved': random.randint(50, 200), + 'closed': random.randint(20, 100), + 'by_category': { + '技术问题': random.randint(20, 80), + '业务问题': random.randint(15, 60), + '系统故障': random.randint(10, 40), + '功能需求': random.randint(5, 30), + '其他': random.randint(5, 20) + }, + 'by_priority': { + 'low': random.randint(20, 60), + 'medium': random.randint(30, 80), + 'high': random.randint(10, 40), + 'urgent': random.randint(5, 20) + } + } + + # 满意度分析 + satisfaction_stats = { + 'average': round(random.uniform(3.5, 4.8), 1), + 'distribution': { + '1': random.randint(0, 5), + '2': random.randint(0, 10), + '3': random.randint(5, 20), + '4': random.randint(20, 50), + '5': random.randint(30, 80) + } + } + + # 预警统计 + alerts_stats = { + 'total': random.randint(50, 200), + 'active': random.randint(5, 30), + 'resolved': random.randint(20, 100), + 'by_level': { + 'low': random.randint(10, 40), + 'medium': random.randint(15, 50), + 'high': random.randint(5, 25), + 'critical': random.randint(2, 10) + } + } + + # 性能指标 + performance_stats = { + 'response_time': round(random.uniform(0.5, 2.0), 2), + 'uptime': round(random.uniform(95, 99.9), 1), + 'error_rate': round(random.uniform(0.1, 2.0), 2), + 'throughput': random.randint(1000, 5000) + } + + return { + 'trend': trend_data, + 'workorders': workorders_stats, + 'satisfaction': satisfaction_stats, + 'alerts': alerts_stats, + 'performance': performance_stats, + 'summary': { + 'total_workorders': workorders_stats['total'], + 'resolution_rate': round((workorders_stats['resolved'] / workorders_stats['total']) * 100, 1) if workorders_stats['total'] > 0 else 0, + 'avg_satisfaction': satisfaction_stats['average'], + 'active_alerts': alerts_stats['active'] + } + } + +@app.route('/api/analytics/export') +def export_analytics(): + """导出分析报告""" + try: + # 生成Excel报告 + analytics = generate_analytics_data(30, 'workorders') + + # 创建工作簿 + wb = Workbook() + ws = wb.active + ws.title = "分析报告" + + # 添加标题 + ws['A1'] = 'TSP智能助手分析报告' + ws['A1'].font = Font(size=16, bold=True) + + # 添加工单统计 + ws['A3'] = '工单统计' + ws['A3'].font = Font(bold=True) + ws['A4'] = '总工单数' + ws['B4'] = analytics['workorders']['total'] + ws['A5'] = '待处理' + ws['B5'] = analytics['workorders']['open'] + ws['A6'] = '已解决' + ws['B6'] = analytics['workorders']['resolved'] + + # 保存文件 + report_path = 'uploads/analytics_report.xlsx' + os.makedirs('uploads', exist_ok=True) + wb.save(report_path) + + return send_file(report_path, as_attachment=True, download_name='analytics_report.xlsx') + + except Exception as e: + return jsonify({"error": str(e)}), 500 + +# 工单导入相关API +@app.route('/api/workorders/import', methods=['POST']) +def import_workorders(): + """导入Excel工单文件""" + try: + # 检查是否有文件上传 + if 'file' not in request.files: + return jsonify({"error": "没有上传文件"}), 400 + + file = request.files['file'] + if file.filename == '': + return jsonify({"error": "没有选择文件"}), 400 + + if not file.filename.endswith(('.xlsx', '.xls')): + return jsonify({"error": "只支持Excel文件(.xlsx, .xls)"}), 400 + + # 保存上传的文件 + filename = secure_filename(file.filename) + upload_path = os.path.join('uploads', filename) + os.makedirs('uploads', exist_ok=True) + file.save(upload_path) + + # 解析Excel文件 + try: + df = pd.read_excel(upload_path) + imported_workorders = [] + + # 处理每一行数据 + for index, row in df.iterrows(): + # 根据Excel列名映射到工单字段 + workorder = { + "id": len(assistant.work_orders) + index + 1, # 生成新ID + "order_id": f"WO{len(assistant.work_orders) + index + 1:06d}", + "title": str(row.get('标题', row.get('title', f'导入工单 {index + 1}'))), + "description": str(row.get('描述', row.get('description', ''))), + "category": str(row.get('分类', row.get('category', '技术问题'))), + "priority": str(row.get('优先级', row.get('priority', 'medium'))), + "status": str(row.get('状态', row.get('status', 'open'))), + "created_at": datetime.now().isoformat(), + "updated_at": datetime.now().isoformat(), + "resolution": str(row.get('解决方案', row.get('resolution', ''))) if pd.notna(row.get('解决方案', row.get('resolution'))) else None, + "satisfaction_score": int(row.get('满意度', row.get('satisfaction_score', 0))) if pd.notna(row.get('满意度', row.get('satisfaction_score'))) else None + } + + # 添加到工单列表(这里应该保存到数据库) + assistant.work_orders.append(workorder) + imported_workorders.append(workorder) + + # 清理上传的文件 + os.remove(upload_path) + + return jsonify({ + "success": True, + "message": f"成功导入 {len(imported_workorders)} 个工单", + "imported_count": len(imported_workorders), + "workorders": imported_workorders + }) + + except Exception as e: + # 清理上传的文件 + if os.path.exists(upload_path): + os.remove(upload_path) + return jsonify({"error": f"解析Excel文件失败: {str(e)}"}), 400 + + except Exception as e: + return jsonify({"error": str(e)}), 500 + +@app.route('/api/workorders/import/template') +def download_import_template(): + """下载工单导入模板""" + try: + # 创建模板数据 + template_data = { + '标题': ['车辆无法启动', '空调不制冷', '导航系统故障'], + '描述': ['用户反映车辆无法正常启动', '空调系统无法制冷', '导航系统显示异常'], + '分类': ['技术问题', '技术问题', '技术问题'], + '优先级': ['high', 'medium', 'low'], + '状态': ['open', 'in_progress', 'resolved'], + '解决方案': ['检查电池和启动系统', '检查制冷剂和压缩机', '更新导航软件'], + '满意度': [5, 4, 5] + } + + df = pd.DataFrame(template_data) + + # 保存为Excel文件 + template_path = 'uploads/workorder_template.xlsx' + os.makedirs('uploads', exist_ok=True) + df.to_excel(template_path, index=False) + + return jsonify({ + "success": True, + "template_url": f"/uploads/workorder_template.xlsx" + }) + + except Exception as e: + return jsonify({"error": str(e)}), 500 + +@app.route('/uploads/') +def uploaded_file(filename): + """提供上传文件的下载服务""" + return send_from_directory(app.config['UPLOAD_FOLDER'], filename) + # 系统设置相关API @app.route('/api/settings') def get_settings(): diff --git a/src/web/static/css/style.css b/src/web/static/css/style.css index 9614a08..9867f82 100644 --- a/src/web/static/css/style.css +++ b/src/web/static/css/style.css @@ -429,3 +429,178 @@ body { background-color: #d1ecf1; border-color: #17a2b8; } + +/* 预设规则卡片样式 */ +.preset-card { + cursor: pointer; + transition: all 0.3s ease; + border: 2px solid transparent; + height: 100%; +} + +.preset-card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 25px rgba(0,0,0,0.15); + border-color: #007bff; +} + +.preset-card.selected { + border-color: #28a745; + background-color: #f8fff9; +} + +.preset-card .card-body { + padding: 1.5rem; + text-align: center; +} + +.preset-card h6 { + margin-bottom: 0.5rem; + font-weight: 600; + color: #333; +} + +.preset-card p { + margin-bottom: 1rem; + color: #6c757d; + font-size: 0.875rem; + line-height: 1.4; +} + +.preset-params { + display: flex; + justify-content: center; + gap: 0.5rem; + flex-wrap: wrap; +} + +.preset-params .badge { + font-size: 0.7rem; + padding: 0.25rem 0.5rem; +} + +/* 预设模板模态框样式 */ +#presetModal .modal-dialog { + max-width: 1200px; +} + +#presetModal .modal-body { + max-height: 70vh; + overflow-y: auto; +} + +/* 预设规则分类标题 */ +#presetModal h6 { + font-weight: 600; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 2px solid; +} + +#presetModal h6.text-primary { + border-bottom-color: #007bff; +} + +#presetModal h6.text-success { + border-bottom-color: #28a745; +} + +#presetModal h6.text-info { + border-bottom-color: #17a2b8; +} + +#presetModal h6.text-warning { + border-bottom-color: #ffc107; +} + +/* 预设卡片图标样式 */ +.preset-card i { + transition: all 0.3s ease; +} + +.preset-card:hover i { + transform: scale(1.1); +} + +/* 预设卡片选中状态 */ +.preset-card.selected i { + color: #28a745 !important; +} + +.preset-card.selected h6 { + color: #28a745; +} + +/* 响应式预设卡片 */ +@media (max-width: 768px) { + .preset-card .card-body { + padding: 1rem; + } + + .preset-card h6 { + font-size: 0.9rem; + } + + .preset-card p { + font-size: 0.8rem; + } + + .preset-params .badge { + font-size: 0.65rem; + padding: 0.2rem 0.4rem; + } +} + +/* 预设规则快速选择 */ +.preset-quick-select { + display: flex; + gap: 0.5rem; + margin-bottom: 1rem; + flex-wrap: wrap; +} + +.preset-quick-select .btn { + font-size: 0.8rem; + padding: 0.25rem 0.75rem; +} + +/* 预设规则预览 */ +.preset-preview { + background-color: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 0.375rem; + padding: 1rem; + margin-top: 1rem; +} + +.preset-preview h6 { + color: #495057; + margin-bottom: 0.5rem; +} + +.preset-preview .preview-params { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0.5rem; +} + +.preset-preview .preview-param { + display: flex; + justify-content: space-between; + padding: 0.25rem 0; + border-bottom: 1px solid #e9ecef; +} + +.preset-preview .preview-param:last-child { + border-bottom: none; +} + +.preset-preview .preview-param strong { + color: #495057; + font-size: 0.875rem; +} + +.preset-preview .preview-param span { + color: #6c757d; + font-size: 0.8rem; +} diff --git a/src/web/static/js/dashboard.js b/src/web/static/js/dashboard.js index a193fa0..270affa 100644 --- a/src/web/static/js/dashboard.js +++ b/src/web/static/js/dashboard.js @@ -1198,9 +1198,14 @@ class TSPDashboard {
- +
+ + +
@@ -1262,17 +1267,748 @@ class TSPDashboard { } } + async viewWorkOrderDetails(workorderId) { + try { + const response = await fetch(`/api/workorders/${workorderId}`); + const workorder = await response.json(); + + if (workorder.error) { + this.showNotification('获取工单详情失败', 'error'); + return; + } + + this.showWorkOrderDetailsModal(workorder); + } catch (error) { + console.error('获取工单详情失败:', error); + this.showNotification('获取工单详情失败', 'error'); + } + } + + showWorkOrderDetailsModal(workorder) { + // 创建模态框HTML + const modalHtml = ` + + `; + + // 移除已存在的模态框 + const existingModal = document.getElementById('workOrderDetailsModal'); + if (existingModal) { + existingModal.remove(); + } + + // 添加新的模态框到页面 + document.body.insertAdjacentHTML('beforeend', modalHtml); + + // 显示模态框 + const modal = new bootstrap.Modal(document.getElementById('workOrderDetailsModal')); + modal.show(); + + // 模态框关闭时移除DOM元素 + document.getElementById('workOrderDetailsModal').addEventListener('hidden.bs.modal', function() { + this.remove(); + }); + } + + async updateWorkOrder(workorderId) { + try { + // 获取工单详情 + const response = await fetch(`/api/workorders/${workorderId}`); + const workorder = await response.json(); + + if (response.ok) { + this.showEditWorkOrderModal(workorder); + } else { + throw new Error(workorder.error || '获取工单详情失败'); + } + } catch (error) { + console.error('获取工单详情失败:', error); + this.showNotification('获取工单详情失败: ' + error.message, 'error'); + } + } + + showEditWorkOrderModal(workorder) { + // 创建编辑工单模态框 + const modalHtml = ` + + `; + + // 移除已存在的模态框 + const existingModal = document.getElementById('editWorkOrderModal'); + if (existingModal) { + existingModal.remove(); + } + + // 添加新模态框到页面 + document.body.insertAdjacentHTML('beforeend', modalHtml); + + // 显示模态框 + const modal = new bootstrap.Modal(document.getElementById('editWorkOrderModal')); + modal.show(); + + // 模态框关闭时清理 + document.getElementById('editWorkOrderModal').addEventListener('hidden.bs.modal', function() { + this.remove(); + }); + } + + async saveWorkOrder(workorderId) { + try { + // 获取表单数据 + const formData = { + title: document.getElementById('editTitle').value, + description: document.getElementById('editDescription').value, + category: document.getElementById('editCategory').value, + priority: document.getElementById('editPriority').value, + status: document.getElementById('editStatus').value, + resolution: document.getElementById('editResolution').value, + satisfaction_score: parseInt(document.getElementById('editSatisfactionScore').value) || null + }; + + // 验证必填字段 + if (!formData.title.trim() || !formData.description.trim()) { + this.showNotification('标题和描述不能为空', 'error'); + return; + } + + // 发送更新请求 + const response = await fetch(`/api/workorders/${workorderId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData) + }); + + const result = await response.json(); + + if (response.ok) { + this.showNotification('工单更新成功', 'success'); + // 关闭模态框 + const modal = bootstrap.Modal.getInstance(document.getElementById('editWorkOrderModal')); + modal.hide(); + // 刷新工单列表 + this.loadWorkOrders(); + } else { + throw new Error(result.error || '更新工单失败'); + } + } catch (error) { + console.error('更新工单失败:', error); + this.showNotification('更新工单失败: ' + error.message, 'error'); + } + } + + // 工单导入功能 + showImportModal() { + // 显示导入模态框 + const modal = new bootstrap.Modal(document.getElementById('importWorkOrderModal')); + modal.show(); + + // 重置表单 + document.getElementById('excel-file-input').value = ''; + document.getElementById('import-progress').classList.add('d-none'); + document.getElementById('import-result').classList.add('d-none'); + } + + async downloadTemplate() { + try { + const response = await fetch('/api/workorders/import/template'); + const result = await response.json(); + + if (result.success) { + // 创建下载链接 + const link = document.createElement('a'); + link.href = result.template_url; + link.download = '工单导入模板.xlsx'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + this.showNotification('模板下载成功', 'success'); + } else { + throw new Error(result.error || '下载模板失败'); + } + } catch (error) { + console.error('下载模板失败:', error); + this.showNotification('下载模板失败: ' + error.message, 'error'); + } + } + + async importWorkOrders() { + const fileInput = document.getElementById('excel-file-input'); + const file = fileInput.files[0]; + + if (!file) { + this.showNotification('请选择要导入的Excel文件', 'error'); + return; + } + + // 验证文件类型 + if (!file.name.match(/\.(xlsx|xls)$/)) { + this.showNotification('只支持Excel文件(.xlsx, .xls)', 'error'); + return; + } + + // 验证文件大小 + if (file.size > 16 * 1024 * 1024) { + this.showNotification('文件大小不能超过16MB', 'error'); + return; + } + + // 显示进度条 + document.getElementById('import-progress').classList.remove('d-none'); + document.getElementById('import-result').classList.add('d-none'); + + try { + // 创建FormData + const formData = new FormData(); + formData.append('file', file); + + // 发送导入请求 + const response = await fetch('/api/workorders/import', { + method: 'POST', + body: formData + }); + + const result = await response.json(); + + if (response.ok && result.success) { + // 显示成功消息 + document.getElementById('import-progress').classList.add('d-none'); + document.getElementById('import-result').classList.remove('d-none'); + document.getElementById('import-success-message').textContent = + `成功导入 ${result.imported_count} 个工单`; + + this.showNotification(result.message, 'success'); + + // 刷新工单列表 + this.loadWorkOrders(); + + // 3秒后关闭模态框 + setTimeout(() => { + const modal = bootstrap.Modal.getInstance(document.getElementById('importWorkOrderModal')); + modal.hide(); + }, 3000); + + } else { + throw new Error(result.error || '导入工单失败'); + } + + } catch (error) { + console.error('导入工单失败:', error); + document.getElementById('import-progress').classList.add('d-none'); + this.showNotification('导入工单失败: ' + error.message, 'error'); + } + } + // 数据分析 async loadAnalytics() { try { const response = await fetch('/api/analytics'); const analytics = await response.json(); this.updateAnalyticsDisplay(analytics); + this.initializeCharts(); } catch (error) { console.error('加载分析数据失败:', error); } } + // 初始化图表 + initializeCharts() { + this.charts = {}; + this.updateCharts(); + } + + // 更新所有图表 + async updateCharts() { + try { + const timeRange = document.getElementById('timeRange').value; + const chartType = document.getElementById('chartType').value; + const dataDimension = document.getElementById('dataDimension').value; + + // 获取数据 + const response = await fetch(`/api/analytics?timeRange=${timeRange}&dimension=${dataDimension}`); + const data = await response.json(); + + // 更新统计卡片 + this.updateStatisticsCards(data); + + // 更新图表 + this.updateMainChart(data, chartType); + this.updateDistributionChart(data); + this.updateTrendChart(data); + this.updatePriorityChart(data); + + // 更新分析报告 + this.updateAnalyticsReport(data); + + } catch (error) { + console.error('更新图表失败:', error); + this.showNotification('更新图表失败: ' + error.message, 'error'); + } + } + + // 更新统计卡片 + updateStatisticsCards(data) { + const total = data.workorders?.total || 0; + const open = data.workorders?.open || 0; + const resolved = data.workorders?.resolved || 0; + const avgSatisfaction = data.satisfaction?.average || 0; + + document.getElementById('totalWorkorders').textContent = total; + document.getElementById('openWorkorders').textContent = open; + document.getElementById('resolvedWorkorders').textContent = resolved; + document.getElementById('avgSatisfaction').textContent = avgSatisfaction.toFixed(1); + + // 更新进度条 + if (total > 0) { + document.getElementById('openProgress').style.width = `${(open / total) * 100}%`; + document.getElementById('resolvedProgress').style.width = `${(resolved / total) * 100}%`; + document.getElementById('satisfactionProgress').style.width = `${(avgSatisfaction / 5) * 100}%`; + } + } + + // 更新主图表 + updateMainChart(data, chartType) { + const ctx = document.getElementById('mainChart').getContext('2d'); + + // 销毁现有图表 + if (this.charts.mainChart) { + this.charts.mainChart.destroy(); + } + + const chartData = this.prepareChartData(data, chartType); + + this.charts.mainChart = new Chart(ctx, { + type: chartType, + data: chartData, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: '数据分析趋势' + }, + legend: { + display: true, + position: 'top' + } + }, + scales: chartType === 'pie' || chartType === 'doughnut' ? {} : { + x: { + display: true, + title: { + display: true, + text: '时间' + } + }, + y: { + display: true, + title: { + display: true, + text: '数量' + } + } + } + } + }); + } + + // 更新分布图表 + updateDistributionChart(data) { + const ctx = document.getElementById('distributionChart').getContext('2d'); + + if (this.charts.distributionChart) { + this.charts.distributionChart.destroy(); + } + + const categories = data.workorders?.by_category || {}; + const labels = Object.keys(categories); + const values = Object.values(categories); + + this.charts.distributionChart = new Chart(ctx, { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ + data: values, + backgroundColor: [ + '#FF6384', + '#36A2EB', + '#FFCE56', + '#4BC0C0', + '#9966FF', + '#FF9F40' + ] + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: '工单分类分布' + }, + legend: { + display: true, + position: 'bottom' + } + } + } + }); + } + + // 更新趋势图表 + updateTrendChart(data) { + const ctx = document.getElementById('trendChart').getContext('2d'); + + if (this.charts.trendChart) { + this.charts.trendChart.destroy(); + } + + const trendData = data.trend || []; + const labels = trendData.map(item => item.date); + const workorders = trendData.map(item => item.workorders); + const alerts = trendData.map(item => item.alerts); + + this.charts.trendChart = new Chart(ctx, { + type: 'line', + data: { + labels: labels, + datasets: [{ + label: '工单数量', + data: workorders, + borderColor: '#36A2EB', + backgroundColor: 'rgba(54, 162, 235, 0.1)', + tension: 0.4 + }, { + label: '预警数量', + data: alerts, + borderColor: '#FF6384', + backgroundColor: 'rgba(255, 99, 132, 0.1)', + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: '时间趋势分析' + } + }, + scales: { + x: { + display: true, + title: { + display: true, + text: '日期' + } + }, + y: { + display: true, + title: { + display: true, + text: '数量' + } + } + } + } + }); + } + + // 更新优先级图表 + updatePriorityChart(data) { + const ctx = document.getElementById('priorityChart').getContext('2d'); + + if (this.charts.priorityChart) { + this.charts.priorityChart.destroy(); + } + + const priorities = data.workorders?.by_priority || {}; + const labels = Object.keys(priorities).map(p => this.getPriorityText(p)); + const values = Object.values(priorities); + + this.charts.priorityChart = new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: '工单数量', + data: values, + backgroundColor: [ + '#28a745', // 低 - 绿色 + '#ffc107', // 中 - 黄色 + '#fd7e14', // 高 - 橙色 + '#dc3545' // 紧急 - 红色 + ] + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: '优先级分布' + } + }, + scales: { + y: { + beginAtZero: true + } + } + } + }); + } + + // 准备图表数据 + prepareChartData(data, chartType) { + const trendData = data.trend || []; + const labels = trendData.map(item => item.date); + const workorders = trendData.map(item => item.workorders); + + if (chartType === 'pie' || chartType === 'doughnut') { + const categories = data.workorders?.by_category || {}; + return { + labels: Object.keys(categories), + datasets: [{ + data: Object.values(categories), + backgroundColor: [ + '#FF6384', + '#36A2EB', + '#FFCE56', + '#4BC0C0', + '#9966FF', + '#FF9F40' + ] + }] + }; + } else { + return { + labels: labels, + datasets: [{ + label: '工单数量', + data: workorders, + borderColor: '#36A2EB', + backgroundColor: 'rgba(54, 162, 235, 0.1)', + tension: chartType === 'line' ? 0.4 : 0 + }] + }; + } + } + + // 导出图表 + exportChart(chartId) { + if (this.charts[chartId]) { + const link = document.createElement('a'); + link.download = `${chartId}_chart.png`; + link.href = this.charts[chartId].toBase64Image(); + link.click(); + } + } + + // 全屏图表 + fullscreenChart(chartId) { + // 这里可以实现全屏显示功能 + this.showNotification('全屏功能开发中', 'info'); + } + + // 导出报告 + async exportReport() { + try { + const response = await fetch('/api/analytics/export'); + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'analytics_report.xlsx'; + link.click(); + window.URL.revokeObjectURL(url); + } catch (error) { + console.error('导出报告失败:', error); + this.showNotification('导出报告失败: ' + error.message, 'error'); + } + } + + // 打印报告 + printReport() { + window.print(); + } + updateAnalyticsDisplay(analytics) { // 更新分析报告 const reportContainer = document.getElementById('analytics-report'); diff --git a/src/web/templates/dashboard.html b/src/web/templates/dashboard.html index 28c8cd0..27d7ab1 100644 --- a/src/web/templates/dashboard.html +++ b/src/web/templates/dashboard.html @@ -844,9 +844,17 @@
工单管理
- +
+ + + +
@@ -914,43 +922,210 @@