refactor(service): 用 RestClient 重写 ElevenLabs 调用并替换 UUID 工具类
- 将手写 HttpURLConnection 改为 Spring RestClient,精简 64 行冗余代码 - 引入 RestClientConfig 统一配置 - 统一使用 Hutool 的 IdUtil 生成文件名称
This commit is contained in:
25
src/main/java/com/yolo/keyborad/config/RestClientConfig.java
Normal file
25
src/main/java/com/yolo/keyborad/config/RestClientConfig.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 + "/")
|
||||
|
||||
@@ -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<String, Object> 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<String, Object> 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<String, Object> buildRequestBody(String text) {
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("text", text);
|
||||
requestBody.put("model_id", elevenLabsProperties.getModelId());
|
||||
|
||||
// 设置语音参数
|
||||
Map<String, Object> voiceSettings = new HashMap<>();
|
||||
voiceSettings.put("stability", elevenLabsProperties.getStability());
|
||||
voiceSettings.put("similarity_boost", elevenLabsProperties.getSimilarityBoost());
|
||||
|
||||
Reference in New Issue
Block a user