Commit 5579620140c7036c35bf270b2ca40ba98a7de7b7
1 parent
708d66e8
【优化】聊天 event stream 改为 flex 返回更加的优雅
Showing
8 changed files
with
70 additions
and
108 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/Utf8SseEmitter.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.controller; | |
| 2 | - | |
| 3 | -import org.springframework.http.HttpHeaders; | |
| 4 | -import org.springframework.http.MediaType; | |
| 5 | -import org.springframework.http.server.ServerHttpResponse; | |
| 6 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | |
| 7 | - | |
| 8 | -import java.nio.charset.StandardCharsets; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 解决中文乱码 | |
| 12 | - * | |
| 13 | - * @author fansili | |
| 14 | - * @time 2024/4/14 15:13 | |
| 15 | - * @since 1.0 | |
| 16 | - */ | |
| 17 | -public class Utf8SseEmitter extends SseEmitter { | |
| 18 | - | |
| 19 | - @Override | |
| 20 | - protected void extendResponse(ServerHttpResponse outputMessage) { | |
| 21 | - super.extendResponse(outputMessage); | |
| 22 | - | |
| 23 | - HttpHeaders headers = outputMessage.getHeaders(); | |
| 24 | - headers.setContentType(new MediaType(MediaType.TEXT_EVENT_STREAM, StandardCharsets.UTF_8)); | |
| 25 | - } | |
| 26 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.chat; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 5 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; |
| 6 | -import cn.iocoder.yudao.module.ai.service.AiChatService; | |
| 7 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; |
| 6 | +import cn.iocoder.yudao.module.ai.service.AiChatService; | |
| 8 | 7 | import io.swagger.v3.oas.annotations.Operation; |
| 9 | 8 | import io.swagger.v3.oas.annotations.Parameter; |
| 10 | 9 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -13,7 +12,7 @@ import lombok.extern.slf4j.Slf4j; |
| 13 | 12 | import org.springframework.http.MediaType; |
| 14 | 13 | import org.springframework.validation.annotation.Validated; |
| 15 | 14 | import org.springframework.web.bind.annotation.*; |
| 16 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | |
| 15 | +import reactor.core.publisher.Flux; | |
| 17 | 16 | |
| 18 | 17 | import java.util.List; |
| 19 | 18 | |
| ... | ... | @@ -39,10 +38,8 @@ public class AiChatMessageController { |
| 39 | 38 | // TODO @fan:要不要使用 Flux 来返回;可以使用 Flux<AiChatMessageRespVO> |
| 40 | 39 | @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") |
| 41 | 40 | @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) |
| 42 | - public SseEmitter sendMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { | |
| 43 | - Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); | |
| 44 | - chatService.chatStream(sendReqVO, sseEmitter); | |
| 45 | - return sseEmitter; | |
| 41 | + public Flux<AiChatMessageRespVO> sendMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { | |
| 42 | + return chatService.chatStream(sendReqVO); | |
| 46 | 43 | } |
| 47 | 44 | |
| 48 | 45 | @Operation(summary = "获得指定会话的消息列表") | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.image; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 5 | -import cn.iocoder.yudao.module.ai.service.AiImageService; | |
| 6 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReq; |
| 7 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq; |
| 6 | +import cn.iocoder.yudao.module.ai.service.AiImageService; | |
| 8 | 7 | import io.swagger.v3.oas.annotations.Operation; |
| 9 | 8 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 10 | 9 | import lombok.AllArgsConstructor; |
| ... | ... | @@ -14,7 +13,6 @@ import org.springframework.web.bind.annotation.PostMapping; |
| 14 | 13 | import org.springframework.web.bind.annotation.RequestBody; |
| 15 | 14 | import org.springframework.web.bind.annotation.RequestMapping; |
| 16 | 15 | import org.springframework.web.bind.annotation.RestController; |
| 17 | -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | |
| 18 | 16 | |
| 19 | 17 | // TODO @芋艿:整理接口定义 |
| 20 | 18 | /** |
| ... | ... | @@ -35,10 +33,11 @@ public class AiImageController { |
| 35 | 33 | |
| 36 | 34 | @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!") |
| 37 | 35 | @PostMapping("/dallDrawing") |
| 38 | - public SseEmitter dallDrawing(@Validated @RequestBody AiImageDallDrawingReq req) { | |
| 39 | - Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); | |
| 40 | - aiImageService.dallDrawing(req, sseEmitter); | |
| 41 | - return sseEmitter; | |
| 36 | + public void dallDrawing(@Validated @RequestBody AiImageDallDrawingReq req) { | |
| 37 | +// Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); | |
| 38 | +// aiImageService.dallDrawing(req, sseEmitter); | |
| 39 | +// return sseEmitter; | |
| 40 | + | |
| 42 | 41 | } |
| 43 | 42 | |
| 44 | 43 | @Operation(summary = "midjourney", description = "midjourney图片绘画流程:1、提交任务 2、获取完成的任务 3、选择对应功能 4、获取最终结果") | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatService.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.service; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 4 | 3 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; |
| 5 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; |
| 5 | +import reactor.core.publisher.Flux; | |
| 6 | 6 | |
| 7 | 7 | import java.util.List; |
| 8 | 8 | |
| ... | ... | @@ -26,11 +26,10 @@ public interface AiChatService { |
| 26 | 26 | /** |
| 27 | 27 | * chat stream |
| 28 | 28 | * |
| 29 | - * @param req | |
| 30 | - * @param sseEmitter | |
| 29 | + * @param sendReqVO | |
| 31 | 30 | * @return |
| 32 | 31 | */ |
| 33 | - void chatStream(AiChatMessageSendReqVO req, Utf8SseEmitter sseEmitter); | |
| 32 | + Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendReqVO sendReqVO); | |
| 34 | 33 | |
| 35 | 34 | /** |
| 36 | 35 | * 获取 - 获取对话 message list | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiImageService.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.service; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 4 | 3 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReq; |
| 5 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq; |
| 6 | 5 | |
| ... | ... | @@ -17,9 +16,8 @@ public interface AiImageService { |
| 17 | 16 | * ai绘画 - dall2/dall3 绘画 |
| 18 | 17 | * |
| 19 | 18 | * @param req |
| 20 | - * @param sseEmitter | |
| 21 | 19 | */ |
| 22 | - void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter); | |
| 20 | + void dallDrawing(AiImageDallDrawingReq req); | |
| 23 | 21 | |
| 24 | 22 | /** |
| 25 | 23 | * midjourney 图片生成 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java
| ... | ... | @@ -9,7 +9,6 @@ import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; |
| 9 | 9 | import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; |
| 10 | 10 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 11 | 11 | import cn.iocoder.yudao.module.ai.config.AiChatClientFactory; |
| 12 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 13 | 12 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; |
| 14 | 13 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; |
| 15 | 14 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; |
| ... | ... | @@ -25,13 +24,12 @@ import cn.iocoder.yudao.module.ai.service.AiChatRoleService; |
| 25 | 24 | import cn.iocoder.yudao.module.ai.service.AiChatService; |
| 26 | 25 | import lombok.AllArgsConstructor; |
| 27 | 26 | import lombok.extern.slf4j.Slf4j; |
| 28 | -import org.springframework.http.MediaType; | |
| 29 | 27 | import org.springframework.stereotype.Service; |
| 30 | 28 | import org.springframework.transaction.annotation.Transactional; |
| 31 | 29 | import reactor.core.publisher.Flux; |
| 32 | 30 | |
| 33 | -import java.io.IOException; | |
| 34 | 31 | import java.util.List; |
| 32 | +import java.util.concurrent.atomic.AtomicInteger; | |
| 35 | 33 | import java.util.function.Consumer; |
| 36 | 34 | |
| 37 | 35 | /** |
| ... | ... | @@ -76,6 +74,7 @@ public class AiChatServiceImpl implements AiChatService { |
| 76 | 74 | chatModal.getModel(), chatModal.getId(), req.getContent(), |
| 77 | 75 | null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); |
| 78 | 76 | String content = null; |
| 77 | + int tokens = 0; | |
| 79 | 78 | try { |
| 80 | 79 | // 创建 chat 需要的 Prompt |
| 81 | 80 | Prompt prompt = new Prompt(req.getContent()); |
| ... | ... | @@ -87,6 +86,7 @@ public class AiChatServiceImpl implements AiChatService { |
| 87 | 86 | ChatClient chatClient = aiChatClientFactory.getChatClient(platformEnum); |
| 88 | 87 | ChatResponse call = chatClient.call(prompt); |
| 89 | 88 | content = call.getResult().getOutput().getContent(); |
| 89 | + tokens = call.getResults().size(); | |
| 90 | 90 | // 更新 conversation |
| 91 | 91 | } catch (Exception e) { |
| 92 | 92 | content = ExceptionUtil.getMessage(e); |
| ... | ... | @@ -94,7 +94,7 @@ public class AiChatServiceImpl implements AiChatService { |
| 94 | 94 | // 保存 chat message |
| 95 | 95 | insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(), |
| 96 | 96 | chatModal.getModel(), chatModal.getId(), content, |
| 97 | - null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); | |
| 97 | + tokens, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); | |
| 98 | 98 | } |
| 99 | 99 | return new AiChatMessageRespVO().setContent(content); |
| 100 | 100 | } |
| ... | ... | @@ -123,8 +123,7 @@ public class AiChatServiceImpl implements AiChatService { |
| 123 | 123 | return insertChatMessageDO; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | - @Override | |
| 127 | - public void chatStream(AiChatMessageSendReqVO req, Utf8SseEmitter sseEmitter) { | |
| 126 | + public Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendReqVO req) { | |
| 128 | 127 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 129 | 128 | // 查询对话 |
| 130 | 129 | AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(req.getConversationId()); |
| ... | ... | @@ -145,46 +144,42 @@ public class AiChatServiceImpl implements AiChatService { |
| 145 | 144 | // req.setTopP(req.getTopP()); |
| 146 | 145 | // req.setTemperature(req.getTemperature()); |
| 147 | 146 | // 保存 chat message |
| 148 | - // 保存 chat message | |
| 149 | 147 | insertChatMessage(conversation.getId(), MessageType.USER, loginUserId, conversation.getRoleId(), |
| 150 | 148 | chatModal.getModel(), chatModal.getId(), req.getContent(), |
| 151 | 149 | null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); |
| 152 | - | |
| 153 | 150 | // 获取 client 类型 |
| 154 | 151 | AiPlatformEnum platformEnum = AiPlatformEnum.valueOfPlatform(chatModal.getPlatform()); |
| 155 | 152 | StreamingChatClient streamingChatClient = aiChatClientFactory.getStreamingChatClient(platformEnum); |
| 156 | 153 | Flux<ChatResponse> streamResponse = streamingChatClient.stream(prompt); |
| 157 | - | |
| 154 | + // 转换 flex AiChatMessageRespVO | |
| 158 | 155 | StringBuffer contentBuffer = new StringBuffer(); |
| 159 | - streamResponse.subscribe( | |
| 160 | - new Consumer<ChatResponse>() { | |
| 161 | - @Override | |
| 162 | - public void accept(ChatResponse chatResponse) { | |
| 163 | - String content = chatResponse.getResults().get(0).getOutput().getContent(); | |
| 164 | - try { | |
| 165 | - contentBuffer.append(content); | |
| 166 | - sseEmitter.send(new AiChatMessageRespVO().setContent(content), MediaType.APPLICATION_JSON); | |
| 167 | - } catch (IOException e) { | |
| 168 | - log.error("发送异常{}", ExceptionUtil.getMessage(e)); | |
| 169 | - // 如果不是因为关闭而抛出异常,则重新连接 | |
| 170 | - sseEmitter.completeWithError(e); | |
| 171 | - } | |
| 172 | - } | |
| 173 | - }, | |
| 174 | - error -> { | |
| 175 | - // | |
| 176 | - log.error("subscribe错误 {}", ExceptionUtil.getMessage(error)); | |
| 177 | - }, | |
| 178 | - () -> { | |
| 179 | - log.info("发送完成!"); | |
| 180 | - sseEmitter.complete(); | |
| 181 | - // 保存 chat message | |
| 182 | - insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(), | |
| 183 | - chatModal.getModel(), chatModal.getId(), contentBuffer.toString(), | |
| 184 | - null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); | |
| 185 | - | |
| 156 | + AtomicInteger tokens = new AtomicInteger(0); | |
| 157 | + return streamResponse.map(res -> { | |
| 158 | + AiChatMessageRespVO aiChatMessageRespVO = new AiChatMessageRespVO(); | |
| 159 | + aiChatMessageRespVO.setContent(res.getResult().getOutput().getContent()); | |
| 160 | + contentBuffer.append(res.getResult().getOutput().getContent()); | |
| 161 | + tokens.incrementAndGet(); | |
| 162 | + return aiChatMessageRespVO; | |
| 186 | 163 | } |
| 187 | - ); | |
| 164 | + ).doOnComplete(new Runnable() { | |
| 165 | + @Override | |
| 166 | + public void run() { | |
| 167 | + log.info("发送完成!"); | |
| 168 | + // 保存 chat message | |
| 169 | + insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(), | |
| 170 | + chatModal.getModel(), chatModal.getId(), contentBuffer.toString(), | |
| 171 | + tokens.get(), conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); | |
| 172 | + } | |
| 173 | + }).doOnError(new Consumer<Throwable>() { | |
| 174 | + @Override | |
| 175 | + public void accept(Throwable throwable) { | |
| 176 | + log.error("发送错误 {}!", throwable.getMessage()); | |
| 177 | + // 保存 chat message | |
| 178 | + insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(), | |
| 179 | + chatModal.getModel(), chatModal.getId(), throwable.getMessage(), | |
| 180 | + tokens.get(), conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts()); | |
| 181 | + } | |
| 182 | + }); | |
| 188 | 183 | } |
| 189 | 184 | |
| 190 | 185 | @Override |
| ... | ... | @@ -194,7 +189,7 @@ public class AiChatServiceImpl implements AiChatService { |
| 194 | 189 | // 获取对话所有 message |
| 195 | 190 | List<AiChatMessageDO> aiChatMessageDOList = aiChatMessageMapper.selectByConversationId(conversationId); |
| 196 | 191 | // 转换 AiChatMessageRespVO |
| 197 | - return AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList); | |
| 192 | + return AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList); | |
| 198 | 193 | } |
| 199 | 194 | |
| 200 | 195 | @Override | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiImageServiceImpl.java
| ... | ... | @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.ai.image.ImageGeneration; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.image.ImagePrompt; |
| 6 | 6 | import cn.iocoder.yudao.framework.ai.image.ImageResponse; |
| 7 | 7 | import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageClient; |
| 8 | -import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum; | |
| 9 | 8 | import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions; |
| 9 | +import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageModelEnum; | |
| 10 | 10 | import cn.iocoder.yudao.framework.ai.imageopenai.enums.OpenAiImageStyleEnum; |
| 11 | 11 | import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi; |
| 12 | 12 | import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter; |
| ... | ... | @@ -14,22 +14,18 @@ import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify; |
| 14 | 14 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 15 | 15 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 16 | 16 | import cn.iocoder.yudao.module.ai.ErrorCodeConstants; |
| 17 | -import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; | |
| 17 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReq; | |
| 18 | +import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq; | |
| 18 | 19 | import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; |
| 19 | -import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum; | |
| 20 | 20 | import cn.iocoder.yudao.module.ai.dal.mysql.AiImageMapper; |
| 21 | +import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum; | |
| 21 | 22 | import cn.iocoder.yudao.module.ai.service.AiImageService; |
| 22 | -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDallDrawingReq; | |
| 23 | -import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageMidjourneyReq; | |
| 24 | 23 | import jakarta.annotation.PostConstruct; |
| 25 | 24 | import lombok.AllArgsConstructor; |
| 26 | 25 | import lombok.extern.slf4j.Slf4j; |
| 27 | -import org.springframework.http.MediaType; | |
| 28 | 26 | import org.springframework.stereotype.Service; |
| 29 | 27 | import org.springframework.transaction.annotation.Transactional; |
| 30 | 28 | |
| 31 | -import java.io.IOException; | |
| 32 | - | |
| 33 | 29 | /** |
| 34 | 30 | * ai 作图 |
| 35 | 31 | * |
| ... | ... | @@ -64,7 +60,7 @@ public class AiImageServiceImpl implements AiImageService { |
| 64 | 60 | } |
| 65 | 61 | |
| 66 | 62 | @Override |
| 67 | - public void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter) { | |
| 63 | + public void dallDrawing(AiImageDallDrawingReq req) { | |
| 68 | 64 | // 获取 model |
| 69 | 65 | OpenAiImageModelEnum openAiImageModelEnum = OpenAiImageModelEnum.valueOfModel(req.getModal()); |
| 70 | 66 | OpenAiImageStyleEnum openAiImageStyleEnum = OpenAiImageStyleEnum.valueOfStyle(req.getStyle()); |
| ... | ... | @@ -79,7 +75,7 @@ public class AiImageServiceImpl implements AiImageService { |
| 79 | 75 | // 发送 |
| 80 | 76 | ImageGeneration imageGeneration = imageResponse.getResult(); |
| 81 | 77 | // 发送信息 |
| 82 | - sendSseEmitter(sseEmitter, imageGeneration); | |
| 78 | +// sendSseEmitter(sseEmitter, imageGeneration); | |
| 83 | 79 | // 保存数据库 |
| 84 | 80 | doSave(req.getPrompt(), req.getSize(), req.getModal(), |
| 85 | 81 | imageGeneration.getOutput().getUrl(), AiChatDrawingStatusEnum.COMPLETE, null); |
| ... | ... | @@ -88,7 +84,7 @@ public class AiImageServiceImpl implements AiImageService { |
| 88 | 84 | doSave(req.getPrompt(), req.getSize(), req.getModal(), |
| 89 | 85 | null, AiChatDrawingStatusEnum.FAIL, aiException.getMessage()); |
| 90 | 86 | // 发送错误信息 |
| 91 | - sendSseEmitter(sseEmitter, aiException.getMessage()); | |
| 87 | +// sendSseEmitter(sseEmitter, aiException.getMessage()); | |
| 92 | 88 | } |
| 93 | 89 | } |
| 94 | 90 | |
| ... | ... | @@ -105,16 +101,16 @@ public class AiImageServiceImpl implements AiImageService { |
| 105 | 101 | } |
| 106 | 102 | } |
| 107 | 103 | |
| 108 | - private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) { | |
| 109 | - try { | |
| 110 | - sseEmitter.send(object, MediaType.APPLICATION_JSON); | |
| 111 | - } catch (IOException e) { | |
| 112 | - throw new RuntimeException(e); | |
| 113 | - } finally { | |
| 114 | - // 发送 complete | |
| 115 | - sseEmitter.complete(); | |
| 116 | - } | |
| 117 | - } | |
| 104 | +// private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) { | |
| 105 | +// try { | |
| 106 | +// sseEmitter.send(object, MediaType.APPLICATION_JSON); | |
| 107 | +// } catch (IOException e) { | |
| 108 | +// throw new RuntimeException(e); | |
| 109 | +// } finally { | |
| 110 | +// // 发送 complete | |
| 111 | +// sseEmitter.complete(); | |
| 112 | +// } | |
| 113 | +// } | |
| 118 | 114 | |
| 119 | 115 | private AiImageDO doSave(String prompt, |
| 120 | 116 | String size, | ... | ... |
yudao-server/src/main/resources/application-local.yaml
| ... | ... | @@ -2,7 +2,6 @@ server: |
| 2 | 2 | port: 48080 |
| 3 | 3 | |
| 4 | 4 | --- #################### 数据库相关配置 #################### |
| 5 | - | |
| 6 | 5 | spring: |
| 7 | 6 | # 数据源配置项 |
| 8 | 7 | autoconfigure: |
| ... | ... | @@ -79,7 +78,12 @@ spring: |
| 79 | 78 | port: 6379 # 端口 |
| 80 | 79 | database: 0 # 数据库索引 |
| 81 | 80 | # password: dev # 密码,建议生产环境开启 |
| 82 | - | |
| 81 | +server: | |
| 82 | + servlet: | |
| 83 | + encoding: | |
| 84 | + enabled: true | |
| 85 | + charset: UTF-8 | |
| 86 | + force: true | |
| 83 | 87 | --- #################### 定时任务相关配置 #################### |
| 84 | 88 | |
| 85 | 89 | # Quartz 配置项,对应 QuartzProperties 配置类 | ... | ... |