소스 검색

1、更改ai对话实例,每次注入都是新的
2、ai实验室功能调取已登录用户id
3、去除前台功能的免登录、免租户注解

liyanbo 8 달 전
부모
커밋
6a5032c968

+ 23 - 10
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/service/chat/AiChatMessageServiceImpl.java

@@ -42,6 +42,7 @@ import org.springframework.ai.chat.model.ChatResponse;
 import org.springframework.ai.chat.model.StreamingChatModel;
 import org.springframework.ai.chat.prompt.ChatOptions;
 import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import reactor.core.publisher.DirectProcessor;
@@ -55,6 +56,7 @@ import java.util.*;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -99,8 +101,12 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
     private AiKnowledgeDocumentService knowledgeDocumentService;
     @Resource
     private AiToolService toolService;
+//    @Resource
+//    private StreamTtsService streamTtsService;  // 注入TTS服务
+    // 在AiChatMessageServiceImpl中注入
     @Resource
-    private StreamTtsService streamTtsService;  // 注入TTS服务
+    private ObjectProvider<StreamTtsService> streamTtsServiceProvider;  // 使用ObjectProvider获取原型bean
+
     @Resource
     private AiTtsMapper ttsMapper;
 
@@ -190,6 +196,12 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
 
         // 创建一个Processor用于合并文本和音频流
         // 创建一个共享的响应对象
+        // 4.3 初始化TTS服务 - 创建新的实例而非使用共享实例
+
+        // 在sendChatMessageStream方法中获取实例
+        StreamTtsService streamTtsService = streamTtsServiceProvider.getObject();
+        streamTtsService.startTts(aiTtsDO);
+
         AtomicReference<CommonResult<AiChatMessageSendRespVO>> sharedResponse = new AtomicReference<>();
 
         DirectProcessor<CommonResult<AiChatMessageSendRespVO>> processor = DirectProcessor.create();
@@ -202,7 +214,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
         StringBuffer contentBuffer = new StringBuffer();
         StringBuffer contentTTSBuffer = new StringBuffer();
         // 添加句子结束符正则表达式
-        Pattern sentencePattern = Pattern.compile("[。!?;\n\r]"); // 增加换行符支持
+        Pattern sentencePattern = Pattern.compile("[。!?;\n\r]"); // 增加换行符支持
 
         ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
         AtomicReference<ScheduledFuture<?>> ttsTask = new AtomicReference<>();
@@ -233,14 +245,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
                 ttsTask.get().cancel(false); // 取消之前的延迟任务
             }
             // 延迟500ms执行,合并短时间内到达的文本片段
-//            ttsTask.set(scheduler.schedule(() -> {
+            ttsTask.set(scheduler.schedule(() -> {
                 Matcher matcher = sentencePattern.matcher(contentTTSBuffer);
                 if (matcher.find()) {
-                    processCompleteSentence(contentTTSBuffer, matcher);
+                    processCompleteSentence(streamTtsService, contentTTSBuffer, matcher);
                 } else if (contentTTSBuffer.length() > 20) { // 最长20字未结束也处理
-                    processCompleteSentence(contentTTSBuffer, contentTTSBuffer.length());
+                    processCompleteSentence(streamTtsService, contentTTSBuffer, contentTTSBuffer.length());
                 }
-//            }, 500, TimeUnit.MILLISECONDS));
+            }, 500, TimeUnit.MILLISECONDS));
 
             CommonResult<AiChatMessageSendRespVO> result = success(new AiChatMessageSendRespVO()
                     .setEventType("TEXT")
@@ -251,7 +263,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
             return result;
         }).doOnComplete(() -> {
 
-            processRemainingText(contentTTSBuffer); // 处理剩余文本
+            processRemainingText(streamTtsService, contentTTSBuffer); // 处理剩余文本
 
             // 忽略租户,因为 Flux 异步无法透传租户
             TenantUtils.executeIgnore(() -> chatMessageMapper.updateById(
@@ -283,6 +295,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
         // ==== 添加finally块清理 ====
         .doFinally(signalType -> {
             streamTtsService.setAudioDataCallback(null);
+
         }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR)));
 
         // 创建音频流
@@ -318,7 +331,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
     }
 
     // 处理完整句子
-    private void processCompleteSentence(StringBuffer buffer, Matcher matcher) {
+    private void processCompleteSentence(StreamTtsService streamTtsService, StringBuffer buffer, Matcher matcher) {
         String sentence = buffer.substring(0, matcher.end());
         System.out.println("==============[处理完整句子[[buffer: " + sentence);
         streamTtsService.sendText(sentence);
@@ -327,7 +340,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
     }
 
     // 处理指定长度文本
-    private void processCompleteSentence(StringBuffer buffer, int length) {
+    private void processCompleteSentence(StreamTtsService streamTtsService, StringBuffer buffer, int length) {
         String sentence = buffer.substring(0, length);
         System.out.println("==============[处理指定长度文本[[buffer: " + sentence);
         streamTtsService.sendText(sentence);
@@ -336,7 +349,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
     }
 
     // 处理剩余文本
-    private void processRemainingText(StringBuffer buffer) {
+    private void processRemainingText(StreamTtsService streamTtsService, StringBuffer buffer) {
         if (!buffer.isEmpty()) {
             System.out.println("TTS合成剩余文本: " + buffer);
             streamTtsService.sendText(buffer.toString());

+ 10 - 3
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/util/tts/StreamTtsService.java

@@ -10,8 +10,11 @@ import com.alibaba.nls.client.protocol.tts.StreamInputTtsListener;
 import com.alibaba.nls.client.protocol.tts.StreamInputTtsResponse;
 import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Service;
 
 import java.io.IOException;
@@ -20,6 +23,7 @@ import java.util.function.Consumer;
 
 @Service
 @Slf4j
+@Scope("prototype")  // 原型作用域,每次注入都会创建新实例
 public class StreamTtsService {
 
     @Value("${ai.tts.appKey:4SUOF4LfaU7FekyW}")
@@ -77,15 +81,17 @@ public class StreamTtsService {
             throw new RuntimeException("创建TTS实例", e);
         }
         synthesizer.setAppKey(appKey);
-        synthesizer.setFormat(OutputFormatEnum.PCM);
-        synthesizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_24K);
+        synthesizer.setFormat(OutputFormatEnum.PCM); // 确保输出PCM格式
+        synthesizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_24K); // 24000Hz采样率
         synthesizer.setVoice(aiTtsDO.getModel());
         synthesizer.setVolume(aiTtsDO.getVolume());
         synthesizer.setPitchRate(aiTtsDO.getPitchRate());
         synthesizer.setSpeechRate(aiTtsDO.getSpeechRate());
-//        synthesizer.setSplitText(true); // 如有类似配置需设为false
+        // ==== 启用文本拆分禁用配置 ====
+//        synthesizer.setSplitText(false); // 禁用文本自动拆分
 //        synthesizer.setEnableSplit(false); // 禁用文本拆分,确保整句合成
 
+
         try {
             synthesizer.startStreamInputTts();
         } catch (Exception e) {
@@ -212,4 +218,5 @@ public class StreamTtsService {
     public void setOnCompleteCallback(Runnable callback) {
         this.onCompleteCallback = callback;
     }
+
 }

+ 5 - 10
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/ai/WebAiController.java

@@ -50,19 +50,14 @@ public class WebAiController {
     @Resource
     private AiChatRoleService chatRoleService;
     
-    private Long userId = 1L;
-
-
     // ================ 智能问答 ================
 
     @Operation(summary = "创建智能问答")
     @PostMapping("/create-dialogue")
     public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
-        return success(chatConversationService.createChatConversationMy(createReqVO, userId));
+        return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId()));
     }
 
-//    @PermitAll
-//    @TenantIgnore
 //    @Operation(summary = "智能问答-获得智能问答列表")
 //    @GetMapping("/dialogue-list")
 //    public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() {
@@ -73,7 +68,7 @@ public class WebAiController {
     @Operation(summary = "智能问答-发送消息(流式)", description = "流式返回,响应较快")
     @PostMapping(value = "/dialogue-send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
     public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
-        return chatMessageService.sendChatMessageStream(sendReqVO, userId);
+        return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId());
     }
 
     // ================ 绘图管理 ================
@@ -81,14 +76,14 @@ public class WebAiController {
     @Operation(summary = "生成图片")
     @PostMapping("/create-painting")
     public CommonResult<Long> drawImage(@Valid @RequestBody AiImageDrawReqVO drawReqVO) {
-        return success(imageService.drawImage(userId, drawReqVO));
+        return success(imageService.drawImage(getLoginUserId(), drawReqVO));
     }
 
     @GetMapping("/painting-get-my")
     @Operation(summary = "绘画-获取绘图记录")
     public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) {
         AiImageDO image = imageService.getImage(id);
-        if (image == null || ObjUtil.notEqual(userId, image.getUserId())) {
+        if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) {
             return success(null);
         }
         return success(BeanUtils.toBean(image, AiImageRespVO.class));
@@ -107,7 +102,7 @@ public class WebAiController {
     @GetMapping("/selectRoleModel")
     @Operation(summary = "获得聊天角色分页")
     public CommonResult<PageResult<WebAiChatRoleVO>> selectRoleModel(@Valid AiChatRolePageReqVO pageReqVO) {
-        PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, userId);
+        PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, getLoginUserId());
         return success(BeanUtils.toBean(pageResult, WebAiChatRoleVO.class));
     }
 }

+ 0 - 2
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/WebQuestionnaireController.java

@@ -48,8 +48,6 @@ public class WebQuestionnaireController {
         return success(webQuestionnaireShowVo);
     }
 
-    @PermitAll
-    @TenantIgnore
     @PostMapping("/saveQuestionResult")
     @Operation(summary = "保存试卷结果")
     public CommonResult<Boolean> saveQuestionResult(@Valid @RequestBody WebQuestionnaireResultVo questionnaireResultVo) {

+ 0 - 4
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/reportprogress/WebReportProgressController.java

@@ -31,8 +31,6 @@ public class WebReportProgressController {
     @Resource
     private WebReportProgressServiceImpl progressService;
 
-    @PermitAll
-    @TenantIgnore
     @PostMapping("/saveReportProgress")
     @Operation(summary = "保存评估报告进度")
     public CommonResult<Boolean> saveReportProgress(@Valid @RequestBody WebReportProgressDO reportProgressDO) {
@@ -47,8 +45,6 @@ public class WebReportProgressController {
         return success(true);
     }
 
-    @PermitAll
-    @TenantIgnore
     @GetMapping("/getReportProgress")
     @Operation(summary = "取评估报告进度")
     public WebReportProgressVO getReportProgress(@Valid WebReportProgressDO reportProgressDO) {