From 8783a4c2af1aa22ff292a85c823393ffed33139d Mon Sep 17 00:00:00 2001 From: ziin Date: Mon, 26 Jan 2026 13:49:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(service):=20=E7=94=A8=20RestClient=20?= =?UTF-8?q?=E9=87=8D=E5=86=99=20ElevenLabs=20=E8=B0=83=E7=94=A8=E5=B9=B6?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=20UUID=20=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将手写 HttpURLConnection 改为 Spring RestClient,精简 64 行冗余代码 - 引入 RestClientConfig 统一配置 - 统一使用 Hutool 的 IdUtil 生成文件名称 --- .../keyborad/config/RestClientConfig.java | 25 ++++ .../service/impl/ChatServiceImpl.java | 2 +- .../service/impl/ElevenLabsServiceImpl.java | 120 ++++-------------- 3 files changed, 54 insertions(+), 93 deletions(-) create mode 100644 src/main/java/com/yolo/keyborad/config/RestClientConfig.java diff --git a/src/main/java/com/yolo/keyborad/config/RestClientConfig.java b/src/main/java/com/yolo/keyborad/config/RestClientConfig.java new file mode 100644 index 0000000..a223843 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/config/RestClientConfig.java @@ -0,0 +1,25 @@ +package com.yolo.keyborad.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestClient; + +/** + * RestClient 配置类 + * 提供连接池复用,优化 HTTP 请求性能 + */ +@Configuration +public class RestClientConfig { + + @Bean + public RestClient restClient() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(30000); + factory.setReadTimeout(60000); + + return RestClient.builder() + .requestFactory(factory) + .build(); + } +} diff --git a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java index 002249b..5580ce1 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java @@ -481,7 +481,7 @@ public class ChatServiceImpl implements ChatService { } byte[] audioBytes = Base64.getDecoder().decode(audioBase64); - String fileName = UUID.randomUUID() + ".mp3"; + String fileName = IdUtil.fastSimpleUUID() + ".mp3"; FileInfo fileInfo = fileStorageService.of(new ByteArrayInputStream(audioBytes)) .setPath(userId + "/") diff --git a/src/main/java/com/yolo/keyborad/service/impl/ElevenLabsServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ElevenLabsServiceImpl.java index d21ed23..8955025 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ElevenLabsServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ElevenLabsServiceImpl.java @@ -1,7 +1,6 @@ package com.yolo.keyborad.service.impl; import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.yolo.keyborad.common.ErrorCode; import com.yolo.keyborad.config.ElevenLabsProperties; @@ -10,14 +9,10 @@ import com.yolo.keyborad.model.vo.TextToSpeechVO; import com.yolo.keyborad.service.ElevenLabsService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -34,6 +29,9 @@ public class ElevenLabsServiceImpl implements ElevenLabsService { @Resource private ElevenLabsProperties elevenLabsProperties; + @Resource + private RestClient restClient; + private static final int MAX_TEXT_LENGTH = 5000; @Override @@ -43,7 +41,6 @@ public class ElevenLabsServiceImpl implements ElevenLabsService { @Override public TextToSpeechVO textToSpeechWithTimestamps(String text, String voiceId) { - // 1. 参数验证 if (StrUtil.isBlank(text)) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "文本内容不能为空"); } @@ -57,111 +54,50 @@ public class ElevenLabsServiceImpl implements ElevenLabsService { voiceId = elevenLabsProperties.getVoiceId(); } - HttpURLConnection connection = null; + String requestUrl = buildRequestUrl(voiceId); + Map requestBody = buildRequestBody(text); + + log.info("调用 ElevenLabs TTS API, voiceId: {}, 文本长度: {}", voiceId, text.length()); + long startTime = System.currentTimeMillis(); + try { - // 2. 构建请求 URL - String requestUrl = buildRequestUrl(voiceId); - URL url = new URL(requestUrl); + String responseJson = restClient.post() + .uri(requestUrl) + .contentType(MediaType.APPLICATION_JSON) + .header("xi-api-key", elevenLabsProperties.getApiKey()) + .body(requestBody) + .retrieve() + .body(String.class); - // 3. 创建连接 - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setDoOutput(true); - connection.setDoInput(true); - connection.setConnectTimeout(30000); - connection.setReadTimeout(60000); - - // 4. 设置请求头 - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("xi-api-key", elevenLabsProperties.getApiKey()); - - // 5. 构建请求体 - Map requestBody = buildRequestBody(text); - String jsonBody = JSON.toJSONString(requestBody); - - log.info("调用 ElevenLabs TTS API, voiceId: {}, 文本长度: {}", voiceId, text.length()); - long startTime = System.currentTimeMillis(); - - // 6. 发送请求 - try (OutputStream os = connection.getOutputStream()) { - byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8); - os.write(input, 0, input.length); - } - - // 7. 获取响应 - int responseCode = connection.getResponseCode(); long duration = System.currentTimeMillis() - startTime; - log.info("ElevenLabs TTS API 响应码: {}, 耗时: {}ms", responseCode, duration); + log.info("ElevenLabs TTS API 响应成功, 耗时: {}ms", duration); - if (responseCode == HttpURLConnection.HTTP_OK) { - // 读取响应 JSON - try (InputStream is = connection.getInputStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - byte[] buffer = new byte[8192]; - int bytesRead; - while ((bytesRead = is.read(buffer)) != -1) { - baos.write(buffer, 0, bytesRead); - } - String responseJson = baos.toString(StandardCharsets.UTF_8); - JSONObject jsonResponse = JSON.parseObject(responseJson); + JSONObject jsonResponse = JSONObject.parseObject(responseJson); + String audioBase64 = jsonResponse.getString("audio_base64"); - String audioBase64 = jsonResponse.getString("audio_base64"); + log.info("语音合成成功,Base64长度: {}", audioBase64.length()); - log.info("语音合成成功,Base64长度: {}", audioBase64.length()); + return TextToSpeechVO.builder() + .audioBase64(audioBase64) + .build(); - return TextToSpeechVO.builder() - .audioBase64(audioBase64) - .build(); - } - } else { - // 读取错误信息 - String errorMsg = ""; - try (InputStream es = connection.getErrorStream()) { - if (es != null) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int bytesRead; - while ((bytesRead = es.read(buffer)) != -1) { - baos.write(buffer, 0, bytesRead); - } - errorMsg = baos.toString(StandardCharsets.UTF_8); - } - } - log.error("ElevenLabs TTS API 调用失败, 状态码: {}, 错误信息: {}", responseCode, errorMsg); - throw new BusinessException(ErrorCode.SYSTEM_ERROR, "语音合成服务异常: " + responseCode); - } - - } catch (BusinessException e) { - throw e; } catch (Exception e) { log.error("调用 ElevenLabs TTS API 发生异常", e); throw new BusinessException(ErrorCode.SYSTEM_ERROR, "语音合成服务异常: " + e.getMessage()); - } finally { - if (connection != null) { - connection.disconnect(); - } } } - /** - * 构建 ElevenLabs TTS API 请求 URL(带时间戳) - */ private String buildRequestUrl(String voiceId) { - StringBuilder url = new StringBuilder(elevenLabsProperties.getBaseUrl()); - url.append("/text-to-speech/").append(voiceId).append("/with-timestamps"); - url.append("?output_format=").append(elevenLabsProperties.getOutputFormat()); - return url.toString(); + return elevenLabsProperties.getBaseUrl() + + "/text-to-speech/" + voiceId + "/with-timestamps" + + "?output_format=" + elevenLabsProperties.getOutputFormat(); } - /** - * 构建请求体 - */ private Map buildRequestBody(String text) { Map requestBody = new HashMap<>(); requestBody.put("text", text); requestBody.put("model_id", elevenLabsProperties.getModelId()); - // 设置语音参数 Map voiceSettings = new HashMap<>(); voiceSettings.put("stability", elevenLabsProperties.getStability()); voiceSettings.put("similarity_boost", elevenLabsProperties.getSimilarityBoost());