diff --git a/src/web/app.py b/src/web/app.py index c50ddd9..3405085 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -10,6 +10,9 @@ import os import json import logging import pandas as pd + +# 配置日志 +logger = logging.getLogger(__name__) from datetime import datetime, timedelta from openpyxl import Workbook from openpyxl.styles import Font @@ -631,9 +634,9 @@ def get_workorders(): priority_filter = request.args.get('priority') with db_manager.get_session() as session: q = session.query(WorkOrder) - if status_filter and status_filter != 'all': + if status_filter and status_filter != 'all': q = q.filter(WorkOrder.status == status_filter) - if priority_filter and priority_filter != 'all': + if priority_filter and priority_filter != 'all': q = q.filter(WorkOrder.priority == priority_filter) q = q.order_by(WorkOrder.created_at.desc()) rows = q.all() @@ -877,80 +880,80 @@ def generate_db_analytics(days: int, dimension: str) -> dict: } for d in day_keys] # 工单统计 - total = len(workorders) - status_counts = Counter([wo.status for wo in workorders]) - category_counts = Counter([wo.category for wo in workorders]) - priority_counts = Counter([wo.priority for wo in workorders]) - resolved_count = status_counts.get('resolved', 0) + total = len(workorders) + status_counts = Counter([wo.status for wo in workorders]) + category_counts = Counter([wo.category for wo in workorders]) + priority_counts = Counter([wo.priority for wo in workorders]) + resolved_count = status_counts.get('resolved', 0) workorders_stats = { - 'total': total, - 'open': status_counts.get('open', 0), - 'in_progress': status_counts.get('in_progress', 0), - 'resolved': resolved_count, - 'closed': status_counts.get('closed', 0), - 'by_category': dict(category_counts), - 'by_priority': dict(priority_counts) - } - - # 满意度 - scores = [] - for wo in workorders: - if wo.satisfaction_score not in (None, ''): - try: - score = float(wo.satisfaction_score) - scores.append(score) - except (ValueError, TypeError): - continue - avg_satisfaction = round(sum(scores)/len(scores), 1) if scores else 0 - dist = Counter([str(int(round(s))) for s in scores]) if scores else {} - satisfaction_stats = { - 'average': avg_satisfaction, - 'distribution': {k: int(v) for k, v in dist.items()} + 'total': total, + 'open': status_counts.get('open', 0), + 'in_progress': status_counts.get('in_progress', 0), + 'resolved': resolved_count, + 'closed': status_counts.get('closed', 0), + 'by_category': dict(category_counts), + 'by_priority': dict(priority_counts) } - - # 预警统计 - level_counts = Counter([al.level for al in alerts]) - active_alerts = len([al for al in alerts if al.is_active]) - resolved_alerts = len([al for al in alerts if not al.is_active and al.resolved_at]) - alerts_stats = { - 'total': len(alerts), - 'active': active_alerts, - 'resolved': resolved_alerts, - 'by_level': {k: int(v) for k, v in level_counts.items()} - } - # 性能指标(基于对话响应时间粗略估计) - resp_times = [] - for c in conversations: - if c.response_time not in (None, ''): - try: - resp_time = float(c.response_time) - resp_times.append(resp_time) - except (ValueError, TypeError): - continue - avg_resp = round(sum(resp_times)/len(resp_times), 2) if resp_times else 0 - throughput = len(conversations) # 期间内的对话数量 - # 错误率:用严重预警比例粗估 - critical = level_counts.get('critical', 0) - error_rate = round((critical / alerts_stats['total']) * 100, 2) if alerts_stats['total'] > 0 else 0 + # 满意度 + scores = [] + for wo in workorders: + if wo.satisfaction_score not in (None, ''): + try: + score = float(wo.satisfaction_score) + scores.append(score) + except (ValueError, TypeError): + continue + avg_satisfaction = round(sum(scores)/len(scores), 1) if scores else 0 + dist = Counter([str(int(round(s))) for s in scores]) if scores else {} + satisfaction_stats = { + 'average': avg_satisfaction, + 'distribution': {k: int(v) for k, v in dist.items()} + } + + # 预警统计 + level_counts = Counter([al.level for al in alerts]) + active_alerts = len([al for al in alerts if al.is_active]) + resolved_alerts = len([al for al in alerts if not al.is_active and al.resolved_at]) + alerts_stats = { + 'total': len(alerts), + 'active': active_alerts, + 'resolved': resolved_alerts, + 'by_level': {k: int(v) for k, v in level_counts.items()} + } + + # 性能指标(基于对话响应时间粗略估计) + resp_times = [] + for c in conversations: + if c.response_time not in (None, ''): + try: + resp_time = float(c.response_time) + resp_times.append(resp_time) + except (ValueError, TypeError): + continue + avg_resp = round(sum(resp_times)/len(resp_times), 2) if resp_times else 0 + throughput = len(conversations) # 期间内的对话数量 + # 错误率:用严重预警比例粗估 + critical = level_counts.get('critical', 0) + error_rate = round((critical / alerts_stats['total']) * 100, 2) if alerts_stats['total'] > 0 else 0 performance_stats = { - 'response_time': avg_resp, - 'uptime': 99.0, # 可接入真实监控后更新 - 'error_rate': error_rate, - 'throughput': throughput + 'response_time': avg_resp, + 'uptime': 99.0, # 可接入真实监控后更新 + 'error_rate': error_rate, + 'throughput': throughput } return { - 'trend': trend, + 'trend': trend, 'workorders': workorders_stats, 'satisfaction': satisfaction_stats, 'alerts': alerts_stats, 'performance': performance_stats, 'summary': { - 'total_workorders': total, - 'resolution_rate': round((resolved_count/total)*100, 1) if total > 0 else 0, - 'avg_satisfaction': avg_satisfaction, - 'active_alerts': active_alerts + 'total_workorders': total, + 'resolution_rate': round((resolved_count/total)*100, 1) if total > 0 else 0, + 'avg_satisfaction': avg_satisfaction, + 'active_alerts': active_alerts } } @@ -1144,11 +1147,11 @@ def get_settings(): settings['api_key'] = '******' settings['api_key_masked'] = True else: - settings = { - "api_timeout": 30, - "max_history": 10, - "refresh_interval": 10, - "auto_monitoring": True, + settings = { + "api_timeout": 30, + "max_history": 10, + "refresh_interval": 10, + "auto_monitoring": True, "agent_mode": True, # LLM与API配置(仅持久化,不直接热更新LLM客户端) "api_provider": "openai",