From 32bc632947783ac18dd8618d57e216ac6174892c Mon Sep 17 00:00:00 2001 From: cherishsince Date: Tue, 9 Apr 2024 20:12:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=84=E7=90=86todo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/ai/enums/AiModelEnum.java | 28 ------- .../module/ai/enums/OpenAiModelEnum.java | 35 ++++++++ .../ai/controller/admin/ChatController.java | 41 ++------- .../ai/controller/admin/vo/AiChatReqVO.java | 20 ++--- .../yudao-spring-boot-starter-ai/pom.xml | 4 + .../ai/chatqianwen/QianWenChatClient.java | 1 + .../ai/chatqianwen/{ => api}/QianWenApi.java | 4 +- .../ai/imageopenai/OpenAiImageApi.java | 3 +- ...{MjMessage.java => MidjourneyMessage.java} | 5 +- ...onstants.java => MidjourneyConstants.java} | 2 +- .../MidjourneyGennerateStatusEnum.java | 31 +++++++ ...m.java => MidjourneyInteractionsEnum.java} | 4 +- ...um.java => MidjourneyMessageTypeEnum.java} | 4 +- ...ifyCode.java => MidjourneyNotifyCode.java} | 2 +- .../constants/MjGennerateStatusEnum.java | 30 ------- ...tions.java => MidjourneyInteractions.java} | 39 +++++---- .../util/{MjUtil.java => MidjourneyUtil.java} | 8 +- ...r.java => MidjourneyWebSocketStarter.java} | 27 +++--- ...r.java => MidjourneyWebSocketHandler.java} | 14 ++-- .../listener/MidjourneyMessageListener.java | 83 +++++++++++++++++++ .../webSocket/listener/MjMessageListener.java | 83 ------------------- .../yudao/framework/ai/util/JacksonUtil.java | 80 ------------------ .../ai/chat/QianWenChatClientTests.java | 3 +- .../MidjourneyInteractionsTests.java} | 15 ++-- .../MidjourneyUtilTests.java} | 10 +-- .../MidjourneyWebSocketTests.java} | 13 ++- 26 files changed, 243 insertions(+), 346 deletions(-) delete mode 100644 yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiModelEnum.java create mode 100644 yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/OpenAiModelEnum.java rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/{ => api}/QianWenApi.java (92%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/{MjMessage.java => MidjourneyMessage.java} (93%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/{MjConstants.java => MidjourneyConstants.java} (97%) create mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyGennerateStatusEnum.java rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/{MjInteractionsEnum.java => MidjourneyInteractionsEnum.java} (81%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/{MjMessageTypeEnum.java => MidjourneyMessageTypeEnum.java} (76%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/{MjNotifyCode.java => MidjourneyNotifyCode.java} (81%) delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjGennerateStatusEnum.java rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/{MjInteractions.java => MidjourneyInteractions.java} (89%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/{MjUtil.java => MidjourneyUtil.java} (91%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/{MjWebSocketStarter.java => MidjourneyWebSocketStarter.java} (89%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/{MjWebSocketHandler.java => MidjourneyWebSocketHandler.java} (96%) create mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MidjourneyMessageListener.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MjMessageListener.java delete mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/util/JacksonUtil.java rename yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/{mj/MjInteractionsTests.java => midjourney/MidjourneyInteractionsTests.java} (79%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/{mj/MjUtilTests.java => midjourney/MidjourneyUtilTests.java} (58%) rename yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/{mj/MjWebSocketTests.java => midjourney/MidjourneyWebSocketTests.java} (76%) diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiModelEnum.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiModelEnum.java deleted file mode 100644 index 7eac2b61f..000000000 --- a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiModelEnum.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.ai.enums; - -import lombok.Getter; - -// TODO @fansili:1)类注释要加下;2)author 和 time 用 javadoc,@author 和 @since;3)@AllArgsConstructor 使用这个注解,去掉构造方法;4)value 改成 model 字段,然后注释都写下哈;5)message 改成 name,然后注释都写下哈 -/** - * author: fansili - * time: 2024/3/4 12:36 - */ -@Getter -public enum AiModelEnum { - - OPEN_AI_GPT_3_5("gpt-3.5-turbo", "GPT3.5"), - OPEN_AI_GPT_4("gpt-4-turbo", "GPT4") - - ; - - AiModelEnum(String value, String message) { - this.value = value; - this.message = message; - } - - // TODO @fan - private String value; - - private String message; - -} diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/OpenAiModelEnum.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/OpenAiModelEnum.java new file mode 100644 index 000000000..3daa3f57b --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/OpenAiModelEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.ai.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +// TODO done @fansili:1)类注释要加下;2)author 和 time 用 javadoc,@author 和 @since;3)@AllArgsConstructor 使用这个注解,去掉构造方法;4)value 改成 model 字段,然后注释都写下哈;5)message 改成 name,然后注释都写下哈 +/** + * @author: fansili + * @time: 2024/3/4 12:36 + */ +@Getter +@AllArgsConstructor +public enum OpenAiModelEnum { + + /** + * open ai 3.5模型 + */ + OPEN_AI_GPT_3_5("gpt-3.5-turbo", "GPT3.5"), + /** + * open ai 4.0 收费模型 + */ + OPEN_AI_GPT_4("gpt-4-turbo", "GPT4") + + ; + + /** + * 模型 - 用于参数传递 + */ + private String model; + /** + * 模型名字 - 用于展示 + */ + private String name; + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/ChatController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/ChatController.java index a6300a5c2..e9f8ab6b5 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/ChatController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/ChatController.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.ai.ErrorCodeConstants; import cn.iocoder.yudao.module.ai.controller.admin.vo.AiChatReqVO; -import cn.iocoder.yudao.module.ai.enums.AiModelEnum; +import cn.iocoder.yudao.module.ai.enums.OpenAiModelEnum; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; @@ -13,7 +13,6 @@ import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.openai.OpenAiChatClient; -import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.validation.annotation.Validated; @@ -23,16 +22,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; -import java.util.Scanner; import java.util.function.Consumer; -// TODO @fansili:有了 swagger 注释,就不用类注释了 -/** - * AI模块 - * - * author: fansili - * time: 2024/3/3 20:28 - */ +// TODO done @fansili:有了 swagger 注释,就不用类注释了 @Tag(name = "AI模块") @RestController @RequestMapping("/ai-api") @@ -48,7 +40,7 @@ public class ChatController { ChatClient chatClient = getChatClient(reqVO.getAiModel()); String res; try { - res = chatClient.call(reqVO.getInputText()); + res = chatClient.call(reqVO.getPrompt()); } catch (Exception e) { res = e.getMessage(); } @@ -59,33 +51,14 @@ public class ChatController { @Operation(summary = "对话聊天chatStream", description = "简单的ai聊天") public CommonResult chatStream(HttpServletResponse response, @RequestBody @Validated AiChatReqVO reqVO) throws InterruptedException { OpenAiChatClient chatClient = applicationContext.getBean(OpenAiChatClient.class); - Flux chatResponse = chatClient.stream(new Prompt(reqVO.getInputText())); + Flux chatResponse = chatClient.stream(new Prompt(reqVO.getPrompt())); chatResponse.subscribe(new Consumer() { @Override public void accept(ChatResponse chatResponse) { System.err.println(chatResponse.getResults().get(0).getOutput().getContent()); } }); - return CommonResult.success("1"); - } - - public static void main(String[] args) { - OpenAiChatClient openAiChatClient = new OpenAiChatClient(new OpenAiApi("openkey")); - Flux responseFlux = openAiChatClient.stream(new Prompt("最好的编程语言!")); - long now = System.currentTimeMillis(); - responseFlux.subscribe(new Consumer() { - @Override - public void accept(ChatResponse chatResponse) { - if (chatResponse.getResults().get(0).getOutput() == null) { - return; - } - System.err.println(chatResponse.getResults().get(0).getOutput().getContent()); - } - }); - - // 阻止退出 - Scanner scanner = new Scanner(System.in); - scanner.nextLine(); + return CommonResult.success(null); } /** @@ -94,8 +67,8 @@ public class ChatController { * @param aiModelEnum * @return */ - private ChatClient getChatClient(AiModelEnum aiModelEnum) { - if (AiModelEnum.OPEN_AI_GPT_3_5 == aiModelEnum) { + private ChatClient getChatClient(OpenAiModelEnum aiModelEnum) { + if (OpenAiModelEnum.OPEN_AI_GPT_3_5 == aiModelEnum) { return applicationContext.getBean(OpenAiChatClient.class); } // AI模型暂不支持 diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/vo/AiChatReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/vo/AiChatReqVO.java index 187f51741..643b6600d 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/vo/AiChatReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/vo/AiChatReqVO.java @@ -1,27 +1,21 @@ package cn.iocoder.yudao.module.ai.controller.admin.vo; -import cn.iocoder.yudao.module.ai.enums.AiModelEnum; +import cn.iocoder.yudao.module.ai.enums.OpenAiModelEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -// TODO @fansili 1)swagger 注释不太对;2)有了 swagger 注释,就不用类注释了 -/** - * ai 聊天 req - * - * author: fansili - * time: 2024/3/4 12:33 - */ -@Schema(description = "用户 App - 上传文件 Request VO") +// TODO done @fansili 1)swagger 注释不太对;2)有了 swagger 注释,就不用类注释了 @Data +@Schema(description = "用户 App - 上传文件 Request VO") public class AiChatReqVO { - @Schema(description = "输入内容", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "输入内容不能为空") - private String inputText; + @Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "提示词不能为空!") + private String prompt; @Schema(description = "AI模型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "AI模型不能为空") - private AiModelEnum aiModel; + private OpenAiModelEnum aiModel; } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml b/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml index 6e3f2b2f1..81d303ab6 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml @@ -149,6 +149,10 @@ + + cn.iocoder.boot + yudao-common + \ No newline at end of file diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java index 62c982095..a8fb9105f 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenChatClient.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.ai.chat.*; import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; import cn.iocoder.yudao.framework.ai.chat.prompt.ChatOptions; import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; +import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi; import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException; import com.aliyun.broadscope.bailian.sdk.models.*; import lombok.extern.slf4j.Slf4j; diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/api/QianWenApi.java similarity index 92% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenApi.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/api/QianWenApi.java index 77d4411f3..c8170af0f 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/QianWenApi.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatqianwen/api/QianWenApi.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.ai.chatqianwen; +package cn.iocoder.yudao.framework.ai.chatqianwen.api; import com.aliyun.broadscope.bailian.sdk.AccessTokenClient; import com.aliyun.broadscope.bailian.sdk.ApplicationClient; @@ -9,7 +9,7 @@ import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import reactor.core.publisher.Flux; -// TODO @fansili:是不是挪到 api 包里?按照 spring ai 的结构;根目录只放 client 和 options +// TODO done @fansili:是不是挪到 api 包里?按照 spring ai 的结构;根目录只放 client 和 options /** * 阿里 通义千问 * diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/imageopenai/OpenAiImageApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/imageopenai/OpenAiImageApi.java index 0f651ac09..6c5c8dba3 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/imageopenai/OpenAiImageApi.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/imageopenai/OpenAiImageApi.java @@ -4,6 +4,7 @@ import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.ai.imageopenai.api.OpenAiImageRequest; import cn.iocoder.yudao.framework.ai.imageopenai.api.OpenAiImageResponse; import cn.iocoder.yudao.framework.ai.util.JacksonUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import io.netty.channel.ChannelOption; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; @@ -55,7 +56,7 @@ public class OpenAiImageApi { httpPost.setURI(URI.create(DEFAULT_BASE_URL.concat("/v1/images/generations"))); httpPost.setHeader("Content-Type", "application/json"); httpPost.setHeader("Authorization", "Bearer " + apiKey); - httpPost.setEntity(new StringEntity(JacksonUtil.toJson(request), "UTF-8")); + httpPost.setEntity(new StringEntity(JsonUtils.toJsonString(request), "UTF-8")); CloseableHttpResponse response= null; try { diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MjMessage.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyMessage.java similarity index 93% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MjMessage.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyMessage.java index 2160e8e14..f52ba9337 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MjMessage.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyMessage.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.ai.midjourney; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum; import lombok.Data; import lombok.experimental.Accessors; @@ -7,7 +8,7 @@ import java.util.List; @Data @Accessors(chain = true) -public class MjMessage { +public class MidjourneyMessage { /** * id是一个重要的字段,在同时生成多个的时候,可以区分生成信息 @@ -41,7 +42,7 @@ public class MjMessage { * 1、等待 * 2、进行中 * 3、完成 - * {@link cn.iocoder.yudao.framework.ai.midjourney.constants.MjGennerateStatusEnum} + * {@link MidjourneyGennerateStatusEnum} */ private String generateStatus; diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjConstants.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyConstants.java similarity index 97% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjConstants.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyConstants.java index 751652b08..ee180a0f4 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjConstants.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyConstants.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.framework.ai.midjourney.constants; -public final class MjConstants { +public final class MidjourneyConstants { /** * 消息 - 编号 diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyGennerateStatusEnum.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyGennerateStatusEnum.java new file mode 100644 index 000000000..ef7147beb --- /dev/null +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyGennerateStatusEnum.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.ai.midjourney.constants; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +// TODO done @fansili:1)Mj 缩写,还是搞成全称。。虽然长一点,但是感觉会相对清晰一些哈;2)lombok 相关的注解,可以用用哈;3)value 改 status; +/** + * mj 生成状态 + * + * author: fansili + * time: 2024/4/6 21:07 + */ +@Getter +@AllArgsConstructor +public enum MidjourneyGennerateStatusEnum { + + WAITING("waiting", "等待..."), + IN_PROGRESS("in_progress", "进行中"), + COMPLETED("completed", "完成"), + + ; + + /** + * 状态 + */ + private String status; + /** + * 状态信息 + */ + private String message; +} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjInteractionsEnum.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyInteractionsEnum.java similarity index 81% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjInteractionsEnum.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyInteractionsEnum.java index 124bc8332..08832e78b 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjInteractionsEnum.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyInteractionsEnum.java @@ -6,7 +6,7 @@ import lombok.Getter; * MJ 命令 */ @Getter -public enum MjInteractionsEnum { +public enum MidjourneyInteractionsEnum { IMAGINE("imagine", "生成图片"), DESCRIBE("describe", "生成描述"), @@ -17,7 +17,7 @@ public enum MjInteractionsEnum { ; - MjInteractionsEnum(String value, String message) { + MidjourneyInteractionsEnum(String value, String message) { this.value =value; this.message =message; } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjMessageTypeEnum.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyMessageTypeEnum.java similarity index 76% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjMessageTypeEnum.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyMessageTypeEnum.java index b47199e91..9c8eb9ed5 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjMessageTypeEnum.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyMessageTypeEnum.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.constants; -public enum MjMessageTypeEnum { +public enum MidjourneyMessageTypeEnum { /** * 创建. */ @@ -15,7 +15,7 @@ public enum MjMessageTypeEnum { */ DELETE; - public static MjMessageTypeEnum of(String type) { + public static MidjourneyMessageTypeEnum of(String type) { return switch (type) { case "MESSAGE_CREATE" -> CREATE; case "MESSAGE_UPDATE" -> UPDATE; diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjNotifyCode.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyNotifyCode.java similarity index 81% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjNotifyCode.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyNotifyCode.java index 103bd6fdf..1dccb8a41 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjNotifyCode.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MidjourneyNotifyCode.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.constants; import lombok.experimental.UtilityClass; @UtilityClass -public final class MjNotifyCode { +public final class MidjourneyNotifyCode { /** * 成功. */ diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjGennerateStatusEnum.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjGennerateStatusEnum.java deleted file mode 100644 index 1e8bc6f53..000000000 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjGennerateStatusEnum.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.framework.ai.midjourney.constants; - -import lombok.Getter; - -// TODO @fansili:1)Mj 缩写,还是搞成全称。。虽然长一点,但是感觉会相对清晰一些哈;2)lombok 相关的注解,可以用用哈;3)value 改 status; -/** - * mj 生成状态 - * - * author: fansili - * time: 2024/4/6 21:07 - */ -@Getter -public enum MjGennerateStatusEnum { - - - WAITING("waiting", "等待..."), - IN_PROGRESS("in_progress", "进行中"), - COMPLETED("completed", "完成"), - - ; - - MjGennerateStatusEnum(String value, String message) { - this.value = value; - this.message = message; - } - - private String value; - - private String message; -} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjInteractions.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MidjourneyInteractions.java similarity index 89% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjInteractions.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MidjourneyInteractions.java index f0bd74daa..104e1dd2c 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjInteractions.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MidjourneyInteractions.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.ai.midjourney.interactions; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; -import cn.iocoder.yudao.framework.ai.midjourney.constants.MjConstants; -import cn.iocoder.yudao.framework.ai.midjourney.util.MjUtil; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyConstants; +import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil; import cn.iocoder.yudao.framework.ai.midjourney.vo.Attachments; import cn.iocoder.yudao.framework.ai.midjourney.vo.Describe; import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll; @@ -32,15 +32,17 @@ import java.util.HashMap; * time: 2024/4/3 17:36 */ @Slf4j -public class MjInteractions { +public class MidjourneyInteractions { + + // TODO done @fansili:静态变量,放在最前面哈; + private static final String HEADER_REFERER = "https://discord.com/channels/%s/%s"; private final String url; private final MidjourneyConfig midjourneyConfig; private final RestTemplate restTemplate = new RestTemplate(); // TODO @fansili:优先级低:后续搞到统一的管理 - // TODO @fansili:静态变量,放在最前面哈; - private static final String HEADER_REFERER = "https://discord.com/channels/%s/%s"; - public MjInteractions(MidjourneyConfig midjourneyConfig) { + + public MidjourneyInteractions(MidjourneyConfig midjourneyConfig) { this.midjourneyConfig = midjourneyConfig; this.url = midjourneyConfig.getServerUrl().concat(midjourneyConfig.getApiInteractions()); } @@ -57,7 +59,7 @@ public class MjInteractions { requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId())); // TODO @fansili:建议用 uuid 之类的;nextId 跨进程未必合适哈; requestParams.put("prompt", prompt); // 解析 template 参数占位符 - String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams); + String requestBody = MidjourneyUtil.parseTemplate(requestTemplate, requestParams); // 获取 header HttpHeaders httpHeaders = getHttpHeaders(); // 发送请求 @@ -65,14 +67,14 @@ public class MjInteractions { String res = restTemplate.postForObject(url, requestEntity, String.class); // 这个 res 只要不返回值,就是成功! // TODO @fansili:可以直接 if (StrUtil.isBlank(res)) - boolean isSuccess = StrUtil.isBlank(res); - if (isSuccess) { + if (StrUtil.isBlank(res)) { return true; + } else { + log.error("请求失败! 请求参数:{} 返回结果! {}", requestBody, res); + return false; } - log.error("请求失败! 请求参数:{} 返回结果! {}", requestBody, res); - return isSuccess; } - // TODO @fansili:方法和方法之间,空一行哈; + // TODO done @fansili:方法和方法之间,空一行哈; public Boolean reRoll(ReRoll reRoll) { @@ -89,7 +91,7 @@ public class MjInteractions { // 获取 header HttpHeaders httpHeaders = getHttpHeaders(); // 设置参数 - String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams); + String requestBody = MidjourneyUtil.parseTemplate(requestTemplate, requestParams); // 发送请求 HttpEntity requestEntity = new HttpEntity<>(requestBody, httpHeaders); String res = restTemplate.postForObject(url, requestEntity, String.class); @@ -123,7 +125,7 @@ public class MjInteractions { httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.set("Authorization", midjourneyConfig.getToken()); httpHeaders.set("User-Agent", midjourneyConfig.getUserAage()); - httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE); + httpHeaders.set("Cookie", MidjourneyConstants.HTTP_COOKIE); httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId())); // 创建HttpEntity对象,包含表单数据和头部信息 HttpEntity> multiValueMapHttpEntity = new HttpEntity<>(multipartRequest, httpHeaders); @@ -132,16 +134,13 @@ public class MjInteractions { String response = restTemplate.postForObject(midjourneyConfig.getServerUrl().concat(uri), multiValueMapHttpEntity, String.class); UploadAttachmentsRes uploadAttachmentsRes = JSON.parseObject(response, UploadAttachmentsRes.class); - // // 上传文件 String uploadUrl = uploadAttachmentsRes.getAttachments().getFirst().getUploadUrl(); - String uploadAttachmentsUrl = midjourneyConfig.getApiAttachmentsUpload().concat(uploadUrl); httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity fileSystemResourceHttpEntity = new HttpEntity<>(attachments.getFileSystemResource(), httpHeaders); ResponseEntity exchange = restTemplate.exchange(uploadUrl, HttpMethod.PUT, fileSystemResourceHttpEntity, String.class); String uploadRes = exchange.getBody(); - return uploadAttachmentsRes; } @@ -161,9 +160,9 @@ public class MjInteractions { httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); // 设置内容类型为JSON httpHeaders.set("Authorization", midjourneyConfig.getToken()); httpHeaders.set("User-Agent", midjourneyConfig.getUserAage()); - httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE); + httpHeaders.set("Cookie", MidjourneyConstants.HTTP_COOKIE); httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId())); - String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams); + String requestBody = MidjourneyUtil.parseTemplate(requestTemplate, requestParams); // 创建表单数据 MultiValueMap formData = new LinkedMultiValueMap<>(); formData.add("payload_json", requestBody); @@ -185,7 +184,7 @@ public class MjInteractions { httpHeaders.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为JSON httpHeaders.set("Authorization", midjourneyConfig.getToken()); httpHeaders.set("User-Agent", midjourneyConfig.getUserAage()); - httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE); + httpHeaders.set("Cookie", MidjourneyConstants.HTTP_COOKIE); httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId())); return httpHeaders; } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MjUtil.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MidjourneyUtil.java similarity index 91% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MjUtil.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MidjourneyUtil.java index 751a79b04..92c7d42e0 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MjUtil.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MidjourneyUtil.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.util; import cn.hutool.core.text.CharSequenceUtil; -import cn.iocoder.yudao.framework.ai.midjourney.MjMessage; +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyMessage; import java.util.Map; import java.util.regex.Matcher; @@ -13,7 +13,7 @@ import java.util.regex.Pattern; * author: fansili * time: 2024/4/6 19:00 */ -public class MjUtil { +public class MidjourneyUtil { /** * content正则匹配prompt和进度. */ @@ -26,12 +26,12 @@ public class MjUtil { * @param content * @return */ - public static MjMessage.Content parseContent(String content) { + public static MidjourneyMessage.Content parseContent(String content) { // 有三种格式。 // 南极应该是什么样子? // "**南极应该是什么样子? --v 6.0 --style raw** - <@972721304891453450> (32%) (fast, stealth)", // "**南极应该是什么样子? --v 6.0 --style raw** - <@972721304891453450> (fast, stealth)" - MjMessage.Content mjContent = new MjMessage.Content(); + MidjourneyMessage.Content mjContent = new MidjourneyMessage.Content(); if (CharSequenceUtil.isBlank(content)) { return null; } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MjWebSocketStarter.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MidjourneyWebSocketStarter.java similarity index 89% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MjWebSocketStarter.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MidjourneyWebSocketStarter.java index b01c4adfe..e7ff41cc5 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MjWebSocketStarter.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MidjourneyWebSocketStarter.java @@ -4,9 +4,9 @@ package cn.iocoder.yudao.framework.ai.midjourney.webSocket; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.thread.ThreadUtil; import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; -import cn.iocoder.yudao.framework.ai.midjourney.constants.MjNotifyCode; -import cn.iocoder.yudao.framework.ai.midjourney.webSocket.handler.MjWebSocketHandler; -import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MjMessageListener; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyNotifyCode; +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.handler.MidjourneyWebSocketHandler; +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MidjourneyMessageListener; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.tomcat.websocket.Constants; @@ -20,11 +20,10 @@ import org.springframework.web.socket.client.standard.StandardWebSocketClient; import java.io.IOException; import java.net.URI; -import java.util.concurrent.TimeoutException; // TODO @fansili:mj 这块 websocket 有点小复杂,虽然代码量 400 多行;感觉可以考虑,有没第三方 sdk,通过它透明接入 mj @Slf4j -public class MjWebSocketStarter implements WebSocketStarter { +public class MidjourneyWebSocketStarter implements WebSocketStarter { /** * 链接重试次数 */ @@ -36,7 +35,7 @@ public class MjWebSocketStarter implements WebSocketStarter { /** * mj 监听(所有message 都会 callback到这里) */ - private final MjMessageListener userMessageListener; + private final MidjourneyMessageListener userMessageListener; /** * wss 服务器 */ @@ -58,10 +57,10 @@ public class MjWebSocketStarter implements WebSocketStarter { */ private WebSocketSession webSocketSession = null; - public MjWebSocketStarter(String wssServer, - String resumeWss, - MidjourneyConfig midjourneyConfig, - MjMessageListener userMessageListener) { + public MidjourneyWebSocketStarter(String wssServer, + String resumeWss, + MidjourneyConfig midjourneyConfig, + MidjourneyMessageListener userMessageListener) { this.wssServer = wssServer; this.resumeWss = resumeWss; this.midjourneyConfig = midjourneyConfig; @@ -83,7 +82,7 @@ public class MjWebSocketStarter implements WebSocketStarter { headers.add("Sec-Websocket-Extensions", "permessage-deflate; client_max_window_bits"); headers.add("User-Agent", this.midjourneyConfig.getUserAage()); // 创建 mjHeader - MjWebSocketHandler mjWebSocketHandler = new MjWebSocketHandler( + MidjourneyWebSocketHandler mjWebSocketHandler = new MidjourneyWebSocketHandler( this.midjourneyConfig, this.userMessageListener, this::onSocketSuccess, this::onSocketFailure); // String gatewayUrl; @@ -105,12 +104,12 @@ public class MjWebSocketStarter implements WebSocketStarter { socketSessionFuture.addCallback(new ListenableFutureCallback<>() { @Override public void onFailure(@NotNull Throwable e) { - onSocketFailure(MjWebSocketHandler.CLOSE_CODE_EXCEPTION, e.getMessage()); + onSocketFailure(MidjourneyWebSocketHandler.CLOSE_CODE_EXCEPTION, e.getMessage()); } @Override public void onSuccess(WebSocketSession session) { - MjWebSocketStarter.this.webSocketSession = session; + MidjourneyWebSocketStarter.this.webSocketSession = session; } }); } @@ -118,7 +117,7 @@ public class MjWebSocketStarter implements WebSocketStarter { private void onSocketSuccess(String sessionId, Object sequence, String resumeGatewayUrl) { this.resumeData = new ResumeData(sessionId, sequence, resumeGatewayUrl); this.running = true; - notifyWssLock(MjNotifyCode.SUCCESS, ""); + notifyWssLock(MidjourneyNotifyCode.SUCCESS, ""); } private void onSocketFailure(int code, String reason) { diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MjWebSocketHandler.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MidjourneyWebSocketHandler.java similarity index 96% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MjWebSocketHandler.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MidjourneyWebSocketHandler.java index 55fc7e4bc..b6fbf5c21 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MjWebSocketHandler.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MidjourneyWebSocketHandler.java @@ -8,7 +8,7 @@ import cn.hutool.http.useragent.UserAgentUtil; import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; import cn.iocoder.yudao.framework.ai.midjourney.webSocket.FailureCallback; import cn.iocoder.yudao.framework.ai.midjourney.webSocket.SuccessCallback; -import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MjMessageListener; +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MidjourneyMessageListener; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.utils.data.DataArray; @@ -29,7 +29,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Slf4j -public class MjWebSocketHandler implements WebSocketHandler { +public class MidjourneyWebSocketHandler implements WebSocketHandler { /** * close 错误码:重连 */ @@ -49,7 +49,7 @@ public class MjWebSocketHandler implements WebSocketHandler { /** * mj 消息监听 */ - private final MjMessageListener userMessageListener; + private final MidjourneyMessageListener userMessageListener; /** * 成功回调 */ @@ -85,10 +85,10 @@ public class MjWebSocketHandler implements WebSocketHandler { */ private final Decompressor decompressor = new ZlibDecompressor(2048); - public MjWebSocketHandler(MidjourneyConfig account, - MjMessageListener userMessageListener, - SuccessCallback successCallback, - FailureCallback failureCallback) { + public MidjourneyWebSocketHandler(MidjourneyConfig account, + MidjourneyMessageListener userMessageListener, + SuccessCallback successCallback, + FailureCallback failureCallback) { this.midjourneyConfig = account; this.userMessageListener = userMessageListener; this.successCallback = successCallback; diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MidjourneyMessageListener.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MidjourneyMessageListener.java new file mode 100644 index 000000000..31bbe0a97 --- /dev/null +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MidjourneyMessageListener.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener; + + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyMessage; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyConstants; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyGennerateStatusEnum; +import cn.iocoder.yudao.framework.ai.midjourney.constants.MidjourneyMessageTypeEnum; +import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.utils.data.DataObject; + +import java.util.List; + +@Slf4j +public class MidjourneyMessageListener { + + private MidjourneyConfig midjourneyConfig; + + public MidjourneyMessageListener(MidjourneyConfig midjourneyConfig) { + this.midjourneyConfig = midjourneyConfig; + } + + public void onMessage(DataObject raw) { + MidjourneyMessageTypeEnum messageType = MidjourneyMessageTypeEnum.of(raw.getString("t")); + if (messageType == null || MidjourneyMessageTypeEnum.DELETE == messageType) { + return; + } + DataObject data = raw.getObject("d"); + if (ignoreAndLogMessage(data, messageType)) { + return; + } + + // 转换几个重要的信息 + MidjourneyMessage mjMessage = new MidjourneyMessage(); + mjMessage.setId(data.getString(MidjourneyConstants.MSG_ID)); + mjMessage.setType(data.getInt(MidjourneyConstants.MSG_TYPE)); + mjMessage.setRawData(StrUtil.str(raw.toJson(), "UTF-8")); + mjMessage.setContent(MidjourneyUtil.parseContent(data.getString(MidjourneyConstants.MSG_CONTENT))); + // 转换 components + if (!data.getArray(MidjourneyConstants.MSG_COMPONENTS).isEmpty()) { + String componentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_COMPONENTS).toJson(), "UTF-8"); + List components = JSON.parseArray(componentsJson, MidjourneyMessage.ComponentType.class); + mjMessage.setComponents(components); + } + // 转换附件 + if (!data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).isEmpty()) { + String attachmentsJson = StrUtil.str(data.getArray(MidjourneyConstants.MSG_ATTACHMENTS).toJson(), "UTF-8"); + List attachments = JSON.parseArray(attachmentsJson, MidjourneyMessage.Attachment.class); + mjMessage.setAttachments(attachments); + } + // 转换状态 + convertGenerateStatus(mjMessage); + // + log.info("message 信息 {}", JSONUtil.toJsonPrettyStr(mjMessage)); + System.err.println(JSONUtil.toJsonPrettyStr(mjMessage)); + } + + private void convertGenerateStatus(MidjourneyMessage mjMessage) { + if (mjMessage.getType() == 20 && mjMessage.getContent().getStatus().contains("Waiting")) { + mjMessage.setGenerateStatus(MidjourneyGennerateStatusEnum.WAITING.getValue()); + } else if (mjMessage.getType() == 20 && !StrUtil.isBlank(mjMessage.getContent().getProgress())) { + mjMessage.setGenerateStatus(MidjourneyGennerateStatusEnum.IN_PROGRESS.getValue()); + } else if (mjMessage.getType() == 0 && !CollUtil.isEmpty(mjMessage.getComponents())) { + mjMessage.setGenerateStatus(MidjourneyGennerateStatusEnum.COMPLETED.getValue()); + } + } + + private boolean ignoreAndLogMessage(DataObject data, MidjourneyMessageTypeEnum messageType) { + String channelId = data.getString(MidjourneyConstants.MSG_CHANNEL_ID); + if (!CharSequenceUtil.equals(channelId, midjourneyConfig.getChannelId())) { + return true; + } + String authorName = data.optObject("author").map(a -> a.getString("username")).orElse("System"); + log.debug("{} - {} - {}: {}", midjourneyConfig.getChannelId(), messageType.name(), authorName, data.opt("content").orElse("")); + return false; + } +} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MjMessageListener.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MjMessageListener.java deleted file mode 100644 index 4893e7b37..000000000 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MjMessageListener.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener; - - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.text.CharSequenceUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; -import cn.iocoder.yudao.framework.ai.midjourney.MjMessage; -import cn.iocoder.yudao.framework.ai.midjourney.constants.MjConstants; -import cn.iocoder.yudao.framework.ai.midjourney.constants.MjGennerateStatusEnum; -import cn.iocoder.yudao.framework.ai.midjourney.constants.MjMessageTypeEnum; -import cn.iocoder.yudao.framework.ai.midjourney.util.MjUtil; -import com.alibaba.fastjson.JSON; -import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.utils.data.DataObject; - -import java.util.List; - -@Slf4j -public class MjMessageListener { - - private MidjourneyConfig midjourneyConfig; - - public MjMessageListener(MidjourneyConfig midjourneyConfig) { - this.midjourneyConfig = midjourneyConfig; - } - - public void onMessage(DataObject raw) { - MjMessageTypeEnum messageType = MjMessageTypeEnum.of(raw.getString("t")); - if (messageType == null || MjMessageTypeEnum.DELETE == messageType) { - return; - } - DataObject data = raw.getObject("d"); - if (ignoreAndLogMessage(data, messageType)) { - return; - } - - // 转换几个重要的信息 - MjMessage mjMessage = new MjMessage(); - mjMessage.setId(data.getString(MjConstants.MSG_ID)); - mjMessage.setType(data.getInt(MjConstants.MSG_TYPE)); - mjMessage.setRawData(StrUtil.str(raw.toJson(), "UTF-8")); - mjMessage.setContent(MjUtil.parseContent(data.getString(MjConstants.MSG_CONTENT))); - // 转换 components - if (!data.getArray(MjConstants.MSG_COMPONENTS).isEmpty()) { - String componentsJson = StrUtil.str(data.getArray(MjConstants.MSG_COMPONENTS).toJson(), "UTF-8"); - List components = JSON.parseArray(componentsJson, MjMessage.ComponentType.class); - mjMessage.setComponents(components); - } - // 转换附件 - if (!data.getArray(MjConstants.MSG_ATTACHMENTS).isEmpty()) { - String attachmentsJson = StrUtil.str(data.getArray(MjConstants.MSG_ATTACHMENTS).toJson(), "UTF-8"); - List attachments = JSON.parseArray(attachmentsJson, MjMessage.Attachment.class); - mjMessage.setAttachments(attachments); - } - // 转换状态 - convertGenerateStatus(mjMessage); - // - log.info("message 信息 {}", JSONUtil.toJsonPrettyStr(mjMessage)); - System.err.println(JSONUtil.toJsonPrettyStr(mjMessage)); - } - - private void convertGenerateStatus(MjMessage mjMessage) { - if (mjMessage.getType() == 20 && mjMessage.getContent().getStatus().contains("Waiting")) { - mjMessage.setGenerateStatus(MjGennerateStatusEnum.WAITING.getValue()); - } else if (mjMessage.getType() == 20 && !StrUtil.isBlank(mjMessage.getContent().getProgress())) { - mjMessage.setGenerateStatus(MjGennerateStatusEnum.IN_PROGRESS.getValue()); - } else if (mjMessage.getType() == 0 && !CollUtil.isEmpty(mjMessage.getComponents())) { - mjMessage.setGenerateStatus(MjGennerateStatusEnum.COMPLETED.getValue()); - } - } - - private boolean ignoreAndLogMessage(DataObject data, MjMessageTypeEnum messageType) { - String channelId = data.getString(MjConstants.MSG_CHANNEL_ID); - if (!CharSequenceUtil.equals(channelId, midjourneyConfig.getChannelId())) { - return true; - } - String authorName = data.optObject("author").map(a -> a.getString("username")).orElse("System"); - log.debug("{} - {} - {}: {}", midjourneyConfig.getChannelId(), messageType.name(), authorName, data.opt("content").orElse("")); - return false; - } -} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/util/JacksonUtil.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/util/JacksonUtil.java deleted file mode 100644 index b5c96c992..000000000 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/util/JacksonUtil.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.framework.ai.util; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; - -import java.io.IOException; - -// TODO @fansili:看看能不能用 JsonUtils -/** - * Jackson工具类 - * - * author: fansili - * time: 2024/3/17 10:13 - */ -public class JacksonUtil { - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - /** - * 初始化 ObjectMapper 以美化输出(即格式化JSON内容) - */ - static { - // 美化输出(缩进) - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - // 忽略值为 null 的属性 - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - // 配置一个模块来将 Long 类型转换为 String 类型 - SimpleModule module = new SimpleModule(); - module.addSerializer(Long.class, ToStringSerializer.instance); - objectMapper.registerModule(module); - } - - /** - * 将对象转换为 JSON 字符串 - * - * @param obj 需要序列化的Java对象 - * @return 序列化后的 JSON 字符串 - * @throws JsonProcessingException 当 JSON 序列化过程中出现错误时抛出异常 - */ - public static String toJson(Object obj) { - try { - return objectMapper.writeValueAsString(obj); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - /** - * 将 JSON 字符串反序列化为指定类型的对象 - * - * @param json JSON 字符串 - * @param clazz 目标类型 Class 对象 - * @param 泛型类型参数 - * @return 反序列化后的 Java 对象 - * @throws IOException 当 JSON 解析过程中出现错误时抛出异常 - */ - public static T fromJson(String json, Class clazz) { - try { - return objectMapper.readValue(json, clazz); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - - /** - * 将对象转换为格式化的 JSON 字符串(已启用 INDENT_OUTPUT 功能,所以所有方法都会返回格式化后的 JSON) - * - * @param obj 需要序列化的Java对象 - * @return 格式化后的 JSON 字符串 - * @throws JsonProcessingException 当 JSON 序列化过程中出现错误时抛出异常 - */ - public static String toFormattedJson(Object obj) { - // 已在类初始化时设置了 SerializationFeature.INDENT_OUTPUT,此处无需额外操作 - return toJson(obj); - } -} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java index 14b839747..0a748667b 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java @@ -1,10 +1,9 @@ package cn.iocoder.yudao.framework.ai.chat; import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; -import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenApi; +import cn.iocoder.yudao.framework.ai.chatqianwen.api.QianWenApi; import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenChatClient; import cn.iocoder.yudao.framework.ai.chatqianwen.QianWenOptions; -import com.aliyun.broadscope.bailian.sdk.models.CompletionsRequest; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Flux; diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjInteractionsTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyInteractionsTests.java similarity index 79% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjInteractionsTests.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyInteractionsTests.java index 636e9d2d4..10c9a0923 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjInteractionsTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyInteractionsTests.java @@ -1,8 +1,7 @@ -package cn.iocoder.yudao.framework.ai.mj; +package cn.iocoder.yudao.framework.ai.midjourney; import cn.hutool.core.io.FileUtil; -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; -import cn.iocoder.yudao.framework.ai.midjourney.interactions.MjInteractions; +import cn.iocoder.yudao.framework.ai.midjourney.interactions.MidjourneyInteractions; import cn.iocoder.yudao.framework.ai.midjourney.vo.Attachments; import cn.iocoder.yudao.framework.ai.midjourney.vo.Describe; import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll; @@ -23,7 +22,7 @@ import java.util.Map; * author: fansili * time: 2024/4/4 18:59 */ -public class MjInteractionsTests { +public class MidjourneyInteractionsTests { private MidjourneyConfig midjourneyConfig; @Before @@ -39,14 +38,14 @@ public class MjInteractionsTests { @Test public void mjImageTest() { - MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig); + MidjourneyInteractions mjImagineInteractions = new MidjourneyInteractions(midjourneyConfig); mjImagineInteractions.imagine("童话里应该是什么样子?"); } @Test public void reRollTest() { - MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig); + MidjourneyInteractions mjImagineInteractions = new MidjourneyInteractions(midjourneyConfig); mjImagineInteractions.reRoll(new ReRoll() .setMessageId("1226165117448753243") .setCustomId("MJ::JOB::upsample::3::2aeefbef-43e2-4057-bcf1-43b5f39ab6f7")); @@ -54,7 +53,7 @@ public class MjInteractionsTests { @Test public void uploadAttachmentsTest() { - MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig); + MidjourneyInteractions mjImagineInteractions = new MidjourneyInteractions(midjourneyConfig); UploadAttachmentsRes res = mjImagineInteractions.uploadAttachments( new Attachments().setFileSystemResource( new FileSystemResource(new File("/Users/fansili/Downloads/DSC01402.JPG"))) @@ -64,7 +63,7 @@ public class MjInteractionsTests { @Test public void describeTest() { - MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig); + MidjourneyInteractions mjImagineInteractions = new MidjourneyInteractions(midjourneyConfig); mjImagineInteractions.describe(new Describe() .setFileName("DSC01402.JPG") .setFinalFileName("16826931-2873-45ec-8cfb-0ad81f1a075f/DSC01402.JPG") diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjUtilTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyUtilTests.java similarity index 58% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjUtilTests.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyUtilTests.java index 521e9b5ab..39d64931f 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjUtilTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyUtilTests.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.framework.ai.mj; +package cn.iocoder.yudao.framework.ai.midjourney; -import cn.iocoder.yudao.framework.ai.midjourney.util.MjUtil; +import cn.iocoder.yudao.framework.ai.midjourney.util.MidjourneyUtil; import org.junit.Test; /** @@ -9,14 +9,14 @@ import org.junit.Test; * author: fansili * time: 2024/4/6 21:57 */ -public class MjUtilTests { +public class MidjourneyUtilTests { @Test public void parseContentTest() { String content1 = "**南极应该是什么样子? --v 6.0 --style raw** - <@972721304891453450> (32%) (fast, stealth)"; String content2 = "**南极应该是什么样子? --v 6.0 --style raw** - <@972721304891453450> (fast, stealth)"; - System.err.println(MjUtil.parseContent(content1)); - System.err.println(MjUtil.parseContent(content2)); + System.err.println(MidjourneyUtil.parseContent(content1)); + System.err.println(MidjourneyUtil.parseContent(content2)); } } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjWebSocketTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyWebSocketTests.java similarity index 76% rename from yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjWebSocketTests.java rename to yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyWebSocketTests.java index 9076923b4..a0d672873 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjWebSocketTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyWebSocketTests.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.framework.ai.mj; +package cn.iocoder.yudao.framework.ai.midjourney; import cn.hutool.core.io.FileUtil; -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; -import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MjMessageListener; -import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MjWebSocketStarter; +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MidjourneyMessageListener; +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter; import org.junit.Before; import org.junit.Test; @@ -17,7 +16,7 @@ import java.util.Scanner; * author: fansili * time: 2024/4/3 16:40 */ -public class MjWebSocketTests { +public class MidjourneyWebSocketTests { private MidjourneyConfig midjourneyConfig; @@ -35,8 +34,8 @@ public class MjWebSocketTests { @Test public void startSocketTest() { String wssUrl = "wss://gateway.discord.gg"; - var messageListener = new MjMessageListener(midjourneyConfig); - var webSocketStarter = new MjWebSocketStarter(wssUrl, null, midjourneyConfig, messageListener); + var messageListener = new MidjourneyMessageListener(midjourneyConfig); + var webSocketStarter = new MidjourneyWebSocketStarter(wssUrl, null, midjourneyConfig, messageListener); try { webSocketStarter.start();