| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.R; |
| | | import com.zy.ai.entity.AiAutoTuneJob; |
| | | import com.zy.ai.entity.AiChatSession; |
| | | import com.zy.ai.entity.LlmCallLog; |
| | | import com.zy.ai.entity.LlmRouteConfig; |
| | | import com.zy.ai.enums.AiPromptScene; |
| | | import com.zy.ai.mapper.AiChatSessionMapper; |
| | | import com.zy.ai.service.AiAutoTuneJobService; |
| | | import com.zy.ai.service.LlmCallLogService; |
| | | import com.zy.ai.service.LlmRouteConfigService; |
| | | import com.zy.asrs.entity.*; |
| | |
| | | import com.zy.core.thread.StationThread; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | |
| | | @Autowired |
| | | private LlmCallLogService llmCallLogService; |
| | | @Autowired |
| | | private AiAutoTuneJobService aiAutoTuneJobService; |
| | | @Autowired |
| | | private AiChatSessionMapper aiChatSessionMapper; |
| | | @Autowired |
| | | private DevicePingFileStorageService devicePingFileStorageService; |
| | | |
| | | @Value("${devicePingStorage.intervalMs:1000}") |
| | | private int devicePingIntervalMs; |
| | | @Value("${devicePingStorage.timeoutMs:800}") |
| | | private int devicePingTimeoutMs; |
| | | @Value("${devicePingStorage.probeCount:3}") |
| | | private int devicePingProbeCount; |
| | | @Value("${devicePingStorage.packetSize:-1}") |
| | | private int devicePingPacketSize; |
| | | |
| | | @GetMapping("/summary/auth") |
| | | @ManagerAuth(memo = "系统仪表盘统计") |
| | | public R summary() { |
| | | Map<String, Object> tasks = buildTaskStats(); |
| | | Map<String, Object> devices = buildDeviceStats(); |
| | | Map<String, Object> network = buildNetworkStats(); |
| | | Map<String, Object> ai = buildAiStats(); |
| | | |
| | | Map<String, Object> overview = new LinkedHashMap<>(); |
| | |
| | | result.put("overview", overview); |
| | | result.put("tasks", tasks); |
| | | result.put("devices", devices); |
| | | result.put("network", network); |
| | | result.put("ai", ai); |
| | | return R.ok(result); |
| | | } |
| | |
| | | long completionTokenTotal = 0L; |
| | | long askCount = 0L; |
| | | long sessionCount = 0L; |
| | | long autoTunePromptTokenTotal = 0L; |
| | | long autoTuneCompletionTokenTotal = 0L; |
| | | long autoTuneTokenTotal = 0L; |
| | | try { |
| | | List<AiChatSession> sessions = aiChatSessionMapper.selectList(new QueryWrapper<AiChatSession>() |
| | | .select("id", "sum_prompt_tokens", "sum_completion_tokens", "sum_total_tokens", "ask_count")); |
| | |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("dashboard ai session stats load failed: {}", safeMessage(e)); |
| | | } |
| | | |
| | | try { |
| | | List<Map<String, Object>> autoTuneRows = aiAutoTuneJobService.listMaps(new QueryWrapper<AiAutoTuneJob>() |
| | | .select("COALESCE(SUM(prompt_tokens), 0) AS prompt_token_total", |
| | | "COALESCE(SUM(completion_tokens), 0) AS completion_token_total", |
| | | "COALESCE(SUM(total_tokens), 0) AS token_total") |
| | | .eq("prompt_scene_code", AiPromptScene.AUTO_TUNE_DISPATCH.getCode())); |
| | | Map<String, Object> autoTuneRow = autoTuneRows == null || autoTuneRows.isEmpty() |
| | | ? Collections.emptyMap() |
| | | : autoTuneRows.get(0); |
| | | autoTunePromptTokenTotal = toLong(autoTuneRow.get("prompt_token_total")); |
| | | autoTuneCompletionTokenTotal = toLong(autoTuneRow.get("completion_token_total")); |
| | | autoTuneTokenTotal = toLong(autoTuneRow.get("token_total")); |
| | | |
| | | // Agent 自动调参不生成 sys_ai_chat_session,会单独落到 sys_ai_auto_tune_job。 |
| | | promptTokenTotal += autoTunePromptTokenTotal; |
| | | completionTokenTotal += autoTuneCompletionTokenTotal; |
| | | tokenTotal += autoTuneTokenTotal; |
| | | } catch (Exception e) { |
| | | log.warn("dashboard ai auto tune token stats load failed: {}", safeMessage(e)); |
| | | } |
| | | |
| | | List<LlmRouteConfig> routes = Collections.emptyList(); |
| | |
| | | overview.put("tokenTotal", tokenTotal); |
| | | overview.put("promptTokenTotal", promptTokenTotal); |
| | | overview.put("completionTokenTotal", completionTokenTotal); |
| | | overview.put("autoTuneTokenTotal", autoTuneTokenTotal); |
| | | overview.put("autoTunePromptTokenTotal", autoTunePromptTokenTotal); |
| | | overview.put("autoTuneCompletionTokenTotal", autoTuneCompletionTokenTotal); |
| | | overview.put("askCount", askCount); |
| | | overview.put("sessionCount", sessionCount); |
| | | overview.put("routeTotal", routeTotal); |
| | |
| | | return result; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | private Map<String, Object> buildNetworkStats() { |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | Map<String, Object> overview = new LinkedHashMap<>(); |
| | | overview.put("totalDevices", 0L); |
| | | overview.put("okDevices", 0L); |
| | | overview.put("unstableDevices", 0L); |
| | | overview.put("offlineDevices", 0L); |
| | | overview.put("noDataDevices", 0L); |
| | | overview.put("attentionDevices", 0L); |
| | | overview.put("avgLatencyMs", null); |
| | | overview.put("maxLatencyMs", null); |
| | | |
| | | Map<String, Object> samplingConfig = new LinkedHashMap<>(); |
| | | samplingConfig.put("intervalMs", devicePingIntervalMs); |
| | | samplingConfig.put("timeoutMs", devicePingTimeoutMs); |
| | | samplingConfig.put("probeCount", devicePingProbeCount); |
| | | samplingConfig.put("packetSize", Math.max(devicePingPacketSize, -1)); |
| | | |
| | | List<Map<String, Object>> statusStats = new ArrayList<>(); |
| | | statusStats.add(metric("正常", 0L)); |
| | | statusStats.add(metric("波动", 0L)); |
| | | statusStats.add(metric("超时/异常", 0L)); |
| | | statusStats.add(metric("暂无数据", 0L)); |
| | | |
| | | List<Map<String, Object>> focusDevices = new ArrayList<>(); |
| | | |
| | | try { |
| | | Map<String, Object> overviewResult = devicePingFileStorageService.queryOverview(listPingConfigs()); |
| | | Map<String, Object> summary = overviewResult.get("summary") instanceof Map |
| | | ? (Map<String, Object>) overviewResult.get("summary") |
| | | : Collections.emptyMap(); |
| | | List<Map<String, Object>> devices = overviewResult.get("devices") instanceof List |
| | | ? (List<Map<String, Object>>) overviewResult.get("devices") |
| | | : Collections.emptyList(); |
| | | |
| | | long okDevices = toLong(summary.get("okDevices")); |
| | | long unstableDevices = toLong(summary.get("unstableDevices")); |
| | | long offlineDevices = toLong(summary.get("offlineDevices")); |
| | | long noDataDevices = toLong(summary.get("noDataDevices")); |
| | | |
| | | overview.put("totalDevices", toLong(summary.get("totalDevices"))); |
| | | overview.put("okDevices", okDevices); |
| | | overview.put("unstableDevices", unstableDevices); |
| | | overview.put("offlineDevices", offlineDevices); |
| | | overview.put("noDataDevices", noDataDevices); |
| | | overview.put("attentionDevices", unstableDevices + offlineDevices + noDataDevices); |
| | | overview.put("avgLatencyMs", summary.get("avgLatencyMs")); |
| | | overview.put("maxLatencyMs", summary.get("maxLatencyMs")); |
| | | |
| | | statusStats = new ArrayList<>(); |
| | | statusStats.add(metric("正常", okDevices)); |
| | | statusStats.add(metric("波动", unstableDevices)); |
| | | statusStats.add(metric("超时/异常", offlineDevices)); |
| | | statusStats.add(metric("暂无数据", noDataDevices)); |
| | | |
| | | focusDevices = buildNetworkFocusDevices(devices); |
| | | } catch (Exception e) { |
| | | log.warn("dashboard network stats load failed: {}", safeMessage(e)); |
| | | } |
| | | |
| | | result.put("overview", overview); |
| | | result.put("samplingConfig", samplingConfig); |
| | | result.put("statusStats", statusStats); |
| | | result.put("focusDevices", focusDevices); |
| | | return result; |
| | | } |
| | | |
| | | private List<DeviceConfig> listDeviceConfig(SlaveType type) { |
| | | try { |
| | | return deviceConfigService.list(new QueryWrapper<DeviceConfig>() |
| | |
| | | } |
| | | } |
| | | |
| | | private List<DeviceConfig> listPingConfigs() { |
| | | try { |
| | | return deviceConfigService.list(new QueryWrapper<DeviceConfig>() |
| | | .isNotNull("ip") |
| | | .ne("ip", "") |
| | | .orderBy(true, true, "device_type", "device_no")); |
| | | } catch (Exception e) { |
| | | log.warn("dashboard ping device config load failed: {}", safeMessage(e)); |
| | | return Collections.emptyList(); |
| | | } |
| | | } |
| | | |
| | | private List<Map<String, Object>> buildNetworkFocusDevices(List<Map<String, Object>> devices) { |
| | | if (devices == null || devices.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<Map<String, Object>> candidates = new ArrayList<>(); |
| | | for (Map<String, Object> row : devices) { |
| | | if (resolveNetworkFocusRank(row) < 3) { |
| | | candidates.add(row); |
| | | } |
| | | } |
| | | if (candidates.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | candidates.sort((left, right) -> { |
| | | int rankDiff = Integer.compare(resolveNetworkFocusRank(left), resolveNetworkFocusRank(right)); |
| | | if (rankDiff != 0) { |
| | | return rankDiff; |
| | | } |
| | | int latencyDiff = Long.compare(toLong(right.get("avgLatencyMs")), toLong(left.get("avgLatencyMs"))); |
| | | if (latencyDiff != 0) { |
| | | return latencyDiff; |
| | | } |
| | | return Long.compare(toLong(right.get("latestTime")), toLong(left.get("latestTime"))); |
| | | }); |
| | | |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (Map<String, Object> item : candidates) { |
| | | if (item == null) { |
| | | continue; |
| | | } |
| | | Map<String, Object> focus = new LinkedHashMap<>(); |
| | | focus.put("name", toText(item.get("deviceType")) + "-" + toText(item.get("deviceNo"))); |
| | | focus.put("ip", toText(item.get("ip"))); |
| | | focus.put("statusText", defaultText(toText(item.get("statusText")), "未知")); |
| | | focus.put("statusType", resolveNetworkStatusTagType(toText(item.get("status")))); |
| | | focus.put("avgLatencyMs", item.get("avgLatencyMs")); |
| | | focus.put("latestTimeLabel", defaultText(toText(item.get("latestTimeLabel")), "--")); |
| | | focus.put("message", defaultText(toText(item.get("message")), "暂无额外说明")); |
| | | result.add(focus); |
| | | if (result.size() >= 4) { |
| | | break; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private int resolveNetworkFocusRank(Map<String, Object> row) { |
| | | String status = row == null ? "" : toText(row.get("status")); |
| | | if ("TIMEOUT".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) { |
| | | return 0; |
| | | } |
| | | if ("UNSTABLE".equalsIgnoreCase(status)) { |
| | | return 1; |
| | | } |
| | | if ("NO_DATA".equalsIgnoreCase(status)) { |
| | | return 2; |
| | | } |
| | | return 3; |
| | | } |
| | | |
| | | private String resolveNetworkStatusTagType(String status) { |
| | | if ("TIMEOUT".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) { |
| | | return "danger"; |
| | | } |
| | | if ("UNSTABLE".equalsIgnoreCase(status)) { |
| | | return "warning"; |
| | | } |
| | | if ("OK".equalsIgnoreCase(status)) { |
| | | return "success"; |
| | | } |
| | | return "info"; |
| | | } |
| | | |
| | | private boolean isInboundTask(Long wrkSts) { |
| | | return wrkSts != null && wrkSts > 0 && wrkSts < 100; |
| | | } |