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 7cadad2b..62d21ab5 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 @@ -103,4 +103,11 @@ public class RedisKeys { public static String getDictDataByTypeKey(String dictType) { return "sys:dict:data:" + dictType; } + + /** + * 获取智能体音频ID的缓存key + */ + public static String getAgentAudioIdKey(String uuid) { + return "agent:audio:id:" + uuid; + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java index cfbb107f..b6c0ac62 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java @@ -3,7 +3,9 @@ package xiaozhi.modules.agent.controller; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -28,6 +30,8 @@ import jakarta.validation.Valid; import lombok.AllArgsConstructor; import xiaozhi.common.constant.Constant; import xiaozhi.common.page.PageData; +import xiaozhi.common.redis.RedisKeys; +import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.Result; @@ -55,6 +59,7 @@ public class AgentController { private final DeviceService deviceService; private final AgentChatHistoryService agentChatHistoryService; private final AgentChatAudioService agentChatAudioService; + private final RedisUtils redisUtils; @GetMapping("/list") @Operation(summary = "获取用户智能体列表") @@ -89,7 +94,7 @@ public class AgentController { @PostMapping @Operation(summary = "创建智能体") @RequiresPermissions("sys:role:normal") - public Result save(@RequestBody @Valid AgentCreateDTO dto) { + public Result save(@RequestBody @Valid AgentCreateDTO dto) { AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class); // 获取默认模板 @@ -117,7 +122,7 @@ public class AgentController { // ID、智能体编码和排序会在Service层自动生成 agentService.insert(entity); - return new Result<>(); + return new Result().ok(entity.getId()); } @PutMapping("/{id}") @@ -235,17 +240,37 @@ public class AgentController { return new Result>().ok(result); } - @GetMapping("/audio/{audioId}") - @Operation(summary = "下载音频") + @PostMapping("/audio/{audioId}") + @Operation(summary = "获取音频下载ID") @RequiresPermissions("sys:role:normal") - public ResponseEntity downloadAudio(@PathVariable("audioId") String audioId) { + public Result getAudioId(@PathVariable("audioId") String audioId) { + byte[] audioData = agentChatAudioService.getAudio(audioId); + if (audioData == null) { + return new Result().error("音频不存在"); + } + String uuid = UUID.randomUUID().toString(); + redisUtils.set(RedisKeys.getAgentAudioIdKey(uuid), audioId); + return new Result().ok(uuid); + } + + @GetMapping("/play/{uuid}") + @Operation(summary = "播放音频") + public ResponseEntity playAudio(@PathVariable("uuid") String uuid) { + + String audioId = (String) redisUtils.get(RedisKeys.getAgentAudioIdKey(uuid)); + if (StringUtils.isBlank(audioId)) { + return ResponseEntity.notFound().build(); + } + byte[] audioData = agentChatAudioService.getAudio(audioId); if (audioData == null) { return ResponseEntity.notFound().build(); } + redisUtils.delete(RedisKeys.getAgentAudioIdKey(uuid)); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"play.wav\"") .body(audioData); } + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java index abccec0f..5252336f 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java @@ -86,6 +86,7 @@ public class ShiroConfig { // 将config路径使用server服务过滤器 filterMap.put("/config/**", "server"); filterMap.put("/agent/chat-history/report", "server"); + filterMap.put("/agent/play/**", "anon"); filterMap.put("/**", "oauth2"); shiroFilter.setFilterChainDefinitionMap(filterMap); diff --git a/main/manager-web/src/apis/module/agent.js b/main/manager-web/src/apis/module/agent.js index fd8f6cf3..8aa89072 100644 --- a/main/manager-web/src/apis/module/agent.js +++ b/main/manager-web/src/apis/module/agent.js @@ -128,19 +128,19 @@ export default { }); }).send(); }, -} - -export function getAgentSessions(agentId, params) { - return request({ - url: `/agent/${agentId}/sessions`, - method: 'get', - params - }); -} - -export function getAgentChatHistory(agentId, sessionId) { - return request({ - url: `/agent/${agentId}/chat-history/${sessionId}`, - method: 'get' - }); + // 获取音频下载ID + getAudioId(audioId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/agent/audio/${audioId}`) + .method('POST') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail(() => { + RequestService.reAjaxFun(() => { + this.getAudioId(audioId, callback); + }); + }).send(); + }, } diff --git a/main/manager-web/src/components/ChatHistoryDialog.vue b/main/manager-web/src/components/ChatHistoryDialog.vue index 4c5421cd..33350208 100644 --- a/main/manager-web/src/components/ChatHistoryDialog.vue +++ b/main/manager-web/src/components/ChatHistoryDialog.vue @@ -66,7 +66,7 @@ export default { currentSessionId: '', currentMacAddress: '', page: 1, - limit: 10, + limit: 20, loading: false, hasMore: true, scrollTimer: null, @@ -237,16 +237,21 @@ export default { this.audioElement = null; } - // 播放新音频 + // 先获取音频下载ID this.playingAudioId = message.audioId; - this.audioElement = new Audio(Api.getServiceUrl() + `/agent/audio/${message.audioId}`); + Api.agent.getAudioId(message.audioId, (res) => { + if (res.data && res.data.data) { + // 使用获取到的下载ID播放音频 + this.audioElement = new Audio(Api.getServiceUrl() + `/agent/play/${res.data.data}`); - this.audioElement.onended = () => { - this.playingAudioId = null; - this.audioElement = null; - }; + this.audioElement.onended = () => { + this.playingAudioId = null; + this.audioElement = null; + }; - this.audioElement.play(); + this.audioElement.play(); + } + }); }, getUserAvatar(sessionId) { // 从 sessionId 中提取所有数字 @@ -269,7 +274,7 @@ export default { \ No newline at end of file