diff --git a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java index 779fea83..78154b5c 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java +++ b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java @@ -177,5 +177,5 @@ public interface Constant { /** * 版本号 */ - public static final String VERSION = "0.3.14"; + public static final String VERSION = "0.4.2"; } \ No newline at end of file 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 62d21ab5..62487456 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 @@ -62,6 +62,13 @@ public class RedisKeys { return "agent:device:count:" + id; } + /** + * 获取智能体最后连接时间缓存key + */ + public static String getAgentDeviceLastConnectedAtById(String id) { + return "agent:device:lastConnected:" + id; + } + /** * 获取系统配置缓存key */ diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/biz/impl/AgentChatHistoryBizServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/biz/impl/AgentChatHistoryBizServiceImpl.java index b839e9e4..21e645de 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/biz/impl/AgentChatHistoryBizServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/biz/impl/AgentChatHistoryBizServiceImpl.java @@ -1,12 +1,15 @@ package xiaozhi.modules.agent.service.biz.impl; import java.util.Base64; +import java.util.Date; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import xiaozhi.common.redis.RedisKeys; +import xiaozhi.common.redis.RedisUtils; import xiaozhi.modules.agent.dto.AgentChatHistoryReportDTO; import xiaozhi.modules.agent.entity.AgentChatHistoryEntity; import xiaozhi.modules.agent.entity.AgentEntity; @@ -29,6 +32,7 @@ public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizServic private final AgentService agentService; private final AgentChatHistoryService agentChatHistoryService; private final AgentChatAudioService agentChatAudioService; + private final RedisUtils redisUtils; /** * 处理聊天记录上报,包括文件上传和相关信息记录 @@ -77,6 +81,8 @@ public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizServic // 3. 保存数据 agentChatHistoryService.save(entity); + // 4. 更新设备最后对话时间 + redisUtils.set(RedisKeys.getAgentDeviceLastConnectedAtById(agentId), new Date()); return Boolean.TRUE; } } 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 97722b59..ae650c85 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 @@ -21,6 +21,7 @@ import xiaozhi.modules.agent.dao.AgentDao; import xiaozhi.modules.agent.dto.AgentDTO; import xiaozhi.modules.agent.entity.AgentEntity; import xiaozhi.modules.agent.service.AgentService; +import xiaozhi.modules.device.service.DeviceService; import xiaozhi.modules.model.service.ModelConfigService; import xiaozhi.modules.security.user.SecurityUser; import xiaozhi.modules.sys.enums.SuperAdminEnum; @@ -29,11 +30,11 @@ import xiaozhi.modules.timbre.service.TimbreService; @Service @AllArgsConstructor public class AgentServiceImpl extends BaseServiceImpl implements AgentService { - private final AgentDao agentDao; private final TimbreService timbreModelService; private final ModelConfigService modelConfigService; private final RedisUtils redisUtils; + private final DeviceService deviceService; @Override public PageData adminAgentList(Map params) { @@ -95,9 +96,11 @@ public class AgentServiceImpl extends BaseServiceImpl imp // 获取 TTS 音色名称 dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId())); + // 获取智能体最近的最后连接时长 + dto.setLastConnectedAt(deviceService.getLatestLastConnectionTime(agent.getId())); + // 获取设备数量 dto.setDeviceCount(getDeviceCountByAgentId(agent.getId())); - return dto; }).collect(Collectors.toList()); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java index 5ede3d6e..6570b89b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java @@ -6,6 +6,16 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import xiaozhi.modules.device.entity.DeviceEntity; +import java.util.Date; +import java.util.List; + @Mapper public interface DeviceDao extends BaseMapper { + /** + * 获取此智能体全部设备的最后连接时间 + * @param agentId 智能体id + * @return + */ + Date getAllLastConnectedAtByAgentId(String agentId); + } \ No newline at end of file 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 aff31bff..fb91ff89 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 @@ -1,5 +1,6 @@ package xiaozhi.modules.device.service; +import java.util.Date; import java.util.List; import xiaozhi.common.page.PageData; @@ -78,4 +79,13 @@ public interface DeviceService extends BaseService { * @return 激活码 */ String geCodeByDeviceId(String deviceId); + + /** + * 获取这个智能体设备理的最近的最后连接时间 + * @param agentId 智能体id + * @return 返回设备最近的最后连接时间 + */ + Date getLatestLastConnectionTime(String agentId); + + } \ No newline at end of file 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 8eb23a93..515aea7f 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 @@ -258,6 +258,20 @@ public class DeviceServiceImpl extends BaseServiceImpl return null; } + @Override + public Date getLatestLastConnectionTime(String agentId) { + // 查询是否有缓存时间,有则返回 + Date cachedDate = (Date) redisUtils.get(RedisKeys.getAgentDeviceLastConnectedAtById(agentId)); + if (cachedDate != null) { + return cachedDate; + } + Date maxDate = deviceDao.getAllLastConnectedAtByAgentId(agentId); + if (maxDate != null) { + redisUtils.set(RedisKeys.getAgentDeviceLastConnectedAtById(agentId), maxDate); + } + return maxDate; + } + private String getDeviceCacheKey(String deviceId) { String safeDeviceId = deviceId.replace(":", "_").toLowerCase(); String dataKey = String.format("ota:activation:data:%s", safeDeviceId); diff --git a/main/manager-api/src/main/resources/db/changelog/202505081146.sql b/main/manager-api/src/main/resources/db/changelog/202505081146.sql new file mode 100644 index 00000000..fe7582f3 --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202505081146.sql @@ -0,0 +1,43 @@ +-- 添加百度ASR模型配置 +delete from `ai_model_config` where `id` = 'ASR_BaiduASR'; +INSERT INTO `ai_model_config` VALUES ('ASR_BaiduASR', 'ASR', 'BaiduASR', '百度语音识别', 0, 1, '{\"type\": \"baidu\", \"app_id\": \"\", \"api_key\": \"\", \"secret_key\": \"\", \"dev_pid\": 1537, \"output_dir\": \"tmp/\"}', NULL, NULL, 7, NULL, NULL, NULL, NULL); + + +-- 添加百度ASR供应器 +delete from `ai_model_provider` where `id` = 'SYSTEM_ASR_BaiduASR'; +INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES +('SYSTEM_ASR_BaiduASR', 'ASR', 'baidu', '百度语音识别', '[{"key":"app_id","label":"应用AppID","type":"string"},{"key":"api_key","label":"API Key","type":"string"},{"key":"secret_key","label":"Secret Key","type":"string"},{"key":"dev_pid","label":"语言参数","type":"number"},{"key":"output_dir","label":"输出目录","type":"string"}]', 7, 1, NOW(), 1, NOW()); + + +-- 更新百度ASR配置说明 +UPDATE `ai_model_config` SET +`doc_link` = 'https://console.bce.baidu.com/ai-engine/old/#/ai/speech/app/list', +`remark` = '百度ASR配置说明: +1. 访问 https://console.bce.baidu.com/ai-engine/old/#/ai/speech/app/list +2. 创建新应用 +3. 获取AppID、API Key和Secret Key +4. 填入配置文件中 +查看资源额度:https://console.bce.baidu.com/ai-engine/old/#/ai/speech/overview/resource/list +语言参数说明:https://ai.baidu.com/ai-doc/SPEECH/0lbxfnc9b +' WHERE `id` = 'ASR_BaiduASR'; + +-- 更新豆包供应器字段 +update `ai_model_provider` set `fields` = +'[{"key":"appid","label":"应用ID","type":"string"},{"key":"access_token","label":"访问令牌","type":"string"},{"key":"cluster","label":"集群","type":"string"},{"key":"boosting_table_name","label":"热词文件名称","type":"string"},{"key":"correct_table_name","label":"替换词文件名称","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]' +where `id` = 'SYSTEM_ASR_DoubaoASR'; + +-- 更新豆包ASR配置说明 +UPDATE `ai_model_config` SET +`doc_link` = 'https://console.volcengine.com/speech/app', +`remark` = '豆包ASR配置说明: +1. 需要在火山引擎控制台创建应用并获取appid和access_token +2. 支持中文语音识别 +3. 需要网络连接 +4. 输出文件保存在tmp/目录 +申请步骤: +1. 访问 https://console.volcengine.com/speech/app +2. 创建新应用 +3. 获取appid和access_token +4. 填入配置文件中 +如需设置热词,请参考:https://www.volcengine.com/docs/6561/155738 +' WHERE `id` = 'ASR_DoubaoASR'; \ No newline at end of file diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index ffbef2ce..2936aed7 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -99,4 +99,11 @@ databaseChangeLog: changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202505022134.sql \ No newline at end of file + path: classpath:db/changelog/202505022134.sql + - changeSet: + id: 202505081146 + author: hrz + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202505081146.sql \ No newline at end of file diff --git a/main/manager-api/src/main/resources/mapper/device/DeviceDao.xml b/main/manager-api/src/main/resources/mapper/device/DeviceDao.xml new file mode 100644 index 00000000..54de47c9 --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/device/DeviceDao.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/main/manager-api/src/test/java/xiaozhi/modules/device/DeviceTest.java b/main/manager-api/src/test/java/xiaozhi/modules/device/DeviceTest.java index 8647692c..37f67cab 100644 --- a/main/manager-api/src/test/java/xiaozhi/modules/device/DeviceTest.java +++ b/main/manager-api/src/test/java/xiaozhi/modules/device/DeviceTest.java @@ -1,5 +1,8 @@ package xiaozhi.modules.device; +import java.util.HashMap; +import java.util.UUID; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -8,8 +11,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import lombok.extern.slf4j.Slf4j; -import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; +import xiaozhi.modules.sys.dto.SysUserDTO; +import xiaozhi.modules.sys.service.SysUserService; @Slf4j @SpringBootTest @@ -19,18 +23,37 @@ public class DeviceTest { @Autowired private RedisUtils redisUtils; + @Autowired + private SysUserService sysUserService; + + @Test + public void testSaveUser() { + SysUserDTO userDTO = new SysUserDTO(); + userDTO.setUsername("test"); + userDTO.setPassword(UUID.randomUUID().toString()); + sysUserService.save(userDTO); + } @Test @DisplayName("测试写入设备信息") public void testWriteDeviceInfo() { log.info("开始测试写入设备信息..."); - // 模拟设备MAC地址 - String macAddress = "00:11:22:33:44:55"; + String macAddress = "00:11:22:33:44:66"; // 模拟设备验证码 String deviceCode = "123456"; - String redisKey = RedisKeys.getDeviceCaptchaKey(deviceCode); + HashMap map = new HashMap<>(); + map.put("mac_address", macAddress); + map.put("activation_code", deviceCode); + map.put("board", "硬件型号"); + map.put("app_version", "0.3.13"); + + String safeDeviceId = macAddress.replace(":", "_").toLowerCase(); + String cacheDeviceKey = String.format("ota:activation:data:%s", safeDeviceId); + redisUtils.set(cacheDeviceKey, map, 300); + + String redisKey = "ota:activation:code:" + deviceCode; log.info("Redis Key: {}", redisKey); // 将设备信息写入Redis diff --git a/main/manager-web/src/components/AddDeviceDialog.vue b/main/manager-web/src/components/AddDeviceDialog.vue index 51f5426b..b273a8dc 100644 --- a/main/manager-web/src/components/AddDeviceDialog.vue +++ b/main/manager-web/src/components/AddDeviceDialog.vue @@ -1,5 +1,5 @@