From 77527d882357d056ed76222d3e591b0fedc414ed Mon Sep 17 00:00:00 2001 From: JianYu Zheng <2375294554@qq.com> Date: Fri, 4 Jul 2025 18:04:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=99=BA=E8=83=BD=E4=BD=93?= =?UTF-8?q?=E5=A3=B0=E7=BA=B9=E6=9C=8D=E5=8A=A1=E5=B1=82=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=9A=84=E2=80=98=E6=B7=BB=E5=8A=A0=E6=99=BA=E8=83=BD=E4=BD=93?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E5=A3=B0=E7=BA=B9=E2=80=99=E5=92=8C=E2=80=98?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=99=BA=E8=83=BD=E4=BD=93=E7=9A=84=E6=8C=87?= =?UTF-8?q?=E7=9A=84=E5=A3=B0=E7=BA=B9=E2=80=99=E5=AE=9A=E4=B9=89=20--Agen?= =?UTF-8?q?tVoicePrintServiceImpl.java=20=E5=AE=9E=E7=8E=B0=E6=96=B9?= =?UTF-8?q?=E6=B3=95=20=201.=E6=B7=BB=E5=8A=A0=E6=99=BA=E8=83=BD=E4=BD=93?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E5=A3=B0=E7=BA=B9=20=202.=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E4=BD=93=E7=9A=84=E6=8C=87=E7=9A=84=E5=A3=B0?= =?UTF-8?q?=E7=BA=B9=20=203.=E5=85=B1=E7=94=A8=E6=96=B9=E6=B3=95=EF=BC=88?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E7=94=9F=E7=BA=B9=E6=8E=A5=E5=8F=A3URI?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=EF=BC=8C=E8=8E=B7=E5=8F=96=E5=A3=B0=E7=BA=B9?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E5=9F=BA=E7=A1=80=E8=B7=AF=E5=BE=84=EF=BC=8C?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E9=AA=8C=E8=AF=81Authorization=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/AgentVoicePrintServiceImpl.java | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentVoicePrintServiceImpl.java diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentVoicePrintServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentVoicePrintServiceImpl.java new file mode 100644 index 00000000..974d4aa9 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentVoicePrintServiceImpl.java @@ -0,0 +1,178 @@ +package xiaozhi.modules.agent.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import xiaozhi.common.constant.Constant; +import xiaozhi.common.exception.RenException; +import xiaozhi.common.utils.ConvertUtils; +import xiaozhi.modules.agent.dao.AgentVoicePrintDao; +import xiaozhi.modules.agent.dto.AgentVoicePrintSaveDTO; +import xiaozhi.modules.agent.dto.AgentVoicePrintUpdateDTO; +import xiaozhi.modules.agent.entity.AgentVoicePrintEntity; +import xiaozhi.modules.agent.service.AgentChatAudioService; +import xiaozhi.modules.agent.service.AgentVoicePrintService; +import xiaozhi.modules.agent.vo.AgentVoicePrintVO; +import xiaozhi.modules.sys.service.SysParamsService; + +import java.beans.Transient; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +/** + * @author zjy + */ +@Service +@AllArgsConstructor +@Slf4j +public class AgentVoicePrintServiceImpl extends ServiceImpl + implements AgentVoicePrintService { + private final AgentChatAudioService agentChatAudioService; + private final RestTemplate restTemplate; + private final SysParamsService sysParamsService; + + + @Override + @Transient + public boolean insert(AgentVoicePrintSaveDTO dto) { + // 获取音频Id + String audioId = dto.getAudioId(); + // 获取到音频数据 + byte[] audio = agentChatAudioService.getAudio(audioId); + // 如果音频数据为空的直接报错不进行下去 + if (audio == null || audio.length == 0) { + throw new RenException("音频数据是空的请检查上传数据"); + } + // 将字节数组包装为资源,并添加到请求体 + ByteArrayResource resource = new ByteArrayResource(audio) { + @Override + public String getFilename() { + return "VoicePrint.WAV"; // 设置文件名 + } + }; + + // 处理声纹接口地址,获取前缀 + URI uri = getVoicePrintURI(); + String baseUrl = getBaseUrl(uri); + String requestUrl = baseUrl + "/voiceprint/register"; + + // 保存声纹信息 + AgentVoicePrintEntity entity = ConvertUtils.sourceToTarget(dto, AgentVoicePrintEntity.class); + int insert = baseMapper.insert(entity); + if(insert != 1){ + throw new RenException("声纹保存失败"); + } + // 创建请求体 + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("speaker_id", entity.getId()); + body.add("file", resource); + + // 创建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", getAuthorization(uri)); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + // 创建请求体 + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + // 发送 POST 请求 + ResponseEntity response = restTemplate.postForEntity(requestUrl, requestEntity, String.class); + + if (response.getStatusCode() != HttpStatus.OK) { + throw new RenException("声纹保存失败"); + } + // 检查响应内容 + String responseBody = response.getBody(); + if(responseBody == null || !responseBody.contains("true")){ + throw new RenException("声纹保存失败"); + } + return true; + } + + + + @Override + public boolean delete(String voicePrintId) { + int insert = baseMapper.deleteById(voicePrintId); + if(insert != 1){ + throw new RenException("声纹删除失败"); + } + URI uri = getVoicePrintURI(); + String baseUrl = getBaseUrl(uri); + String requestUrl = baseUrl + "/voiceprint/" + voicePrintId; + // 创建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", getAuthorization(uri)); + // 创建请求体 + HttpEntity> requestEntity = new HttpEntity<>(headers); + + // 发送 POST 请求 + ResponseEntity response = restTemplate.exchange(requestUrl, HttpMethod.DELETE, requestEntity, String.class); + if (response.getStatusCode() != HttpStatus.OK) { + throw new RenException("声纹保存失败"); + } + // 检查响应内容 + String responseBody = response.getBody(); + if(responseBody == null || !responseBody.contains("true")){ + throw new RenException("声纹保存失败"); + } + return true; + } + + @Override + public List list(String agentId) { + return List.of(); + } + + @Override + public boolean update(AgentVoicePrintUpdateDTO dto) { + return false; + } + + /** + * 获取生纹接口URI对象 + * + * @return URI对象 + */ + private URI getVoicePrintURI() { + // 获取声纹接口地址 + String voicePrint = sysParamsService.getValue(Constant.SERVER_VOICE_PRINT, true); + try { + return new URI(voicePrint); + } catch (URISyntaxException e) { + log.error("路径格式不正确路径:{},\n错误信息:{}", voicePrint, e.getMessage()); + throw new RuntimeException("声纹接口的地址存在错误,请进入参数管理修改声纹接口地址"); + } + } + + /** + * 获取声纹地址基础路径 + * @param uri 声纹地址uri + * @return 基础路径 + */ + private String getBaseUrl(URI uri) { + String protocol = uri.getScheme(); + String host = uri.getHost(); + int port = uri.getPort(); + return "%s://%s:%s".formatted(protocol,host,port); + } + + /** + * 获取验证Authorization + * + * @param uri 声纹地址uri + * @return Authorization值 + */ + private String getAuthorization(URI uri) { + // 获取参数 + String query = uri.getQuery(); + // 获取aes加密密钥 + String str = "key="; + return "Bearer " + query.substring(query.indexOf(str) + str.length()); + } +}