Commit 7d0f5fdb7b7a8b2acecda37b4171c3c83a9f7835

Authored by cherishsince
2 parents ed1841e6 29dc77fc

Merge branch 'master-jdk21-ai' of https://gitee.com/cherishsince/ruoyi-vue-pro into master-jdk21-ai

Showing 26 changed files with 322 additions and 60 deletions
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
@@ -120,6 +120,35 @@ @@ -120,6 +120,35 @@
120 <version>4.5.14</version> 120 <version>4.5.14</version>
121 <scope>compile</scope> 121 <scope>compile</scope>
122 </dependency> 122 </dependency>
  123 + <dependency>
  124 + <groupId>org.springframework.boot</groupId>
  125 + <artifactId>spring-boot-starter-websocket</artifactId>
  126 + </dependency>
  127 + <!-- JSON 处理库,如 Jackson -->
  128 + <dependency>
  129 + <groupId>com.fasterxml.jackson.core</groupId>
  130 + <artifactId>jackson-databind</artifactId>
  131 + </dependency>
  132 + <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
  133 + <dependency>
  134 + <groupId>com.squareup.okhttp3</groupId>
  135 + <artifactId>okhttp</artifactId>
  136 + </dependency>
  137 + <dependency>
  138 + <groupId>com.google.guava</groupId>
  139 + <artifactId>guava</artifactId>
  140 + </dependency>
  141 + <dependency>
  142 + <groupId>net.dv8tion</groupId>
  143 + <artifactId>JDA</artifactId>
  144 + <version>5.0.0-beta.21</version>
  145 +<!-- <exclusions>-->
  146 +<!-- <exclusion>-->
  147 +<!-- <groupId>club.minnced</groupId>-->
  148 +<!-- <artifactId>opus-java</artifactId>-->
  149 +<!-- </exclusion>-->
  150 +<!-- </exclusions>-->
  151 + </dependency>
123 </dependencies> 152 </dependencies>
124 153
125 </project> 154 </project>
126 \ No newline at end of file 155 \ No newline at end of file
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/MidjourneyConfig.java
@@ -42,14 +42,20 @@ public class MidjourneyConfig { @@ -42,14 +42,20 @@ public class MidjourneyConfig {
42 * 发送命令 42 * 发送命令
43 */ 43 */
44 private String apiInteractions = "api/v9/interactions"; 44 private String apiInteractions = "api/v9/interactions";
45 - 45 + /**
  46 + * 附件
  47 + */
  48 + private String apiAttachments = "/api/v9/channels/%s/attachments";
  49 + /**
  50 + * 文件上传
  51 + */
  52 + private String apiAttachmentsUpload = "https://discord-attachments-uploads-prd.storage.googleapis.com/";
46 53
47 // 54 //
48 // 浏览器配置 55 // 浏览器配置
49 56
50 private String userAage = "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"; 57 private String userAage = "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";
51 58
52 -  
53 // 59 //
54 // 请求 json 文件 60 // 请求 json 文件
55 61
@@ -65,9 +71,6 @@ public class MidjourneyConfig { @@ -65,9 +71,6 @@ public class MidjourneyConfig {
65 this.token = token; 71 this.token = token;
66 this.guildId = guildId; 72 this.guildId = guildId;
67 this.channelId = channelId; 73 this.channelId = channelId;
68 - this.serverUrl = serverUrl;  
69 - this.apiInteractions = apiInteractions;  
70 - this.userAage = userAage;  
71 this.requestTemplates = requestTemplates; 74 this.requestTemplates = requestTemplates;
72 75
73 // 生成 session id 76 // 生成 session id
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/constants/MjConstants.java
@@ -34,4 +34,8 @@ public final class MjConstants { @@ -34,4 +34,8 @@ public final class MjConstants {
34 public static final String MSG_ATTACHMENTS = "attachments"; 34 public static final String MSG_ATTACHMENTS = "attachments";
35 35
36 36
  37 + //
  38 + //
  39 +
  40 + public static final String HTTP_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";
37 } 41 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjClient.java deleted
1 -package cn.iocoder.yudao.framework.ai.midjourney.interactions;  
2 -  
3 -import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig;  
4 -import org.springframework.http.HttpEntity;  
5 -import org.springframework.http.HttpHeaders;  
6 -import org.springframework.http.MediaType;  
7 -import org.springframework.web.client.RestTemplate;  
8 -  
9 -import java.util.Map;  
10 -  
11 -/**  
12 - * mj client  
13 - * <p>  
14 - * author: fansili  
15 - * time: 2024/4/3 17:37  
16 - */  
17 -public class MjClient {  
18 -  
19 - private static RestTemplate restTemplate = new RestTemplate();  
20 - private static HttpHeaders headers = new HttpHeaders();  
21 -  
22 - private static final String HEADER_REFERER = "https://discord.com/channels/%s/%s";  
23 -  
24 - static {  
25 - headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为JSON  
26 - 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");  
27 - 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");  
28 - }  
29 -  
30 - public static String post(String url, MidjourneyConfig config, String body) {  
31 - // 设置 header  
32 - headers.set("Referer", String.format(HEADER_REFERER, config.getGuildId(), config.getChannelId()));  
33 - headers.set("Authorization", config.getToken());  
34 - // 封装请求体和头部信息  
35 - HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);  
36 - // 发送请求  
37 - return restTemplate.postForObject(url, requestEntity, String.class);  
38 - }  
39 -  
40 -  
41 - public static String setParams(String requestTemplate, Map<String, String> requestParams) {  
42 - for (Map.Entry<String, String> entry : requestParams.entrySet()) {  
43 - requestTemplate = requestTemplate.replace("$".concat(entry.getKey()), entry.getValue());  
44 - }  
45 - return requestTemplate;  
46 - }  
47 -}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/interactions/MjInteractions.java
@@ -3,10 +3,25 @@ package cn.iocoder.yudao.framework.ai.midjourney.interactions; @@ -3,10 +3,25 @@ package cn.iocoder.yudao.framework.ai.midjourney.interactions;
3 import cn.hutool.core.util.IdUtil; 3 import cn.hutool.core.util.IdUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; 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.util.MjUtil;
  8 +import cn.iocoder.yudao.framework.ai.midjourney.vo.Attachments;
  9 +import cn.iocoder.yudao.framework.ai.midjourney.vo.Describe;
6 import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll; 10 import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll;
  11 +import cn.iocoder.yudao.framework.ai.midjourney.vo.UploadAttachmentsRes;
  12 +import com.alibaba.fastjson.JSON;
  13 +import com.alibaba.fastjson.JSONObject;
  14 +import com.google.common.collect.Lists;
7 import com.google.common.collect.Maps; 15 import com.google.common.collect.Maps;
8 import lombok.extern.slf4j.Slf4j; 16 import lombok.extern.slf4j.Slf4j;
  17 +import org.jetbrains.annotations.NotNull;
  18 +import org.springframework.core.io.FileSystemResource;
  19 +import org.springframework.http.*;
  20 +import org.springframework.util.LinkedMultiValueMap;
  21 +import org.springframework.util.MultiValueMap;
  22 +import org.springframework.web.client.RestTemplate;
9 23
  24 +import java.io.IOException;
10 import java.util.HashMap; 25 import java.util.HashMap;
11 26
12 /** 27 /**
@@ -18,9 +33,12 @@ import java.util.HashMap; @@ -18,9 +33,12 @@ import java.util.HashMap;
18 @Slf4j 33 @Slf4j
19 public class MjInteractions { 34 public class MjInteractions {
20 35
21 - private MidjourneyConfig midjourneyConfig;  
22 36
23 - private String url; 37 + private final String url;
  38 + private final MidjourneyConfig midjourneyConfig;
  39 + private final RestTemplate restTemplate = new RestTemplate();
  40 + private static final String HEADER_REFERER = "https://discord.com/channels/%s/%s";
  41 +
24 42
25 public MjInteractions(MidjourneyConfig midjourneyConfig) { 43 public MjInteractions(MidjourneyConfig midjourneyConfig) {
26 this.midjourneyConfig = midjourneyConfig; 44 this.midjourneyConfig = midjourneyConfig;
@@ -37,10 +55,13 @@ public class MjInteractions { @@ -37,10 +55,13 @@ public class MjInteractions {
37 requestParams.put("session_id", midjourneyConfig.getSessionId()); 55 requestParams.put("session_id", midjourneyConfig.getSessionId());
38 requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId())); 56 requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId()));
39 requestParams.put("prompt", prompt); 57 requestParams.put("prompt", prompt);
40 - // 设置参数  
41 - String requestBody = MjClient.setParams(requestTemplate, requestParams); 58 + // 解析 template 参数占位符
  59 + String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams);
  60 + // 获取 header
  61 + HttpHeaders httpHeaders = getHttpHeaders();
42 // 发送请求 62 // 发送请求
43 - String res = MjClient.post(url, midjourneyConfig, requestBody); 63 + HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, httpHeaders);
  64 + String res = restTemplate.postForObject(url, requestEntity, String.class);
44 // 这个 res 只要不返回值,就是成功! 65 // 这个 res 只要不返回值,就是成功!
45 boolean isSuccess = StrUtil.isBlank(res); 66 boolean isSuccess = StrUtil.isBlank(res);
46 if (isSuccess) { 67 if (isSuccess) {
@@ -50,6 +71,8 @@ public class MjInteractions { @@ -50,6 +71,8 @@ public class MjInteractions {
50 return isSuccess; 71 return isSuccess;
51 } 72 }
52 73
  74 +
  75 +
53 public Boolean reRoll(ReRoll reRoll) { 76 public Boolean reRoll(ReRoll reRoll) {
54 // 获取请求模板 77 // 获取请求模板
55 String requestTemplate = midjourneyConfig.getRequestTemplates().get("reroll"); 78 String requestTemplate = midjourneyConfig.getRequestTemplates().get("reroll");
@@ -61,10 +84,88 @@ public class MjInteractions { @@ -61,10 +84,88 @@ public class MjInteractions {
61 requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId())); 84 requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId()));
62 requestParams.put("custom_id", reRoll.getCustomId()); 85 requestParams.put("custom_id", reRoll.getCustomId());
63 requestParams.put("message_id", reRoll.getMessageId()); 86 requestParams.put("message_id", reRoll.getMessageId());
  87 + // 获取 header
  88 + HttpHeaders httpHeaders = getHttpHeaders();
  89 + // 设置参数
  90 + String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams);
  91 + // 发送请求
  92 + HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, httpHeaders);
  93 + String res = restTemplate.postForObject(url, requestEntity, String.class);
  94 + // 这个 res 只要不返回值,就是成功!
  95 + boolean isSuccess = StrUtil.isBlank(res);
  96 + if (isSuccess) {
  97 + return true;
  98 + }
  99 + log.error("请求失败! 请求参数:{} 返回结果! {}", requestBody, res);
  100 + return isSuccess;
  101 + }
  102 +
  103 +
  104 + public UploadAttachmentsRes uploadAttachments(Attachments attachments) {
  105 + // file
  106 + JSONObject fileObj = new JSONObject();
  107 + fileObj.put("id", "0");
  108 + fileObj.put("filename", attachments.getFileSystemResource().getFilename());
  109 + try {
  110 + fileObj.put("file_size", attachments.getFileSystemResource().contentLength());
  111 + } catch (IOException e) {
  112 + throw new RuntimeException(e);
  113 + }
  114 + // 创建用于存放表单数据的MultiValueMap
  115 + MultiValueMap<String, Object> multipartRequest = new LinkedMultiValueMap<>();
  116 + multipartRequest.put("files", Lists.newArrayList(fileObj));
  117 + // 设置header值
  118 + HttpHeaders httpHeaders = new HttpHeaders();
  119 + httpHeaders.setContentType(MediaType.APPLICATION_JSON);
  120 + httpHeaders.set("Authorization", midjourneyConfig.getToken());
  121 + httpHeaders.set("User-Agent", midjourneyConfig.getUserAage());
  122 + httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE);
  123 + httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId()));
  124 + // 创建HttpEntity对象,包含表单数据和头部信息
  125 + HttpEntity<MultiValueMap<String, Object>> multiValueMapHttpEntity = new HttpEntity<>(multipartRequest, httpHeaders);
  126 + // 发送POST请求并接收响应
  127 + String uri = String.format(midjourneyConfig.getApiAttachments(), midjourneyConfig.getChannelId());
  128 + String response = restTemplate.postForObject(midjourneyConfig.getServerUrl().concat(uri), multiValueMapHttpEntity, String.class);
  129 + UploadAttachmentsRes uploadAttachmentsRes = JSON.parseObject(response, UploadAttachmentsRes.class);
  130 +
  131 +
  132 + //
  133 + // 上传文件
  134 + String uploadUrl = uploadAttachmentsRes.getAttachments().getFirst().getUploadUrl();
  135 + String uploadAttachmentsUrl = midjourneyConfig.getApiAttachmentsUpload().concat(uploadUrl);
  136 + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
  137 + HttpEntity<FileSystemResource> fileSystemResourceHttpEntity = new HttpEntity<>(attachments.getFileSystemResource(), httpHeaders);
  138 + ResponseEntity<String> exchange = restTemplate.exchange(uploadUrl, HttpMethod.PUT, fileSystemResourceHttpEntity, String.class);
  139 + String uploadRes = exchange.getBody();
  140 +
  141 + return uploadAttachmentsRes;
  142 + }
  143 +
  144 + public Boolean describe(Describe describe) {
  145 + // 获取请求模板
  146 + String requestTemplate = midjourneyConfig.getRequestTemplates().get("describe");
64 // 设置参数 147 // 设置参数
65 - String requestBody = MjClient.setParams(requestTemplate, requestParams); 148 + HashMap<String, String> requestParams = Maps.newHashMap();
  149 + requestParams.put("guild_id", midjourneyConfig.getGuildId());
  150 + requestParams.put("channel_id", midjourneyConfig.getChannelId());
  151 + requestParams.put("session_id", midjourneyConfig.getSessionId());
  152 + requestParams.put("nonce", String.valueOf(IdUtil.getSnowflakeNextId()));
  153 + requestParams.put("file_name", describe.getFileName());
  154 + requestParams.put("final_file_name", describe.getFinalFileName());
  155 + // 设置 header
  156 + HttpHeaders httpHeaders = new HttpHeaders();
  157 + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); // 设置内容类型为JSON
  158 + httpHeaders.set("Authorization", midjourneyConfig.getToken());
  159 + httpHeaders.set("User-Agent", midjourneyConfig.getUserAage());
  160 + httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE);
  161 + httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId()));
  162 + String requestBody = MjUtil.parseTemplate(requestTemplate, requestParams);
  163 + // 创建表单数据
  164 + MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
  165 + formData.add("payload_json", requestBody);
66 // 发送请求 166 // 发送请求
67 - String res = MjClient.post(url, midjourneyConfig, requestBody); 167 + HttpEntity<MultiValueMap<String, String>> multiValueMapHttpEntity = new HttpEntity<>(formData, httpHeaders);
  168 + String res = restTemplate.postForObject(url, multiValueMapHttpEntity, String.class);
68 // 这个 res 只要不返回值,就是成功! 169 // 这个 res 只要不返回值,就是成功!
69 boolean isSuccess = StrUtil.isBlank(res); 170 boolean isSuccess = StrUtil.isBlank(res);
70 if (isSuccess) { 171 if (isSuccess) {
@@ -73,4 +174,15 @@ public class MjInteractions { @@ -73,4 +174,15 @@ public class MjInteractions {
73 log.error("请求失败! 请求参数:{} 返回结果! {}", requestBody, res); 174 log.error("请求失败! 请求参数:{} 返回结果! {}", requestBody, res);
74 return isSuccess; 175 return isSuccess;
75 } 176 }
  177 +
  178 + @NotNull
  179 + private HttpHeaders getHttpHeaders() {
  180 + HttpHeaders httpHeaders = new HttpHeaders();
  181 + httpHeaders.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为JSON
  182 + httpHeaders.set("Authorization", midjourneyConfig.getToken());
  183 + httpHeaders.set("User-Agent", midjourneyConfig.getUserAage());
  184 + httpHeaders.set("Cookie", MjConstants.HTTP_COOKIE);
  185 + httpHeaders.set("Referer", String.format(HEADER_REFERER, midjourneyConfig.getGuildId(), midjourneyConfig.getChannelId()));
  186 + return httpHeaders;
  187 + }
76 } 188 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/util/MjUtil.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.util; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.ai.midjourney.util;
3 import cn.hutool.core.text.CharSequenceUtil; 3 import cn.hutool.core.text.CharSequenceUtil;
4 import cn.iocoder.yudao.framework.ai.midjourney.MjMessage; 4 import cn.iocoder.yudao.framework.ai.midjourney.MjMessage;
5 5
  6 +import java.util.Map;
6 import java.util.regex.Matcher; 7 import java.util.regex.Matcher;
7 import java.util.regex.Pattern; 8 import java.util.regex.Pattern;
8 9
@@ -19,7 +20,12 @@ public class MjUtil { @@ -19,7 +20,12 @@ public class MjUtil {
19 public static final String CONTENT_REGEX = ".*?\\*\\*(.*?)\\*\\*.+<@\\d+> \\((.*?)\\)"; 20 public static final String CONTENT_REGEX = ".*?\\*\\*(.*?)\\*\\*.+<@\\d+> \\((.*?)\\)";
20 public static final String CONTENT_PROGRESS_REGEX = "\\(([^)]*)\\)"; 21 public static final String CONTENT_PROGRESS_REGEX = "\\(([^)]*)\\)";
21 22
22 - 23 + /**
  24 + * 解析 content 参数
  25 + *
  26 + * @param content
  27 + * @return
  28 + */
23 public static MjMessage.Content parseContent(String content) { 29 public static MjMessage.Content parseContent(String content) {
24 // 有三种格式。 30 // 有三种格式。
25 // 南极应该是什么样子? 31 // 南极应该是什么样子?
@@ -61,4 +67,17 @@ public class MjUtil { @@ -61,4 +67,17 @@ public class MjUtil {
61 return mjContent; 67 return mjContent;
62 } 68 }
63 69
  70 + /**
  71 + * 设置 params
  72 + *
  73 + * @param requestTemplate
  74 + * @param requestParams
  75 + * @return
  76 + */
  77 + public static String parseTemplate(String requestTemplate, Map<String, String> requestParams) {
  78 + for (Map.Entry<String, String> entry : requestParams.entrySet()) {
  79 + requestTemplate = requestTemplate.replace("$".concat(entry.getKey()), entry.getValue());
  80 + }
  81 + return requestTemplate;
  82 + }
64 } 83 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/vo/Attachments.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.midjourney.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.experimental.Accessors;
  5 +import org.springframework.core.io.FileSystemResource;
  6 +
  7 +/**
  8 + * 附件
  9 + * <p>
  10 + * author: fansili
  11 + * time: 2024/4/7 17:18
  12 + */
  13 +@Data
  14 +@Accessors(chain = true)
  15 +public class Attachments {
  16 +
  17 + /**
  18 + * 创建文件系统资源对象
  19 + */
  20 + private FileSystemResource fileSystemResource;
  21 +
  22 +}
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/vo/Describe.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.midjourney.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.experimental.Accessors;
  5 +
  6 +import java.io.File;
  7 +
  8 +/**
  9 + * describe
  10 + *
  11 + * author: fansili
  12 + * time: 2024/4/7 12:30
  13 + */
  14 +@Data
  15 +@Accessors(chain = true)
  16 +public class Describe {
  17 +
  18 + /**
  19 + * 文件名字
  20 + */
  21 + private String fileName;
  22 + /**
  23 + * UploadAttachmentsRes 里面的 finalFileName
  24 + */
  25 + private String finalFileName;
  26 +}
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/vo/ReRoll.java
@@ -11,6 +11,12 @@ import lombok.experimental.Accessors; @@ -11,6 +11,12 @@ import lombok.experimental.Accessors;
11 @Accessors(chain = true) 11 @Accessors(chain = true)
12 public class ReRoll { 12 public class ReRoll {
13 13
  14 + /**
  15 + * socket 消息里面收到的 messageId
  16 + */
14 private String messageId; 17 private String messageId;
  18 + /**
  19 + * socket 消息里面的,操作按钮id(MJ::JOB::upsample::3::2aeefbef-43e2-4057-bcf1-43b5f39ab6f7)
  20 + */
15 private String customId; 21 private String customId;
16 } 22 }
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/midjourney/vo/UploadAttachmentsRes.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.midjourney.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.experimental.Accessors;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * 上传附件 - res
  10 + *
  11 + * author: fansili
  12 + * time: 2024/4/8 13:32
  13 + */
  14 +@Data
  15 +@Accessors(chain = true)
  16 +public class UploadAttachmentsRes {
  17 +
  18 + private List<Attachment> attachments;
  19 +
  20 + @Data
  21 + @Accessors(chain = true)
  22 + public static class Attachment {
  23 + /**
  24 + * 附件的ID。
  25 + */
  26 + private int id;
  27 + /**
  28 + * 附件的上传URL。
  29 + */
  30 + private String uploadUrl;
  31 + /**
  32 + * 上传到服务器的文件名。
  33 + */
  34 + private String uploadFilename;
  35 + }
  36 +}
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/http-body/describe.json 0 → 100644
  1 +{
  2 + "type": 2,
  3 + "guild_id": "$guild_id",
  4 + "channel_id": "$channel_id",
  5 + "application_id": "936929561302675456",
  6 + "session_id": "$session_id",
  7 + "nonce": "$nonce",
  8 + "data": {
  9 + "version": "1204231436023111690",
  10 + "id": "1092492867185950852",
  11 + "name": "describe",
  12 + "type": 1,
  13 + "options": [
  14 + {
  15 + "type": 11,
  16 + "name": "image",
  17 + "value": 0
  18 + }
  19 + ],
  20 + "attachments": [
  21 + {
  22 + "id": "0",
  23 + "filename": "$file_name",
  24 + "uploaded_filename": "$final_file_name"
  25 + }
  26 + ]
  27 + }
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/1.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/1.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/10.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/10.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/11.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/11.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/12.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/12.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/2.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/2.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/3.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/3.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/4.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/4.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/5.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/5.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/6.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/6.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/7.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/7.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/8.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/8.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/图片消息过程/9.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/imageGenerationProcess/9.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/http-body/interactions_type2.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/interactions_type2.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/http-body/interactions_type3.json renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/requestTestJson/interactions_type3.json
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mj/MjInteractionsTests.java
@@ -3,9 +3,14 @@ package cn.iocoder.yudao.framework.ai.mj; @@ -3,9 +3,14 @@ package cn.iocoder.yudao.framework.ai.mj;
3 import cn.hutool.core.io.FileUtil; 3 import cn.hutool.core.io.FileUtil;
4 import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig; 4 import cn.iocoder.yudao.framework.ai.midjourney.MidjourneyConfig;
5 import cn.iocoder.yudao.framework.ai.midjourney.interactions.MjInteractions; 5 import cn.iocoder.yudao.framework.ai.midjourney.interactions.MjInteractions;
  6 +import cn.iocoder.yudao.framework.ai.midjourney.vo.Attachments;
  7 +import cn.iocoder.yudao.framework.ai.midjourney.vo.Describe;
6 import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll; 8 import cn.iocoder.yudao.framework.ai.midjourney.vo.ReRoll;
  9 +import cn.iocoder.yudao.framework.ai.midjourney.vo.UploadAttachmentsRes;
  10 +import com.alibaba.fastjson.JSON;
7 import org.junit.Before; 11 import org.junit.Before;
8 import org.junit.Test; 12 import org.junit.Test;
  13 +import org.springframework.core.io.FileSystemResource;
9 14
10 import java.io.File; 15 import java.io.File;
11 import java.util.HashMap; 16 import java.util.HashMap;
@@ -46,4 +51,23 @@ public class MjInteractionsTests { @@ -46,4 +51,23 @@ public class MjInteractionsTests {
46 .setMessageId("1226165117448753243") 51 .setMessageId("1226165117448753243")
47 .setCustomId("MJ::JOB::upsample::3::2aeefbef-43e2-4057-bcf1-43b5f39ab6f7")); 52 .setCustomId("MJ::JOB::upsample::3::2aeefbef-43e2-4057-bcf1-43b5f39ab6f7"));
48 } 53 }
  54 +
  55 + @Test
  56 + public void uploadAttachmentsTest() {
  57 + MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig);
  58 + UploadAttachmentsRes res = mjImagineInteractions.uploadAttachments(
  59 + new Attachments().setFileSystemResource(
  60 + new FileSystemResource(new File("/Users/fansili/Downloads/DSC01402.JPG")))
  61 + );
  62 + System.err.println(JSON.toJSONString(res));
  63 + }
  64 +
  65 + @Test
  66 + public void describeTest() {
  67 + MjInteractions mjImagineInteractions = new MjInteractions(midjourneyConfig);
  68 + mjImagineInteractions.describe(new Describe()
  69 + .setFileName("DSC01402.JPG")
  70 + .setFinalFileName("16826931-2873-45ec-8cfb-0ad81f1a075f/DSC01402.JPG")
  71 + );
  72 + }
49 } 73 }