Commit 7d0f5fdb7b7a8b2acecda37b4171c3c83a9f7835
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 | } |