Commit 5044a58118408c98367c7d3eaed440abac4accd5
1 parent
28b2fad7
增加mj web socket
Showing
26 changed files
with
110 additions
and
591 deletions
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjConstants.java
0 → 100644
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyInteractionsEnum.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjInteractionsEnum.java
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney; | |
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.constants; | |
| 2 | 2 | |
| 3 | 3 | import lombok.Getter; |
| 4 | 4 | |
| ... | ... | @@ -6,7 +6,7 @@ import lombok.Getter; |
| 6 | 6 | * MJ 命令 |
| 7 | 7 | */ |
| 8 | 8 | @Getter |
| 9 | -public enum MidjourneyInteractionsEnum { | |
| 9 | +public enum MjInteractionsEnum { | |
| 10 | 10 | |
| 11 | 11 | IMAGINE("imagine", "生成图片"), |
| 12 | 12 | DESCRIBE("describe", "生成描述"), |
| ... | ... | @@ -17,7 +17,7 @@ public enum MidjourneyInteractionsEnum { |
| 17 | 17 | |
| 18 | 18 | ; |
| 19 | 19 | |
| 20 | - MidjourneyInteractionsEnum(String value, String message) { | |
| 20 | + MjInteractionsEnum(String value, String message) { | |
| 21 | 21 | this.value =value; |
| 22 | 22 | this.message =message; |
| 23 | 23 | } | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/MessageType.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjMessageTypeEnum.java
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss; | |
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.constants; | |
| 2 | 2 | |
| 3 | 3 | |
| 4 | -public enum MessageType { | |
| 4 | +public enum MjMessageTypeEnum { | |
| 5 | 5 | /** |
| 6 | 6 | * 创建. |
| 7 | 7 | */ |
| ... | ... | @@ -15,7 +15,7 @@ public enum MessageType { |
| 15 | 15 | */ |
| 16 | 16 | DELETE; |
| 17 | 17 | |
| 18 | - public static MessageType of(String type) { | |
| 18 | + public static MjMessageTypeEnum of(String type) { | |
| 19 | 19 | return switch (type) { |
| 20 | 20 | case "MESSAGE_CREATE" -> CREATE; |
| 21 | 21 | case "MESSAGE_UPDATE" -> UPDATE; | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/ReturnCode.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjNotifyCode.java
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss; | |
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.constants; | |
| 2 | 2 | |
| 3 | 3 | import lombok.experimental.UtilityClass; |
| 4 | 4 | |
| 5 | 5 | @UtilityClass |
| 6 | -public final class ReturnCode { | |
| 6 | +public final class MjNotifyCode { | |
| 7 | 7 | /** |
| 8 | 8 | * 成功. |
| 9 | 9 | */ | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/DiscordJadMain.java deleted
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/DiscordWebSocketClient.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo; | |
| 2 | -import cn.hutool.http.useragent.UserAgent; | |
| 3 | -import cn.hutool.http.useragent.UserAgentUtil; | |
| 4 | -import cn.hutool.json.JSONObject; | |
| 5 | -import com.alibaba.fastjson.JSON; | |
| 6 | -import org.springframework.web.socket.*; | |
| 7 | -import org.springframework.web.socket.client.standard.StandardWebSocketClient; | |
| 8 | -import org.springframework.web.socket.handler.TextWebSocketHandler; | |
| 9 | - | |
| 10 | -import java.io.IOException; | |
| 11 | -import java.net.URI; | |
| 12 | -import java.net.URISyntaxException; | |
| 13 | -import java.nio.ByteBuffer; | |
| 14 | -import java.nio.charset.StandardCharsets; | |
| 15 | -import java.util.concurrent.ExecutionException; | |
| 16 | -import java.util.concurrent.Future; | |
| 17 | - | |
| 18 | -/** | |
| 19 | - * https://blog.csdn.net/qq_38490457/article/details/125250135 | |
| 20 | - */ | |
| 21 | -public class DiscordWebSocketClient { | |
| 22 | - | |
| 23 | - private static final String DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/?v=9&encoding=json"; | |
| 24 | - | |
| 25 | - public static void main(String[] args) throws InterruptedException, ExecutionException, IOException, URISyntaxException { | |
| 26 | - StandardWebSocketClient client = new StandardWebSocketClient(); | |
| 27 | - DiscordWebSocketHandler handler = new DiscordWebSocketHandler(); | |
| 28 | - | |
| 29 | - | |
| 30 | - WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); | |
| 31 | - headers.add("Accept-Encoding", "gzip, deflate, br"); | |
| 32 | - headers.add("Accept-Language", "zh-CN,zh;q=0.9"); | |
| 33 | - headers.add("Cache-Control", "no-cache"); | |
| 34 | - headers.add("Pragma", "no-cache"); | |
| 35 | - headers.add("Sec-Websocket-Extensions", "permessage-deflate; client_max_window_bits"); | |
| 36 | - headers.add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"); | |
| 37 | - | |
| 38 | - Future<WebSocketSession> futureSession = client.doHandshake(handler, headers, new URI(DISCORD_GATEWAY_URL)); | |
| 39 | - WebSocketSession session = futureSession.get(); // 这会阻塞直到连接建立 | |
| 40 | - | |
| 41 | - // 登录过程(你需要替换 TOKEN 为你的 Discord Bot Token) | |
| 42 | -// String token = "YOUR_DISCORD_BOT_TOKEN"; // 请替换为你的 Bot Token | |
| 43 | -// String identifyPayload = "{\"op\":2,\"d\":{\"token\":\"" + token + "\",\"properties\":{\"$os\":\"java\",\"$browser\":\"spring-websocket\",\"$device\":\"spring-websocket\"},\"compress\":false,\"large_threshold\":256,\"shard\":[0,1]}}"; | |
| 44 | -// session.sendMessage(new TextMessage(identifyPayload)); | |
| 45 | - | |
| 46 | - // 发送心跳以保持连接活跃 | |
| 47 | - Thread heartbeatThread = new Thread(() -> { | |
| 48 | - int interval = 0; // 初始心跳间隔,后续从 Discord 服务器获取 | |
| 49 | - while (!Thread.currentThread().isInterrupted()) { | |
| 50 | - try { | |
| 51 | - Thread.sleep(interval * 1000); // 等待指定的心跳间隔 | |
| 52 | - session.sendMessage(new TextMessage("{\"op\":1,\"d\":null}")); // 发送心跳包 | |
| 53 | - } catch (Exception e) { | |
| 54 | - e.printStackTrace(); | |
| 55 | - break; | |
| 56 | - } | |
| 57 | - } | |
| 58 | - }); | |
| 59 | - heartbeatThread.start(); | |
| 60 | - | |
| 61 | - // 等待用户输入来保持程序运行(仅用于示例) | |
| 62 | - System.in.read(); | |
| 63 | - | |
| 64 | - // 关闭连接和线程 | |
| 65 | - session.close(); | |
| 66 | - heartbeatThread.interrupt(); | |
| 67 | - } | |
| 68 | - | |
| 69 | - private static class DiscordWebSocketHandler implements WebSocketHandler { | |
| 70 | - | |
| 71 | - @Override | |
| 72 | - public void afterConnectionEstablished(WebSocketSession session) throws Exception { | |
| 73 | - | |
| 74 | - } | |
| 75 | - | |
| 76 | - @Override | |
| 77 | - public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { | |
| 78 | - Object payload = message.getPayload(); | |
| 79 | - | |
| 80 | - session.sendMessage(new TextMessage(JSON.toJSONString(createAuthData()))); | |
| 81 | - String a= ""; | |
| 82 | - } | |
| 83 | - | |
| 84 | - @Override | |
| 85 | - public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { | |
| 86 | - | |
| 87 | - } | |
| 88 | - | |
| 89 | - @Override | |
| 90 | - public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { | |
| 91 | - | |
| 92 | - } | |
| 93 | - | |
| 94 | - @Override | |
| 95 | - public boolean supportsPartialMessages() { | |
| 96 | - return false; | |
| 97 | - } | |
| 98 | - | |
| 99 | - | |
| 100 | - private JSONObject createAuthData() { | |
| 101 | - String userAgentStr = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"; | |
| 102 | - UserAgent userAgent = UserAgentUtil.parse(userAgentStr); | |
| 103 | - String token = "NTY5MDY4NDAxNzEyOTU1Mzky.G4-Fu0.MzD-7ll-ElbXTTgDPHF-WS_UyhMAfbKN3WyyBc"; | |
| 104 | - | |
| 105 | - JSONObject connectionProperties = new JSONObject() | |
| 106 | - .put("browser", userAgent.getBrowser().getName()) | |
| 107 | - .put("browser_user_agent", userAgentStr) | |
| 108 | - .put("browser_version", userAgent.getVersion()) | |
| 109 | - .put("client_build_number", 222963) | |
| 110 | - .put("client_event_source", null) | |
| 111 | - .put("device", "") | |
| 112 | - .put("os", userAgent.getOs().getName()) | |
| 113 | - .put("referer", "https://www.midjourney.com") | |
| 114 | - .put("referrer_current", "") | |
| 115 | - .put("referring_domain", "www.midjourney.com") | |
| 116 | - .put("referring_domain_current", "") | |
| 117 | - .put("release_channel", "stable") | |
| 118 | - .put("system_locale", "zh-CN"); | |
| 119 | - JSONObject presence = new JSONObject() | |
| 120 | - .put("activities", "") | |
| 121 | - .put("afk", false) | |
| 122 | - .put("since", 0) | |
| 123 | - .put("status", "online"); | |
| 124 | - JSONObject clientState = new JSONObject() | |
| 125 | - .put("api_code_version", 0) | |
| 126 | - .put("guild_versions", "") | |
| 127 | - .put("highest_last_message_id", "0") | |
| 128 | - .put("private_channels_version", "0") | |
| 129 | - .put("read_state_version", 0) | |
| 130 | - .put("user_guild_settings_version", -1) | |
| 131 | - .put("user_settings_version", -1); | |
| 132 | - return new JSONObject() | |
| 133 | - .put("capabilities", 16381) | |
| 134 | - .put("client_state", clientState) | |
| 135 | - .put("compress", false) | |
| 136 | - .put("presence", presence) | |
| 137 | - .put("properties", connectionProperties) | |
| 138 | - .put("token", token); | |
| 139 | - } | |
| 140 | - } | |
| 141 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/MidjourneyApi.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo; | |
| 2 | - | |
| 3 | -/** | |
| 4 | - * 文档: https://www.xiubbs.com/t-401-1-1.html | |
| 5 | - * | |
| 6 | - * https://github.com/novicezk/midjourney-proxy/blob/main/README_CN.md | |
| 7 | - * | |
| 8 | - * discord4j、https://github.com/discord-jda/JDA | |
| 9 | - * | |
| 10 | - */ | |
| 11 | -public class MidjourneyApi { | |
| 12 | - | |
| 13 | - | |
| 14 | -// https://discord.com/api/v9/interactions | |
| 15 | -// | |
| 16 | -// payload_json: {"type":2,"application_id":"936929561302675456","guild_id":"1224337694918971392","channel_id":"1224337694918971396","session_id":"696318caed5180a2210e358e44801449","data":{"version":"1166847114203123795","id":"938956540159881230","name":"imagine","type":1,"options":[{"type":3,"name":"prompt","value":"中国的是什么样子"}],"application_command":{"id":"938956540159881230","type":1,"application_id":"936929561302675456","version":"1166847114203123795","name":"imagine","description":"Create images with Midjourney","options":[{"type":3,"name":"prompt","description":"The prompt to imagine","required":true,"description_localized":"The prompt to imagine","name_localized":"prompt"}],"dm_permission":true,"integration_types":[0],"global_popularity_rank":1,"description_localized":"Create images with Midjourney","name_localized":"imagine"},"attachments":[]},"nonce":"1224342266261274624","analytics_location":"slash_ui"} | |
| 17 | -// | |
| 18 | - | |
| 19 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/MjExecute.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyInteractionsEnum; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * mj 命令 | |
| 7 | - */ | |
| 8 | -public interface MjExecute { | |
| 9 | - | |
| 10 | - /** | |
| 11 | - * 执行命令 | |
| 12 | - * | |
| 13 | - * @param mjCommand | |
| 14 | - * @param prompt | |
| 15 | - * @return | |
| 16 | - */ | |
| 17 | - boolean execute(MidjourneyInteractionsEnum mjCommand, String prompt); | |
| 18 | - | |
| 19 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/MjHttpExecute.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo; | |
| 2 | - | |
| 3 | -import cn.hutool.core.io.FileUtil; | |
| 4 | -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyInteractionsEnum; | |
| 5 | -import org.springframework.http.HttpEntity; | |
| 6 | -import org.springframework.http.HttpHeaders; | |
| 7 | -import org.springframework.http.MediaType; | |
| 8 | -import org.springframework.web.client.RestTemplate; | |
| 9 | - | |
| 10 | -import java.nio.charset.Charset; | |
| 11 | - | |
| 12 | -public class MjHttpExecute implements MjExecute { | |
| 13 | - | |
| 14 | - private static final String URL = "https://discord.com/"; | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public boolean execute(MidjourneyInteractionsEnum mjCommand, String prompt) { | |
| 18 | - // 发送的 uri | |
| 19 | - String uri = "api/v9/interactions"; | |
| 20 | - // restTemplate 发送post请求 | |
| 21 | -// String result = restTemplate.postForObject(URL + uri, prompt, String.class); | |
| 22 | - // 加载当前目录下文件 | |
| 23 | - return false; | |
| 24 | - } | |
| 25 | - | |
| 26 | - public static void main(String[] args) { | |
| 27 | - RestTemplate restTemplate = new RestTemplate(); | |
| 28 | - | |
| 29 | - String token = "NTY5MDY4NDAxNzEyOTU1Mzky.G4-Fu0.MzD-7ll-ElbXTTgDPHF-WS_UyhMAfbKN3WyyBc"; | |
| 30 | - String body = FileUtil.readString("/Users/fansili/projects/github/ruoyi-vue-pro/yudao-module-ai" + | |
| 31 | - "/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney" + | |
| 32 | - "/interactions_type2.json", Charset.forName("utf-8")); | |
| 33 | - // 创建HTTP头部 | |
| 34 | - HttpHeaders headers = new HttpHeaders(); | |
| 35 | - headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为JSON | |
| 36 | - headers.set("Authorization", token); // 如果需要,设置认证信息(例如JWT令牌) | |
| 37 | - headers.set("Referer", "https://discord.com/channels/1221445697157468200/1221445862962630706"); // 如果需要,设置认证信息(例如JWT令牌) | |
| 38 | - headers.set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"); // 如果需要,设置认证信息(例如JWT令牌) | |
| 39 | - headers.set("Cookie", "__dcfduid=6ca536c0e3fa11eeb7cbe34c31b49caf; __sdcfduid=6ca536c1e3fa11eeb7cbe34c31b49caf52cce5ffd8983d2a052cf6aba75fe5fe566f2c265902e283ce30dbf98b8c9c93; _gcl_au=1.1.245923998.1710853617; _ga=GA1.1.111061823.1710853617; __cfruid=6385bb3f48345a006b25992db7dcf984e395736d-1712124666; _cfuvid=O09la5ms0ypNptiG0iD8A6BKWlTxz1LG0WR7qRStD7o-1712124666575-0.0.1.1-604800000; locale=zh-CN; cf_clearance=l_YGod1_SUtYxpDVeZXiX7DLLPl1DYrquZe8WVltvYs-1712124668-1.0.1.1-Hl2.fToel23EpF2HCu9J20rB4D7OhhCzoajPSdo.9Up.wPxhvq22DP9RHzEBKuIUlKyH.kJLxXJfAt2N.LD5WQ; OptanonConsent=isIABGlobal=false&datestamp=Wed+Apr+03+2024+14%3A11%3A15+GMT%2B0800+(%E4%B8%AD%E5%9B%BD%E6%A0%87%E5%87%86%E6%97%B6%E9%97%B4)&version=6.33.0&hosts=&landingPath=https%3A%2F%2Fdiscord.com%2F&groups=C0001%3A1%2CC0002%3A1%2CC0003%3A1; _ga_Q149DFWHT7=GS1.1.1712124668.4.1.1712124679.0.0.0"); // 如果需要,设置认证信息(例如JWT令牌) | |
| 40 | - // 封装请求体和头部信息 | |
| 41 | - HttpEntity<String> requestEntity = new HttpEntity<>(body, headers); | |
| 42 | - | |
| 43 | - // 定义请求URL和返回类型 | |
| 44 | - String uri = "api/v9/interactions"; | |
| 45 | - String res = restTemplate.postForObject(URL + uri, requestEntity, String.class); | |
| 46 | - System.err.println("11"); | |
| 47 | - | |
| 48 | - | |
| 49 | - } | |
| 50 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/jad/Constants.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.jad; | |
| 2 | - | |
| 3 | -import lombok.experimental.UtilityClass; | |
| 4 | - | |
| 5 | -@UtilityClass | |
| 6 | -public final class Constants { | |
| 7 | - // 任务扩展属性 start | |
| 8 | - public static final String TASK_PROPERTY_NOTIFY_HOOK = "notifyHook"; | |
| 9 | - public static final String TASK_PROPERTY_FINAL_PROMPT = "finalPrompt"; | |
| 10 | - public static final String TASK_PROPERTY_MESSAGE_ID = "messageId"; | |
| 11 | - public static final String TASK_PROPERTY_MESSAGE_HASH = "messageHash"; | |
| 12 | - public static final String TASK_PROPERTY_PROGRESS_MESSAGE_ID = "progressMessageId"; | |
| 13 | - public static final String TASK_PROPERTY_FLAGS = "flags"; | |
| 14 | - public static final String TASK_PROPERTY_NONCE = "nonce"; | |
| 15 | - public static final String TASK_PROPERTY_DISCORD_INSTANCE_ID = "discordInstanceId"; | |
| 16 | - // 任务扩展属性 end | |
| 17 | - | |
| 18 | - public static final String API_SECRET_HEADER_NAME = "mj-api-secret"; | |
| 19 | - public static final String DEFAULT_DISCORD_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"; | |
| 20 | - | |
| 21 | - public static final String MJ_MESSAGE_HANDLED = "mj_proxy_handled"; | |
| 22 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/jad/DiscordAccount.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.jad; | |
| 2 | - | |
| 3 | -import com.fasterxml.jackson.annotation.JsonIgnore; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.EqualsAndHashCode; | |
| 6 | - | |
| 7 | -@Data | |
| 8 | -@EqualsAndHashCode(callSuper = true) | |
| 9 | - | |
| 10 | -public class DiscordAccount extends DomainObject { | |
| 11 | - | |
| 12 | - | |
| 13 | - private String guildId; | |
| 14 | - | |
| 15 | - private String channelId; | |
| 16 | - | |
| 17 | - private String userToken; | |
| 18 | - | |
| 19 | - private String userAgent = Constants.DEFAULT_DISCORD_USER_AGENT; | |
| 20 | - | |
| 21 | - | |
| 22 | - private boolean enable = true; | |
| 23 | - | |
| 24 | - | |
| 25 | - private int coreSize = 3; | |
| 26 | - | |
| 27 | - private int queueSize = 10; | |
| 28 | - | |
| 29 | - private int timeoutMinutes = 5; | |
| 30 | - | |
| 31 | - @JsonIgnore | |
| 32 | - public String getDisplay() { | |
| 33 | - return this.channelId; | |
| 34 | - } | |
| 35 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/jad/DomainObject.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.jad; | |
| 2 | - | |
| 3 | - | |
| 4 | -import com.fasterxml.jackson.annotation.JsonIgnore; | |
| 5 | -import lombok.Getter; | |
| 6 | -import lombok.Setter; | |
| 7 | - | |
| 8 | -import java.io.Serializable; | |
| 9 | -import java.util.HashMap; | |
| 10 | -import java.util.Map; | |
| 11 | - | |
| 12 | - | |
| 13 | -public class DomainObject implements Serializable { | |
| 14 | - @Getter | |
| 15 | - @Setter | |
| 16 | - protected String id; | |
| 17 | - | |
| 18 | - @Setter | |
| 19 | - protected Map<String, Object> properties; // 扩展属性,仅支持基本类型 | |
| 20 | - | |
| 21 | - @JsonIgnore | |
| 22 | - private final transient Object lock = new Object(); | |
| 23 | - | |
| 24 | - public void sleep() throws InterruptedException { | |
| 25 | - synchronized (this.lock) { | |
| 26 | - this.lock.wait(); | |
| 27 | - } | |
| 28 | - } | |
| 29 | - | |
| 30 | - public void awake() { | |
| 31 | - synchronized (this.lock) { | |
| 32 | - this.lock.notifyAll(); | |
| 33 | - } | |
| 34 | - } | |
| 35 | - | |
| 36 | - public DomainObject setProperty(String name, Object value) { | |
| 37 | - getProperties().put(name, value); | |
| 38 | - return this; | |
| 39 | - } | |
| 40 | - | |
| 41 | - public DomainObject removeProperty(String name) { | |
| 42 | - getProperties().remove(name); | |
| 43 | - return this; | |
| 44 | - } | |
| 45 | - | |
| 46 | - public Object getProperty(String name) { | |
| 47 | - return getProperties().get(name); | |
| 48 | - } | |
| 49 | - | |
| 50 | - @SuppressWarnings("unchecked") | |
| 51 | - public <T> T getPropertyGeneric(String name) { | |
| 52 | - return (T) getProperty(name); | |
| 53 | - } | |
| 54 | - | |
| 55 | - public <T> T getProperty(String name, Class<T> clz) { | |
| 56 | - return getProperty(name, clz, null); | |
| 57 | - } | |
| 58 | - | |
| 59 | - public <T> T getProperty(String name, Class<T> clz, T defaultValue) { | |
| 60 | - Object value = getProperty(name); | |
| 61 | - return value == null ? defaultValue : clz.cast(value); | |
| 62 | - } | |
| 63 | - | |
| 64 | - public Map<String, Object> getProperties() { | |
| 65 | - if (this.properties == null) { | |
| 66 | - this.properties = new HashMap<>(); | |
| 67 | - } | |
| 68 | - return this.properties; | |
| 69 | - } | |
| 70 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/AsyncLockUtils.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss; | |
| 2 | - | |
| 3 | -import cn.hutool.cache.CacheUtil; | |
| 4 | -import cn.hutool.cache.impl.TimedCache; | |
| 5 | -import cn.hutool.core.thread.ThreadUtil; | |
| 6 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.jad.DomainObject; | |
| 7 | -import lombok.experimental.UtilityClass; | |
| 8 | - | |
| 9 | -import java.time.Duration; | |
| 10 | -import java.util.concurrent.ExecutionException; | |
| 11 | -import java.util.concurrent.Future; | |
| 12 | -import java.util.concurrent.TimeUnit; | |
| 13 | -import java.util.concurrent.TimeoutException; | |
| 14 | - | |
| 15 | -@UtilityClass | |
| 16 | -public class AsyncLockUtils { | |
| 17 | - private static final TimedCache<String, LockObject> LOCK_MAP = CacheUtil.newTimedCache(Duration.ofDays(1).toMillis()); | |
| 18 | - | |
| 19 | - public static synchronized LockObject getLock(String key) { | |
| 20 | - return LOCK_MAP.get(key); | |
| 21 | - } | |
| 22 | - | |
| 23 | - public static LockObject waitForLock(String key, Duration duration) throws TimeoutException { | |
| 24 | - LockObject lockObject; | |
| 25 | - synchronized (LOCK_MAP) { | |
| 26 | - if (LOCK_MAP.containsKey(key)) { | |
| 27 | - lockObject = LOCK_MAP.get(key); | |
| 28 | - } else { | |
| 29 | - lockObject = new LockObject(key); | |
| 30 | - LOCK_MAP.put(key, lockObject); | |
| 31 | - } | |
| 32 | - } | |
| 33 | - Future<?> future = ThreadUtil.execAsync(() -> { | |
| 34 | - try { | |
| 35 | - lockObject.sleep(); | |
| 36 | - } catch (InterruptedException e) { | |
| 37 | - Thread.currentThread().interrupt(); | |
| 38 | - } | |
| 39 | - }); | |
| 40 | - try { | |
| 41 | - future.get(duration.toMillis(), TimeUnit.MILLISECONDS); | |
| 42 | - } catch (InterruptedException e) { | |
| 43 | - Thread.currentThread().interrupt(); | |
| 44 | - } catch (ExecutionException e) { | |
| 45 | - // do nothing | |
| 46 | - } catch (TimeoutException e) { | |
| 47 | - future.cancel(true); | |
| 48 | - throw new TimeoutException("Wait Timeout"); | |
| 49 | - } finally { | |
| 50 | - LOCK_MAP.remove(lockObject.getId()); | |
| 51 | - } | |
| 52 | - return lockObject; | |
| 53 | - } | |
| 54 | - | |
| 55 | - public static class LockObject extends DomainObject { | |
| 56 | - | |
| 57 | - public LockObject(String id) { | |
| 58 | - this.id = id; | |
| 59 | - } | |
| 60 | - } | |
| 61 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/DiscordHelper.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss; | |
| 2 | - | |
| 3 | -import cn.hutool.core.text.CharSequenceUtil; | |
| 4 | -import lombok.RequiredArgsConstructor; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -@Component | |
| 8 | -@RequiredArgsConstructor | |
| 9 | -public class DiscordHelper { | |
| 10 | - /** | |
| 11 | - * DISCORD_SERVER_URL. | |
| 12 | - */ | |
| 13 | - public static final String DISCORD_SERVER_URL = "https://discord.com"; | |
| 14 | - /** | |
| 15 | - * DISCORD_CDN_URL. | |
| 16 | - */ | |
| 17 | - public static final String DISCORD_CDN_URL = "https://cdn.discordapp.com"; | |
| 18 | - /** | |
| 19 | - * DISCORD_WSS_URL. | |
| 20 | - */ | |
| 21 | - public static final String DISCORD_WSS_URL = "wss://gateway.discord.gg"; | |
| 22 | - /** | |
| 23 | - * DISCORD_UPLOAD_URL. | |
| 24 | - */ | |
| 25 | - public static final String DISCORD_UPLOAD_URL = "https://discord-attachments-uploads-prd.storage.googleapis.com"; | |
| 26 | - | |
| 27 | - public String getServer() { | |
| 28 | - return DISCORD_SERVER_URL; | |
| 29 | - } | |
| 30 | - | |
| 31 | - public String getCdn() { | |
| 32 | - return DISCORD_CDN_URL; | |
| 33 | - } | |
| 34 | - | |
| 35 | - public String getWss() { | |
| 36 | - return DISCORD_WSS_URL; | |
| 37 | - } | |
| 38 | - | |
| 39 | - public String getMessageHash(String imageUrl) { | |
| 40 | - if (CharSequenceUtil.isBlank(imageUrl)) { | |
| 41 | - return null; | |
| 42 | - } | |
| 43 | - if (CharSequenceUtil.endWith(imageUrl, "_grid_0.webp")) { | |
| 44 | - int hashStartIndex = imageUrl.lastIndexOf("/"); | |
| 45 | - if (hashStartIndex < 0) { | |
| 46 | - return null; | |
| 47 | - } | |
| 48 | - return CharSequenceUtil.sub(imageUrl, hashStartIndex + 1, imageUrl.length() - "_grid_0.webp".length()); | |
| 49 | - } | |
| 50 | - int hashStartIndex = imageUrl.lastIndexOf("_"); | |
| 51 | - if (hashStartIndex < 0) { | |
| 52 | - return null; | |
| 53 | - } | |
| 54 | - return CharSequenceUtil.subBefore(imageUrl.substring(hashStartIndex + 1), ".", true); | |
| 55 | - } | |
| 56 | - | |
| 57 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/user/UserMessageListener.java deleted
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss.user; | |
| 2 | - | |
| 3 | - | |
| 4 | -import cn.hutool.core.thread.ThreadUtil; | |
| 5 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.wss.MessageType; | |
| 6 | -import lombok.extern.slf4j.Slf4j; | |
| 7 | -import net.dv8tion.jda.api.utils.data.DataObject; | |
| 8 | - | |
| 9 | -@Slf4j | |
| 10 | -public class UserMessageListener { | |
| 11 | - | |
| 12 | - public void onMessage(DataObject raw) { | |
| 13 | - MessageType messageType = MessageType.of(raw.getString("t")); | |
| 14 | - if (messageType == null || MessageType.DELETE == messageType) { | |
| 15 | - return; | |
| 16 | - } | |
| 17 | - DataObject data = raw.getObject("d"); | |
| 18 | - System.err.println(data); | |
| 19 | - ThreadUtil.sleep(50); | |
| 20 | -// for (MessageHandler messageHandler : this.messageHandlers) { | |
| 21 | -// if (data.getBoolean(Constants.MJ_MESSAGE_HANDLED, false)) { | |
| 22 | -// return; | |
| 23 | -// } | |
| 24 | -// messageHandler.handle(this.instance, messageType, data); | |
| 25 | -// } | |
| 26 | - } | |
| 27 | -} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjImagineInteractions.java
| ... | ... | @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.interactions; |
| 3 | 3 | import cn.hutool.core.util.IdUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; |
| 6 | -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyInteractionsEnum; | |
| 6 | +import cn.iocoder.yudao.framework.ai.midjourney.constants.MjInteractionsEnum; | |
| 7 | 7 | import com.google.common.collect.Maps; |
| 8 | 8 | import lombok.extern.slf4j.Slf4j; |
| 9 | 9 | |
| ... | ... | @@ -27,7 +27,7 @@ public class MjImagineInteractions implements MjInteractions { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | @Override |
| 30 | - public List<MidjourneyInteractionsEnum> supperInteractions() { | |
| 30 | + public List<MjInteractionsEnum> supperInteractions() { | |
| 31 | 31 | return null; |
| 32 | 32 | } |
| 33 | 33 | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjInteractions.java
| 1 | 1 | package cn.iocoder.yudao.framework.ai.midjourney.interactions; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyInteractionsEnum; | |
| 3 | +import cn.iocoder.yudao.framework.ai.midjourney.constants.MjInteractionsEnum; | |
| 4 | 4 | |
| 5 | 5 | import java.util.List; |
| 6 | 6 | |
| ... | ... | @@ -12,7 +12,7 @@ import java.util.List; |
| 12 | 12 | */ |
| 13 | 13 | public interface MjInteractions { |
| 14 | 14 | |
| 15 | - List<MidjourneyInteractionsEnum> supperInteractions(); | |
| 15 | + List<MjInteractionsEnum> supperInteractions(); | |
| 16 | 16 | |
| 17 | 17 | Boolean execute(String prompt); |
| 18 | 18 | } | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/package-info.java deleted
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/user/FailureCallback.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/FailureCallback.java
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/user/SpringUserWebSocketStarter.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/MjWebSocketStarter.java
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss.user; | |
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.webSocket; | |
| 2 | 2 | |
| 3 | 3 | |
| 4 | -import cn.hutool.core.exceptions.ValidateException; | |
| 5 | 4 | import cn.hutool.core.text.CharSequenceUtil; |
| 6 | 5 | import cn.hutool.core.thread.ThreadUtil; |
| 7 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.jad.DiscordAccount; | |
| 8 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.wss.AsyncLockUtils; | |
| 9 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.wss.ReturnCode; | |
| 10 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.wss.WebSocketStarter; | |
| 6 | +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; | |
| 7 | +import cn.iocoder.yudao.framework.ai.midjourney.constants.MjNotifyCode; | |
| 8 | +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.handler.MjWebSocketHandler; | |
| 9 | +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MjMessageListener; | |
| 11 | 10 | import lombok.extern.slf4j.Slf4j; |
| 12 | 11 | import org.apache.tomcat.websocket.Constants; |
| 13 | 12 | import org.jetbrains.annotations.NotNull; |
| ... | ... | @@ -19,15 +18,14 @@ import org.springframework.web.socket.client.standard.StandardWebSocketClient; |
| 19 | 18 | |
| 20 | 19 | import java.io.IOException; |
| 21 | 20 | import java.net.URI; |
| 22 | -import java.time.Duration; | |
| 23 | 21 | import java.util.concurrent.TimeoutException; |
| 24 | 22 | |
| 25 | 23 | @Slf4j |
| 26 | -public class SpringUserWebSocketStarter implements WebSocketStarter { | |
| 24 | +public class MjWebSocketStarter implements WebSocketStarter { | |
| 27 | 25 | private static final int CONNECT_RETRY_LIMIT = 5; |
| 28 | 26 | |
| 29 | - private final DiscordAccount account; | |
| 30 | - private final UserMessageListener userMessageListener; | |
| 27 | + private final MidjourneyConfig midjourneyConfig; | |
| 28 | + private final MjMessageListener userMessageListener; | |
| 31 | 29 | private final String wssServer; |
| 32 | 30 | private final String resumeWss; |
| 33 | 31 | |
| ... | ... | @@ -36,10 +34,10 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 36 | 34 | private WebSocketSession webSocketSession = null; |
| 37 | 35 | private ResumeData resumeData = null; |
| 38 | 36 | |
| 39 | - public SpringUserWebSocketStarter(String wssServer, String resumeWss, DiscordAccount account, UserMessageListener userMessageListener) { | |
| 37 | + public MjWebSocketStarter(String wssServer, String resumeWss, MidjourneyConfig midjourneyConfig, MjMessageListener userMessageListener) { | |
| 40 | 38 | this.wssServer = wssServer; |
| 41 | 39 | this.resumeWss = resumeWss; |
| 42 | - this.account = account; | |
| 40 | + this.midjourneyConfig = midjourneyConfig; | |
| 43 | 41 | this.userMessageListener = userMessageListener; |
| 44 | 42 | } |
| 45 | 43 | |
| ... | ... | @@ -55,8 +53,8 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 55 | 53 | headers.add("Cache-Control", "no-cache"); |
| 56 | 54 | headers.add("Pragma", "no-cache"); |
| 57 | 55 | headers.add("Sec-Websocket-Extensions", "permessage-deflate; client_max_window_bits"); |
| 58 | - headers.add("User-Agent", this.account.getUserAgent()); | |
| 59 | - var handler = new SpringWebSocketHandler(this.account, this.userMessageListener, this::onSocketSuccess, this::onSocketFailure); | |
| 56 | + headers.add("User-Agent", this.midjourneyConfig.getUserAage()); | |
| 57 | + var handler = new MjWebSocketHandler(this.midjourneyConfig, this.userMessageListener, this::onSocketSuccess, this::onSocketFailure); | |
| 60 | 58 | String gatewayUrl; |
| 61 | 59 | if (reconnect) { |
| 62 | 60 | gatewayUrl = getGatewayServer(this.resumeData.resumeGatewayUrl()) + "/?encoding=json&v=9&compress=zlib-stream"; |
| ... | ... | @@ -72,12 +70,12 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 72 | 70 | socketSessionFuture.addCallback(new ListenableFutureCallback<>() { |
| 73 | 71 | @Override |
| 74 | 72 | public void onFailure(@NotNull Throwable e) { |
| 75 | - onSocketFailure(SpringWebSocketHandler.CLOSE_CODE_EXCEPTION, e.getMessage()); | |
| 73 | + onSocketFailure(MjWebSocketHandler.CLOSE_CODE_EXCEPTION, e.getMessage()); | |
| 76 | 74 | } |
| 77 | 75 | |
| 78 | 76 | @Override |
| 79 | 77 | public void onSuccess(WebSocketSession session) { |
| 80 | - SpringUserWebSocketStarter.this.webSocketSession = session; | |
| 78 | + MjWebSocketStarter.this.webSocketSession = session; | |
| 81 | 79 | } |
| 82 | 80 | }); |
| 83 | 81 | } |
| ... | ... | @@ -85,7 +83,7 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 85 | 83 | private void onSocketSuccess(String sessionId, Object sequence, String resumeGatewayUrl) { |
| 86 | 84 | this.resumeData = new ResumeData(sessionId, sequence, resumeGatewayUrl); |
| 87 | 85 | this.running = true; |
| 88 | - notifyWssLock(ReturnCode.SUCCESS, ""); | |
| 86 | + notifyWssLock(MjNotifyCode.SUCCESS, ""); | |
| 89 | 87 | } |
| 90 | 88 | |
| 91 | 89 | private void onSocketFailure(int code, String reason) { |
| ... | ... | @@ -99,13 +97,12 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 99 | 97 | } |
| 100 | 98 | this.running = false; |
| 101 | 99 | if (code >= 4000) { |
| 102 | - log.warn("[wss-{}] Can't reconnect! Account disabled. Closed by {}({}).", this.account.getDisplay(), code, reason); | |
| 103 | - disableAccount(); | |
| 100 | + log.warn("[wss-{}] Can't reconnect! Account disabled. Closed by {}({}).", this.midjourneyConfig.getChannelId(), code, reason); | |
| 104 | 101 | } else if (code == 2001) { |
| 105 | - log.warn("[wss-{}] Closed by {}({}). Try reconnect...", this.account.getDisplay(), code, reason); | |
| 102 | + log.warn("[wss-{}] Closed by {}({}). Try reconnect...", this.midjourneyConfig.getChannelId(), code, reason); | |
| 106 | 103 | tryReconnect(); |
| 107 | 104 | } else { |
| 108 | - log.warn("[wss-{}] Closed by {}({}). Try new connection...", this.account.getDisplay(), code, reason); | |
| 105 | + log.warn("[wss-{}] Closed by {}({}). Try new connection...", this.midjourneyConfig.getChannelId(), code, reason); | |
| 109 | 106 | tryNewConnect(); |
| 110 | 107 | } |
| 111 | 108 | } |
| ... | ... | @@ -117,7 +114,7 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 117 | 114 | if (e instanceof TimeoutException) { |
| 118 | 115 | closeSocketSessionWhenIsOpen(); |
| 119 | 116 | } |
| 120 | - log.warn("[wss-{}] Reconnect fail: {}, Try new connection...", this.account.getDisplay(), e.getMessage()); | |
| 117 | + log.warn("[wss-{}] Reconnect fail: {}, Try new connection...", this.midjourneyConfig.getChannelId(), e.getMessage()); | |
| 121 | 118 | ThreadUtil.sleep(1000); |
| 122 | 119 | tryNewConnect(); |
| 123 | 120 | } |
| ... | ... | @@ -132,39 +129,19 @@ public class SpringUserWebSocketStarter implements WebSocketStarter { |
| 132 | 129 | if (e instanceof TimeoutException) { |
| 133 | 130 | closeSocketSessionWhenIsOpen(); |
| 134 | 131 | } |
| 135 | - log.warn("[wss-{}] New connect fail ({}): {}", this.account.getDisplay(), i, e.getMessage()); | |
| 132 | + log.warn("[wss-{}] New connect fail ({}): {}", this.midjourneyConfig.getChannelId(), i, e.getMessage()); | |
| 136 | 133 | ThreadUtil.sleep(5000); |
| 137 | 134 | } |
| 138 | 135 | } |
| 139 | - log.error("[wss-{}] Account disabled", this.account.getDisplay()); | |
| 140 | - disableAccount(); | |
| 136 | + log.error("[wss-{}] Account disabled", this.midjourneyConfig.getChannelId()); | |
| 141 | 137 | } |
| 142 | 138 | |
| 143 | 139 | public void tryStart(boolean reconnect) throws Exception { |
| 144 | 140 | start(reconnect); |
| 145 | - AsyncLockUtils.LockObject lock = AsyncLockUtils.waitForLock("wss:" + this.account.getId(), Duration.ofSeconds(20)); | |
| 146 | - int code = lock.getProperty("code", Integer.class, 0); | |
| 147 | - if (code == ReturnCode.SUCCESS) { | |
| 148 | - log.debug("[wss-{}] {} success.", this.account.getDisplay(), reconnect ? "Reconnect" : "New connect"); | |
| 149 | - return; | |
| 150 | - } | |
| 151 | - throw new ValidateException(lock.getProperty("description", String.class)); | |
| 152 | 141 | } |
| 153 | 142 | |
| 154 | 143 | private void notifyWssLock(int code, String reason) { |
| 155 | - AsyncLockUtils.LockObject lock = AsyncLockUtils.getLock("wss:" + this.account.getId()); | |
| 156 | - if (lock != null) { | |
| 157 | - lock.setProperty("code", code); | |
| 158 | - lock.setProperty("description", reason); | |
| 159 | - lock.awake(); | |
| 160 | - } | |
| 161 | - } | |
| 162 | - | |
| 163 | - private void disableAccount() { | |
| 164 | - if (Boolean.FALSE.equals(this.account.isEnable())) { | |
| 165 | - return; | |
| 166 | - } | |
| 167 | - this.account.setEnable(false); | |
| 144 | + System.err.println("notifyWssLock: " + code + " - " + reason); | |
| 168 | 145 | } |
| 169 | 146 | |
| 170 | 147 | private void closeSocketSessionWhenIsOpen() { | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/user/SuccessCallback.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/SuccessCallback.java
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/WebSocketStarter.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/WebSocketStarter.java
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/wss/user/SpringWebSocketHandler.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/handler/MjWebSocketHandler.java
| 1 | -package cn.iocoder.yudao.framework.ai.midjourney.demo.wss.user; | |
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.webSocket.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.text.CharSequenceUtil; |
| 4 | 4 | import cn.hutool.core.thread.ThreadUtil; |
| 5 | 5 | import cn.hutool.core.util.RandomUtil; |
| 6 | 6 | import cn.hutool.http.useragent.UserAgent; |
| 7 | 7 | import cn.hutool.http.useragent.UserAgentUtil; |
| 8 | -import cn.iocoder.yudao.framework.ai.midjourney.demo.jad.DiscordAccount; | |
| 8 | +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; | |
| 9 | +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.FailureCallback; | |
| 10 | +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.SuccessCallback; | |
| 11 | +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener.MjMessageListener; | |
| 9 | 12 | import lombok.Setter; |
| 10 | 13 | import lombok.extern.slf4j.Slf4j; |
| 11 | 14 | import net.dv8tion.jda.api.utils.data.DataArray; |
| ... | ... | @@ -26,13 +29,13 @@ import java.util.concurrent.ScheduledExecutorService; |
| 26 | 29 | import java.util.concurrent.TimeUnit; |
| 27 | 30 | |
| 28 | 31 | @Slf4j |
| 29 | -public class SpringWebSocketHandler implements WebSocketHandler { | |
| 32 | +public class MjWebSocketHandler implements WebSocketHandler { | |
| 30 | 33 | public static final int CLOSE_CODE_RECONNECT = 2001; |
| 31 | 34 | public static final int CLOSE_CODE_INVALIDATE = 1009; |
| 32 | 35 | public static final int CLOSE_CODE_EXCEPTION = 1011; |
| 33 | 36 | |
| 34 | - private final DiscordAccount account; | |
| 35 | - private final UserMessageListener userMessageListener; | |
| 37 | + private final MidjourneyConfig midjourneyConfig; | |
| 38 | + private final MjMessageListener userMessageListener; | |
| 36 | 39 | private final SuccessCallback successCallback; |
| 37 | 40 | private final FailureCallback failureCallback; |
| 38 | 41 | |
| ... | ... | @@ -54,8 +57,11 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 54 | 57 | |
| 55 | 58 | private final Decompressor decompressor = new ZlibDecompressor(2048); |
| 56 | 59 | |
| 57 | - public SpringWebSocketHandler(DiscordAccount account, UserMessageListener userMessageListener, SuccessCallback successCallback, FailureCallback failureCallback) { | |
| 58 | - this.account = account; | |
| 60 | + public MjWebSocketHandler(MidjourneyConfig account, | |
| 61 | + MjMessageListener userMessageListener, | |
| 62 | + SuccessCallback successCallback, | |
| 63 | + FailureCallback failureCallback) { | |
| 64 | + this.midjourneyConfig = account; | |
| 59 | 65 | this.userMessageListener = userMessageListener; |
| 60 | 66 | this.successCallback = successCallback; |
| 61 | 67 | this.failureCallback = failureCallback; |
| ... | ... | @@ -70,7 +76,7 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 70 | 76 | |
| 71 | 77 | @Override |
| 72 | 78 | public void handleTransportError(@NotNull WebSocketSession session, @NotNull Throwable e) throws Exception { |
| 73 | - log.error("[wss-{}] Transport error", this.account.getDisplay(), e); | |
| 79 | + log.error("[wss-{}] Transport error", this.midjourneyConfig.getChannelId(), e); | |
| 74 | 80 | onFailure(CLOSE_CODE_EXCEPTION, "transport error"); |
| 75 | 81 | } |
| 76 | 82 | |
| ... | ... | @@ -108,7 +114,7 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 108 | 114 | case WebSocketCode.RECONNECT -> onFailure(CLOSE_CODE_RECONNECT, "receive server reconnect"); |
| 109 | 115 | case WebSocketCode.INVALIDATE_SESSION -> onFailure(CLOSE_CODE_INVALIDATE, "receive session invalid"); |
| 110 | 116 | case WebSocketCode.DISPATCH -> handleDispatch(data); |
| 111 | - default -> log.debug("[wss-{}] Receive unknown code: {}.", account.getDisplay(), data); | |
| 117 | + default -> log.debug("[wss-{}] Receive unknown code: {}.", midjourneyConfig.getChannelId(), data); | |
| 112 | 118 | } |
| 113 | 119 | } |
| 114 | 120 | |
| ... | ... | @@ -129,7 +135,7 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 129 | 135 | try { |
| 130 | 136 | this.userMessageListener.onMessage(raw); |
| 131 | 137 | } catch (Exception e) { |
| 132 | - log.error("[wss-{}] Handle message error", this.account.getDisplay(), e); | |
| 138 | + log.error("[wss-{}] Handle message error", this.midjourneyConfig.getChannelId(), e); | |
| 133 | 139 | } |
| 134 | 140 | } |
| 135 | 141 | } |
| ... | ... | @@ -160,7 +166,7 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 160 | 166 | if (CharSequenceUtil.isBlank(this.sessionId)) { |
| 161 | 167 | sendMessage(session, WebSocketCode.IDENTIFY, this.authData); |
| 162 | 168 | } else { |
| 163 | - var data = DataObject.empty().put("token", this.account.getUserToken()) | |
| 169 | + var data = DataObject.empty().put("token", this.midjourneyConfig.getToken()) | |
| 164 | 170 | .put("session_id", this.sessionId).put("seq", this.sequence); |
| 165 | 171 | sendMessage(session, WebSocketCode.RESUME, data); |
| 166 | 172 | } |
| ... | ... | @@ -171,7 +177,7 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 171 | 177 | try { |
| 172 | 178 | session.sendMessage(new TextMessage(data.toString())); |
| 173 | 179 | } catch (IOException e) { |
| 174 | - log.error("[wss-{}] Send message error", this.account.getDisplay(), e); | |
| 180 | + log.error("[wss-{}] Send message error", this.midjourneyConfig.getChannelId(), e); | |
| 175 | 181 | onFailure(CLOSE_CODE_EXCEPTION, "send message error"); |
| 176 | 182 | } |
| 177 | 183 | } |
| ... | ... | @@ -201,10 +207,10 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 201 | 207 | } |
| 202 | 208 | |
| 203 | 209 | private DataObject createAuthData() { |
| 204 | - UserAgent userAgent = UserAgentUtil.parse(this.account.getUserAgent()); | |
| 210 | + UserAgent userAgent = UserAgentUtil.parse(this.midjourneyConfig.getUserAage()); | |
| 205 | 211 | DataObject connectionProperties = DataObject.empty() |
| 206 | 212 | .put("browser", userAgent.getBrowser().getName()) |
| 207 | - .put("browser_user_agent", this.account.getUserAgent()) | |
| 213 | + .put("browser_user_agent", this.midjourneyConfig.getUserAage()) | |
| 208 | 214 | .put("browser_version", userAgent.getVersion()) |
| 209 | 215 | .put("client_build_number", 222963) |
| 210 | 216 | .put("client_event_source", null) |
| ... | ... | @@ -235,6 +241,6 @@ public class SpringWebSocketHandler implements WebSocketHandler { |
| 235 | 241 | .put("compress", false) |
| 236 | 242 | .put("presence", presence) |
| 237 | 243 | .put("properties", connectionProperties) |
| 238 | - .put("token", this.account.getUserToken()); | |
| 244 | + .put("token", this.midjourneyConfig.getToken()); | |
| 239 | 245 | } |
| 240 | 246 | } | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/webSocket/listener/MjMessageListener.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.midjourney.webSocket.listener; | |
| 2 | + | |
| 3 | + | |
| 4 | +import cn.hutool.core.text.CharSequenceUtil; | |
| 5 | +import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; | |
| 6 | +import cn.iocoder.yudao.framework.ai.midjourney.constants.MjConstants; | |
| 7 | +import cn.iocoder.yudao.framework.ai.midjourney.constants.MjMessageTypeEnum; | |
| 8 | +import lombok.extern.slf4j.Slf4j; | |
| 9 | +import net.dv8tion.jda.api.utils.data.DataObject; | |
| 10 | + | |
| 11 | +@Slf4j | |
| 12 | +public class MjMessageListener { | |
| 13 | + | |
| 14 | + private MidjourneyConfig midjourneyConfig; | |
| 15 | + | |
| 16 | + public MjMessageListener(MidjourneyConfig midjourneyConfig) { | |
| 17 | + this.midjourneyConfig = midjourneyConfig; | |
| 18 | + } | |
| 19 | + | |
| 20 | + public void onMessage(DataObject raw) { | |
| 21 | + MjMessageTypeEnum messageType = MjMessageTypeEnum.of(raw.getString("t")); | |
| 22 | + if (messageType == null || MjMessageTypeEnum.DELETE == messageType) { | |
| 23 | + return; | |
| 24 | + } | |
| 25 | + DataObject data = raw.getObject("d"); | |
| 26 | + if (ignoreAndLogMessage(data, messageType)) { | |
| 27 | + return; | |
| 28 | + } | |
| 29 | + System.err.println(data); | |
| 30 | +// if (data.getBoolean(Constants.MJ_MESSAGE_HANDLED, false)) { | |
| 31 | +// return; | |
| 32 | +// } | |
| 33 | + } | |
| 34 | + | |
| 35 | + private boolean ignoreAndLogMessage(DataObject data, MjMessageTypeEnum messageType) { | |
| 36 | + String channelId = data.getString(MjConstants.CHANNEL_ID); | |
| 37 | + if (!CharSequenceUtil.equals(channelId, midjourneyConfig.getChannelId())) { | |
| 38 | + return true; | |
| 39 | + } | |
| 40 | + String authorName = data.optObject("author").map(a -> a.getString("username")).orElse("System"); | |
| 41 | + log.debug("{} - {} - {}: {}", midjourneyConfig.getChannelId(), messageType.name(), authorName, data.opt("content").orElse("")); | |
| 42 | + return false; | |
| 43 | + } | |
| 44 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/interactions_type2.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/http-body/interactions_type2.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/demo/interactions_type3.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/http-body/interactions_type3.json