From ad1855cfb5f9d5750b749d8acb994d79a93d0b8f Mon Sep 17 00:00:00 2001 From: linjiaqin Date: Fri, 16 Jan 2026 15:45:42 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E6=8E=A5=E5=8F=A3=E7=9B=B8=E5=85=B3=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/xiaozhi/common/redis/RedisKeys.java | 10 ++ .../java/xiaozhi/common/utils/ToolUtil.java | 89 +++++++++++++++ .../device/controller/DeviceController.java | 91 +-------------- .../modules/device/service/DeviceService.java | 4 + .../service/impl/DeviceServiceImpl.java | 105 ++++++++++++++---- 5 files changed, 188 insertions(+), 111 deletions(-) create mode 100644 main/manager-api/src/main/java/xiaozhi/common/utils/ToolUtil.java diff --git a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java index 281472e0..527b9330 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java +++ b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java @@ -166,4 +166,14 @@ public class RedisKeys { public static String getTmpRegisterMacKey(String deviceId) { return "tmp_register_mac:" + deviceId; } + + /** + * OTA绑定设备 + */ + public static String getOtaActivationCode(String activationCode) {return "ota:activation:code:" + activationCode;} + + /** + * OTA获取设备mac相关信息 + */ + public static String getOtaDeviceActivationInfo(String deviceId) {return "ota:activation:data:" + deviceId;} } diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/ToolUtil.java b/main/manager-api/src/main/java/xiaozhi/common/utils/ToolUtil.java new file mode 100644 index 00000000..40888965 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/common/utils/ToolUtil.java @@ -0,0 +1,89 @@ +package xiaozhi.common.utils; + +import cn.hutool.core.util.ReUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 通用工具类 + */ +public class ToolUtil { + private static final Logger logger = LoggerFactory.getLogger(ToolUtil.class); + + /** + * 对象是否不为空(新增) + */ + public static boolean isNotEmpty(Object o) { + return !isEmpty(o); + } + + /** + * 对象是否为空 + */ + public static boolean isEmpty(Object o) { + if (o == null) { + return true; + } + if (o instanceof String) { + if (o.toString().trim().equals("")) { + return true; + } + } else if (o instanceof List) { + if (((List) o).size() == 0) { + return true; + } + } else if (o instanceof Map) { + if (((Map) o).size() == 0) { + return true; + } + } else if (o instanceof Set) { + if (((Set) o).size() == 0) { + return true; + } + } else if (o instanceof Object[]) { + if (((Object[]) o).length == 0) { + return true; + } + } else if (o instanceof int[]) { + if (((int[]) o).length == 0) { + return true; + } + } else if (o instanceof long[]) { + if (((long[]) o).length == 0) { + return true; + } + } + return false; + } + + /** + * 对象组中是否存在空对象 + */ + public static boolean isOneEmpty(Object... os) { + for (Object o : os) { + if (isEmpty(o)) { + return true; + } + } + return false; + } + + /** + * 对象组中是否全是空对象 + */ + public static boolean isAllEmpty(Object... os) { + for (Object o : os) { + if (!isEmpty(o)) { + return false; + } + } + return true; + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index 78a17b02..b562542b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -1,14 +1,9 @@ package xiaozhi.modules.device.controller; -import java.util.List; - +import java.util.*; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.BeanUtils; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -16,10 +11,6 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -import com.fasterxml.jackson.databind.ObjectMapper; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -44,16 +35,11 @@ public class DeviceController { private final DeviceService deviceService; private final RedisUtils redisUtils; private final SysParamsService sysParamsService; - private final RestTemplate restTemplate; - private final ObjectMapper objectMapper; - public DeviceController(DeviceService deviceService, RedisUtils redisUtils, SysParamsService sysParamsService, - RestTemplate restTemplate, ObjectMapper objectMapper) { + public DeviceController(DeviceService deviceService, RedisUtils redisUtils, SysParamsService sysParamsService) { this.deviceService = deviceService; this.redisUtils = redisUtils; this.sysParamsService = sysParamsService; - this.restTemplate = restTemplate; - this.objectMapper = objectMapper; } @PostMapping("/bind/{agentId}/{deviceCode}") @@ -99,83 +85,12 @@ public class DeviceController { @RequiresPermissions("sys:role:normal") public Result forwardToMqttGateway(@PathVariable String agentId, @RequestBody String requestBody) { try { - // 从系统参数中获取MQTT网关地址 - String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); - if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { - return new Result<>(); - } - - // 获取当前用户的设备列表 - UserDetail user = SecurityUser.getUser(); - List devices = deviceService.getUserDevices(user.getId(), agentId); - - // 构建deviceIds数组 - java.util.List deviceIds = new java.util.ArrayList<>(); - for (DeviceEntity device : devices) { - String macAddress = device.getMacAddress() != null ? device.getMacAddress() : "unknown"; - String groupId = device.getBoard() != null ? device.getBoard() : "GID_default"; - - // 替换冒号为下划线 - groupId = groupId.replace(":", "_"); - macAddress = macAddress.replace(":", "_"); - - // 构建mqtt客户端ID格式:groupId@@@macAddress@@@macAddress - String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress; - deviceIds.add(mqttClientId); - } - - // 构建完整的URL - String url = "http://" + mqttGatewayUrl + "/api/devices/status"; - - // 设置请求头 - HttpHeaders headers = new HttpHeaders(); - headers.set("Content-Type", "application/json"); - - // 生成Bearer令牌 - String token = generateBearerToken(); - if (token == null) { - return new Result().error("令牌生成失败"); - } - headers.set("Authorization", "Bearer " + token); - - // 构建请求体JSON - String jsonBody = "{\"clientIds\":" + objectMapper.writeValueAsString(deviceIds) + "}"; - HttpEntity requestEntity = new HttpEntity<>(jsonBody, headers); - - // 发送POST请求 - ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); - - // 返回响应 - return new Result().ok(response.getBody()); + return new Result().ok(deviceService.getDeviceOnlineData(agentId)); } catch (Exception e) { return new Result().error("转发请求失败: " + e.getMessage()); } } - private String generateBearerToken() { - try { - // 获取当前日期,格式为yyyy-MM-dd - String dateStr = java.time.LocalDate.now() - .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); - - // 获取MQTT签名密钥 - String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); - if (StringUtils.isBlank(signatureKey)) { - return null; - } - - // 将日期字符串与MQTT_SIGNATURE_KEY连接 - String tokenContent = dateStr + signatureKey; - - // 对连接后的字符串进行SHA256哈希计算 - String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent); - - return token; - } catch (Exception e) { - return null; - } - } - @PostMapping("/unbind") @Operation(summary = "解绑设备") @RequiresPermissions("sys:role:normal") diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java index f4debba9..c37f69f5 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java @@ -13,6 +13,10 @@ import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.vo.UserShowDeviceListVO; public interface DeviceService extends BaseService { + /** + * 获取设备在线数据 + */ + String getDeviceOnlineData(String agentId); /** * 检查设备是否激活 diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index ea0d20eb..8c9d6232 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -4,17 +4,21 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; -import java.util.Base64; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.http.ContentType; +import cn.hutool.http.Header; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.aop.framework.AopContext; import org.springframework.scheduling.annotation.Async; @@ -40,6 +44,8 @@ import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.DateUtils; +import xiaozhi.common.utils.Result; +import xiaozhi.common.utils.ToolUtil; import xiaozhi.modules.device.dao.DeviceDao; import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.dto.DevicePageUserDTO; @@ -88,16 +94,16 @@ public class DeviceServiceImpl extends BaseServiceImpl if (StringUtils.isBlank(activationCode)) { throw new RenException(ErrorCode.ACTIVATION_CODE_EMPTY); } - String deviceKey = "ota:activation:code:" + activationCode; + String deviceKey = RedisKeys.getOtaActivationCode(activationCode); Object cacheDeviceId = redisUtils.get(deviceKey); - if (cacheDeviceId == null) { + if (ToolUtil.isEmpty(cacheDeviceId)) { throw new RenException(ErrorCode.ACTIVATION_CODE_ERROR); } String deviceId = (String) cacheDeviceId; String safeDeviceId = deviceId.replace(":", "_").toLowerCase(); - String cacheDeviceKey = String.format("ota:activation:data:%s", safeDeviceId); + String cacheDeviceKey = RedisKeys.getOtaDeviceActivationInfo(safeDeviceId); Map cacheMap = (Map) redisUtils.get(cacheDeviceKey); - if (cacheMap == null) { + if (ToolUtil.isEmpty(cacheMap)) { throw new RenException(ErrorCode.ACTIVATION_CODE_ERROR); } String cachedCode = (String) cacheMap.get("activation_code"); @@ -133,19 +139,56 @@ public class DeviceServiceImpl extends BaseServiceImpl deviceEntity.setLastConnectedAt(currentTime); deviceDao.insert(deviceEntity); - // 清理redis缓存 - redisUtils.delete(cacheDeviceKey); - redisUtils.delete(deviceKey); - - // 添加:清除智能体设备数量缓存 - redisUtils.delete(RedisKeys.getAgentDeviceCountById(agentId)); - + // 清理redis缓存、清除智能体设备数量缓存 + redisUtils.delete(List.of(cacheDeviceKey, deviceKey, RedisKeys.getAgentDeviceCountById(agentId))); return true; } + /** + * 获取设备在线数据 + */ @Override - public DeviceReportRespDTO checkDeviceActive(String macAddress, String clientId, - DeviceReportReqDTO deviceReport) { + public String getDeviceOnlineData(String agentId) { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { + return ""; + } + // 构建完整的URL + String url = StrUtil.format("http://{}/api/devices/status", mqttGatewayUrl); + + // 获取当前用户的设备列表 + UserDetail user = SecurityUser.getUser(); + List devices = getUserDevices(user.getId(), agentId); + + // 构建deviceIds数组 + Set deviceIds = devices.stream().map(o -> { + String macAddress = Optional.ofNullable(o.getMacAddress()).orElse("unknown").replace(":", "_"); + String groupId = Optional.ofNullable(o.getBoard()).orElse("GID_default").replace(":", "_"); + return StrUtil.format("{}@@@{}@@@{}", groupId, macAddress, macAddress); + }).collect(Collectors.toSet()); + + // 构建请求入参 + Map> params = MapUtil + .builder(new HashMap>()) + .put("clientIds", deviceIds).build(); + + if (ToolUtil.isNotEmpty(deviceIds)) { + // 发送请求 + String resultMessage = HttpRequest.post(url) + .header(Header.CONTENT_TYPE, ContentType.JSON.getValue()) + .header(Header.AUTHORIZATION, "Bearer " + generateBearerToken()) + .body(JSONUtil.toJsonStr(params)) + .timeout(10000) //超时,毫秒 + .execute().body(); + return resultMessage; + } + // 返回响应 + return ""; + } + + @Override + public DeviceReportRespDTO checkDeviceActive(String macAddress, String clientId, DeviceReportReqDTO deviceReport) { DeviceReportRespDTO response = new DeviceReportRespDTO(); response.setServer_time(buildServerTime()); @@ -356,8 +399,7 @@ public class DeviceServiceImpl extends BaseServiceImpl private String getDeviceCacheKey(String deviceId) { String safeDeviceId = deviceId.replace(":", "_").toLowerCase(); - String dataKey = String.format("ota:activation:data:%s", safeDeviceId); - return dataKey; + return RedisKeys.getOtaDeviceActivationInfo(safeDeviceId); } public DeviceReportRespDTO.Activation buildActivation(String deviceId, DeviceReportReqDTO deviceReport) { @@ -396,7 +438,7 @@ public class DeviceServiceImpl extends BaseServiceImpl redisUtils.set(dataKey, dataMap); // 写入反查激活码 key - String codeKey = "ota:activation:code:" + newCode; + String codeKey = RedisKeys.getOtaActivationCode(newCode); redisUtils.set(codeKey, deviceId); } return code; @@ -606,4 +648,21 @@ public class DeviceServiceImpl extends BaseServiceImpl return mqtt; } + + + /** + * 生成BearerToken + */ + private String generateBearerToken() { + try { + String dateStr = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN); + String signatureKey = sysParamsService.getValue(Constant.SERVER_MQTT_SECRET,false); + if (ToolUtil.isEmpty(signatureKey)) { + return null; + } + return DigestUtil.sha256Hex(dateStr + signatureKey); + } catch (Exception e) { + return null; + } + } } From 9042b7e6d7c4b7ad02263ce2c5b67f3310545e43 Mon Sep 17 00:00:00 2001 From: linjiaqin Date: Fri, 16 Jan 2026 16:43:04 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E4=BD=93=E6=A8=A1=E5=9D=97=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgentMcpAccessPointController.java | 2 +- .../impl/AgentChatHistoryServiceImpl.java | 15 +++++---- .../impl/AgentChatSummaryServiceImpl.java | 32 +++++++++---------- .../agent/service/impl/AgentServiceImpl.java | 30 ++++++----------- .../service/impl/ConfigServiceImpl.java | 6 ++-- .../device/controller/OTAMagController.java | 10 +++--- 6 files changed, 42 insertions(+), 53 deletions(-) diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java index 3f369774..bee728f5 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java @@ -28,7 +28,7 @@ public class AgentMcpAccessPointController { /** * 获取智能体的Mcp接入点地址 * - * @param audioId 智能体id + * @param agentId 智能体id * @return 返回错误提醒或者Mcp接入点地址 */ @Operation(summary = "获取智能体的Mcp接入点地址") diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatHistoryServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatHistoryServiceImpl.java index 63b820c9..494107a2 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatHistoryServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatHistoryServiceImpl.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import cn.hutool.core.collection.ListUtil; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,6 +19,7 @@ import xiaozhi.common.constant.Constant; import xiaozhi.common.page.PageData; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.JsonUtils; +import xiaozhi.common.utils.ToolUtil; import xiaozhi.modules.agent.Enums.AgentChatHistoryType; import xiaozhi.modules.agent.dao.AiAgentChatHistoryDao; import xiaozhi.modules.agent.dto.AgentChatHistoryDTO; @@ -86,13 +88,12 @@ public class AgentChatHistoryServiceImpl extends ServiceImpl audioIds = baseMapper.getAudioIdsByAgentId(agentId); - if (audioIds != null && !audioIds.isEmpty()) { - int batchSize = 1000; // 每批删除1000条 - for (int i = 0; i < audioIds.size(); i += batchSize) { - int end = Math.min(i + batchSize, audioIds.size()); - List batch = audioIds.subList(i, end); - baseMapper.deleteAudioByIds(batch); - } + if (ToolUtil.isNotEmpty(audioIds)) { + // 每批删除1000条 + List> batch = ListUtil.split(audioIds, 1000); + batch.forEach(dataList->{ + baseMapper.deleteAudioByIds(dataList); + }); } } if (deleteAudio && !deleteText) { diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java index f367891f..38fef94b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java @@ -78,11 +78,11 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { // 4. 生成总结(generateSummaryFromMessages方法已包含长度限制逻辑) String summary = generateSummaryFromMessages(meaningfulMessages, agentId); - System.out.println("成功生成会话 " + sessionId + " 的聊天记录总结,长度: " + summary.length() + " 字符"); + log.info("成功生成会话 {} 的聊天记录总结,长度: {} 字符", sessionId, summary.length()); return new AgentChatSummaryDTO(sessionId, agentId, summary); } catch (Exception e) { - System.err.println("生成会话 " + sessionId + " 的聊天记录总结时发生错误: " + e.getMessage()); + log.error("生成会话 {} 的聊天记录总结时发生错误: {}", sessionId, e.getMessage()); return new AgentChatSummaryDTO(sessionId, "生成总结时发生错误: " + e.getMessage()); } } @@ -93,14 +93,14 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { // 1. 生成总结 AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId); if (!summaryDTO.isSuccess()) { - System.err.println("生成总结失败: " + summaryDTO.getErrorMessage()); + log.info("生成总结失败: {}", summaryDTO.getErrorMessage()); return false; } // 2. 获取设备信息(通过会话关联的设备) DeviceEntity device = getDeviceBySessionId(sessionId); if (device == null) { - System.err.println("未找到与会话 " + sessionId + " 关联的设备"); + log.info("未找到与会话 {} 关联的设备", sessionId); return false; } @@ -116,11 +116,11 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { } }); - System.out.println("成功保存会话 " + sessionId + " 的聊天记录总结到智能体 " + device.getAgentId()); + log.info("成功保存会话 {} 的聊天记录总结到智能体 {}", sessionId, device.getAgentId()); return true; } catch (Exception e) { - System.err.println("保存会话 " + sessionId + " 的聊天记录总结时发生错误: " + e.getMessage()); + log.error("保存会话 {} 的聊天记录总结时发生错误: {}", sessionId, e.getMessage()); return false; } } @@ -138,7 +138,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { } return agentChatHistoryService.getChatHistoryBySessionId(agentId, sessionId); } catch (Exception e) { - System.err.println("获取会话 " + sessionId + " 的聊天记录失败: " + e.getMessage()); + log.error("获取会话 {} 的聊天记录失败: {}", sessionId, e.getMessage()); return null; } } @@ -157,7 +157,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { AgentChatHistoryEntity entity = agentChatHistoryService.getOne(wrapper); return entity != null ? entity.getAgentId() : null; } catch (Exception e) { - System.err.println("根据会话ID " + sessionId + " 查找智能体ID失败: " + e.getMessage()); + log.error("根据会话ID {} 查找智能体ID失败: {}", sessionId, e.getMessage()); return null; } } @@ -272,7 +272,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { return summary; } catch (Exception e) { - System.err.println("调用Java端LLM服务失败: " + e.getMessage()); + log.error("调用Java端LLM服务失败: {}", e.getMessage()); throw new RuntimeException("LLM服务不可用,无法生成聊天总结"); } } @@ -295,7 +295,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { // 返回智能体的当前总结记忆 return agentInfo.getSummaryMemory(); } catch (Exception e) { - System.err.println("获取智能体历史记忆失败,agentId: " + agentId + ", 错误: " + e.getMessage()); + log.error("获取智能体历史记忆失败,agentId: {}, 错误: {}", agentId, e.getMessage()); return null; } } @@ -309,7 +309,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { String modelId = getMemorySummaryModelId(agentId); if (StringUtils.isBlank(modelId)) { - System.out.println("未找到记忆总结的LLM模型配置,使用默认LLM服务"); + log.info("未找到记忆总结的LLM模型配置,使用默认LLM服务"); return llmService.generateSummaryWithHistory(conversation, historyMemory, null, null); } @@ -323,7 +323,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { throw new RuntimeException("Java端LLM服务返回异常: " + summary); } catch (Exception e) { - System.err.println("调用Java端LLM服务异常,agentId: " + agentId + ", 错误: " + e.getMessage()); + log.error("调用Java端LLM服务异常,agentId: {}, 错误: {}", agentId, e.getMessage()); throw e; } } @@ -337,7 +337,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { String modelId = getMemorySummaryModelId(agentId); if (StringUtils.isBlank(modelId)) { - System.out.println("未找到记忆总结的LLM模型配置,使用默认LLM服务"); + log.info("未找到记忆总结的LLM模型配置,使用默认LLM服务"); return llmService.generateSummary(conversation); } @@ -351,7 +351,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { throw new RuntimeException("Java端LLM服务返回异常: " + summary); } catch (Exception e) { - System.err.println("调用Java端LLM服务异常,agentId: " + agentId + ", 错误: " + e.getMessage()); + log.error("调用Java端LLM服务异常,agentId: {}, 错误: {}", agentId, e.getMessage()); throw e; } } @@ -394,7 +394,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { return llmModelId; } catch (Exception e) { - System.err.println("获取记忆总结LLM模型ID失败,agentId: " + agentId + ", 错误: " + e.getMessage()); + log.error("获取记忆总结LLM模型ID失败,agentId: {}, 错误: {}", agentId, e.getMessage()); return null; } } @@ -416,7 +416,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { } return null; } catch (Exception e) { - System.err.println("根据会话ID " + sessionId + " 查找设备信息失败: " + e.getMessage()); + log.error("根据会话ID {} 查找设备信息失败: {}", sessionId, e.getMessage()); return null; } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java index dac5cbba..3237e22c 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java @@ -1,11 +1,6 @@ package xiaozhi.modules.agent.service.impl; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -28,6 +23,7 @@ import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.JsonUtils; +import xiaozhi.common.utils.ToolUtil; import xiaozhi.modules.agent.dao.AgentDao; import xiaozhi.modules.agent.dto.AgentCreateDTO; import xiaozhi.modules.agent.dto.AgentDTO; @@ -136,20 +132,14 @@ public class AgentServiceImpl extends BaseServiceImpl imp if (StringUtils.isNotBlank(keyword)) { if ("mac".equals(searchType)) { // 按MAC地址搜索:先搜索设备,再获取对应的智能体 - List devices = deviceService.searchDevicesByMacAddress(keyword, userId); - - if (!devices.isEmpty()) { - // 获取设备对应的智能体ID列表 - List agentIds = devices.stream() - .map(DeviceEntity::getAgentId) - .distinct() - .collect(Collectors.toList()); - - if (!agentIds.isEmpty()) { - queryWrapper.in("id", agentIds); - } else { - return new ArrayList<>(); - } + List devices = Optional.ofNullable(deviceService.searchDevicesByMacAddress(keyword, userId)).orElseGet(ArrayList::new); + // 获取设备对应的智能体ID列表 + List agentIds = devices.stream() + .map(DeviceEntity::getAgentId) + .distinct() + .collect(Collectors.toList()); + if (ToolUtil.isNotEmpty(agentIds)) { + queryWrapper.in("id", agentIds); } else { return new ArrayList<>(); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index ead30b70..49885614 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -163,11 +163,11 @@ public class ConfigServiceImpl implements ConfigService { } result.put("chat_history_conf", chatHistoryConf); // 如果客户端已实例化模型,则不返回 - String alreadySelectedVadModelId = (String) selectedModule.get("VAD"); + String alreadySelectedVadModelId = selectedModule.get("VAD"); if (alreadySelectedVadModelId != null && alreadySelectedVadModelId.equals(agent.getVadModelId())) { agent.setVadModelId(null); } - String alreadySelectedAsrModelId = (String) selectedModule.get("ASR"); + String alreadySelectedAsrModelId = selectedModule.get("ASR"); if (alreadySelectedAsrModelId != null && alreadySelectedAsrModelId.equals(agent.getAsrModelId())) { agent.setAsrModelId(null); } @@ -302,7 +302,7 @@ public class ConfigServiceImpl implements ConfigService { private void buildVoiceprintConfig(String agentId, Map result) { try { // 获取声纹接口地址 - String voiceprintUrl = sysParamsService.getValue("server.voice_print", true); + String voiceprintUrl = sysParamsService.getValue(Constant.SERVER_VOICE_PRINT, true); if (StringUtils.isBlank(voiceprintUrl) || "null".equals(voiceprintUrl)) { return; } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java index bbe0c66a..128ba195 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java @@ -7,7 +7,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import org.apache.commons.lang3.StringUtils; @@ -145,15 +147,11 @@ public class OTAMagController { // 检查下载次数 String downloadCountKey = RedisKeys.getOtaDownloadCountKey(uuid); - Integer downloadCount = (Integer) redisUtils.get(downloadCountKey); - if (downloadCount == null) { - downloadCount = 0; - } + Integer downloadCount = (Integer) Optional.ofNullable(redisUtils.get(downloadCountKey)).orElse(0); // 如果下载次数超过3次,返回404 if (downloadCount >= 3) { - redisUtils.delete(downloadCountKey); - redisUtils.delete(RedisKeys.getOtaIdKey(uuid)); + redisUtils.delete(List.of(downloadCountKey, RedisKeys.getOtaIdKey(uuid))); logger.warn("Download limit exceeded for UUID: {}", uuid); return ResponseEntity.notFound().build(); }