瀏覽代碼

tts繁转简

zhaohan 5 月之前
父節點
當前提交
cf12eab615

+ 2 - 2
ruoyi-admin/src/main/resources/application-prod.yml

@@ -60,7 +60,7 @@ spring.data:
     # 数据库索引
     database: 0
     # 密码(如没有密码请注释掉)
-    password: 123456
+    password: HE2WrbSzY7tjHfWj;
     # 连接超时时间
     timeout: 10S
 redisson:
@@ -118,7 +118,7 @@ mcp:
 # 大模型配置
 llm:
   # 模型名称
-  model: deepseek-r1-distill-qwen
+  model: qwen3-32B
   # 最大token数量
   max-tokens: 10240
 

+ 4 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -163,6 +163,9 @@ security:
     - /tokenRole/records/**
     - /parse/file
     - /system/ruleFinal/fetchMatchingRules
+    - /system/ruleFinal/fetchMatchingRules
+    - /chat/audio
+    - /chat/speech/proxy
 # 多租户配置
 tenant:
   # 是否开启
@@ -315,7 +318,7 @@ spring:
   ai:
     openai:
       api-key: sk-9m5gDHBajkqZw4uuC92c5f686f5e4bEc8fA6858dD6115357
-      base-url: https://api.pandarobot.chat/
+      base-url: http://60.164.133.40:19997/
     mcp:
       client:
         enabled: false

+ 17 - 2
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java

@@ -443,8 +443,23 @@ public class OpenAiStreamClient {
         if (Objects.nonNull(transcriptions.getTemperature())) {
             requestBodyMap.put(Transcriptions.Fields.temperature, RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(transcriptions.getTemperature())));
         }
-        Single<WhisperResponse> whisperResponse = this.openAiApi.speechToTextTranscriptions(multipartBody, requestBodyMap);
-        return whisperResponse.blockingGet();
+        try {
+            Single<WhisperResponse> whisperResponse = this.openAiApi.speechToTextTranscriptions(multipartBody, requestBodyMap);
+            return whisperResponse.blockingGet();
+        } catch (Exception e) {
+            log.error("语音转文本API调用失败 - 详细错误信息: {}", e.getMessage(), e);
+            // 如果是HttpException,尝试获取响应体
+            if (e instanceof retrofit2.adapter.rxjava2.HttpException) {
+                retrofit2.adapter.rxjava2.HttpException httpException = (retrofit2.adapter.rxjava2.HttpException) e;
+                try {
+                    String errorBody = httpException.response().errorBody().string();
+                    log.error("API错误响应体: {}", errorBody);
+                } catch (Exception ex) {
+                    log.error("无法读取错误响应体: {}", ex.getMessage());
+                }
+            }
+            throw e;
+        }
     }
 
     /**

+ 6 - 0
ruoyi-modules/ruoyi-chat/pom.xml

@@ -124,6 +124,12 @@
             <artifactId>ruoyi-system-api</artifactId>
         </dependency>
 
+        <!-- OpenCC4J 简繁转换库 -->
+        <dependency>
+            <groupId>com.github.houbb</groupId>
+            <artifactId>opencc4j</artifactId>
+            <version>1.7.2</version>
+        </dependency>
 
     </dependencies>
 

+ 66 - 2
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java

@@ -28,6 +28,7 @@ import org.ruoyi.common.core.utils.DateUtils;
 import org.ruoyi.common.core.utils.StringUtils;
 import org.ruoyi.common.core.utils.file.FileUtils;
 import org.ruoyi.common.core.utils.file.MimeTypeUtils;
+import com.github.houbb.opencc4j.util.ZhConverterUtil;
 import org.ruoyi.common.satoken.utils.LoginHelper;
 import org.ruoyi.common.core.service.ConfigService;
 import org.ruoyi.core.page.PageQuery;
@@ -111,7 +112,7 @@ public class SseServiceImpl implements ISseService {
 
     private String rerankModelName = "bge-reranker-v2-m3";
 
-    private static final String DEFAULT_TTS_PROXY_URL = "http://1.13.255.120:7899/v1/audio/speech";
+    private static final String DEFAULT_TTS_PROXY_URL = "http://8.136.61.90:7899/v1/audio/speech";
     private static final String DEFAULT_TTS_VOICE = "zh-CN-XiaoxiaoNeural";
 
     @Override
@@ -460,8 +461,26 @@ public class SseServiceImpl implements ISseService {
         }
         Transcriptions transcriptions = Transcriptions.builder()
                 .model(resolveAudioModel())
+                .language(resolveAudioLanguage())
+                .prompt(resolveAudioPrompt())
                 .build();
-        return openAiStreamClient.speechToTextTranscriptions(fileA, transcriptions);
+
+        log.info("语音转文本API调用参数 - 模型: {}, 语言: {}, 提示词: {}",
+                 transcriptions.getModel(), transcriptions.getLanguage(), transcriptions.getPrompt());
+
+        WhisperResponse response = openAiStreamClient.speechToTextTranscriptions(fileA, transcriptions);
+
+        // 转换繁体为简体
+        if (response != null && response.getText() != null) {
+            String originalText = response.getText();
+            String convertedText = convertToSimplifiedChinese(originalText);
+            if (!convertedText.equals(originalText)) {
+                log.info("语音转文本检测到繁体中文,已转换为简体 - 原文本: {}, 转换后: {}", originalText, convertedText);
+                response.setText(convertedText);
+            }
+        }
+
+        return response;
     }
 
     private String resolveAudioModel() {
@@ -477,6 +496,31 @@ public class SseServiceImpl implements ISseService {
         return defaultModel;
     }
 
+    private String resolveAudioLanguage() {
+        String defaultLanguage = "mandarin"; // 使用API支持的语言名称
+        try {
+            String audioLanguage = configService.getConfigValue("chat", "audioLanguage");
+            if (StringUtils.isNotBlank(audioLanguage)) {
+                return audioLanguage;
+            }
+        } catch (Exception e) {
+            log.warn("音频语言配置获取失败,使用默认语言 {} :{}", defaultLanguage, e.getMessage());
+        }
+        return defaultLanguage;
+    }
+
+    private String resolveAudioPrompt() {
+        String defaultPrompt = "请将语音转换为简体中文。使用现代标准汉语,避免繁体字。"; // 引导输出简体中文
+        try {
+            String audioPrompt = configService.getConfigValue("chat", "audioPrompt");
+            if (StringUtils.isNotBlank(audioPrompt)) {
+                return audioPrompt;
+            }
+        } catch (Exception e) {
+            log.warn("音频提示词配置获取失败,使用默认提示词:{}", e.getMessage());
+        }
+        return defaultPrompt;
+    }
 
     @Override
     public UploadFileResponse upload(MultipartFile file) {
@@ -759,4 +803,24 @@ public class SseServiceImpl implements ISseService {
         return thinkProjectMapper.insertProject(map);
     }
 
+    /**
+     * 将繁体中文转换为简体中文
+     * 使用opencc4j库进行专业的简繁转换
+     * @param text 输入文本
+     * @return 转换后的简体中文文本
+     */
+    private String convertToSimplifiedChinese(String text) {
+        if (text == null || text.isEmpty()) {
+            return text;
+        }
+
+        try {
+            // 使用opencc4j进行繁体到简体的转换
+            return ZhConverterUtil.toSimple(text);
+        } catch (Exception e) {
+            log.warn("语音转文本简繁转换失败,使用原文: {}", e.getMessage());
+            return text;
+        }
+    }
+
 }