diff --git a/docs/config.md b/docs/config.md index af449b64..c8355aa2 100644 --- a/docs/config.md +++ b/docs/config.md @@ -20,6 +20,7 @@ | mj.ng-discord.server | 否 | https://discord.com 反代地址 | | mj.ng-discord.cdn | 否 | https://cdn.discordapp.com 反代地址 | | mj.ng-discord.wss | 否 | wss://gateway.discord.gg 反代地址 | +| mj.ng-discord.upload-server | 否 | https://discord-attachments-uploads-prd.storage.googleapis.com 反代地址 | | mj.translate-way | 否 | 中文prompt翻译成英文的方式,可选null(默认)、baidu、gpt | | mj.baidu-translate.appid | 否 | 百度翻译的appid | | mj.baidu-translate.app-secret | 否 | 百度翻译的app-secret | diff --git a/docs/docker-start.md b/docs/docker-start.md index ae6a3e20..55d2335e 100644 --- a/docs/docker-start.md +++ b/docs/docker-start.md @@ -6,7 +6,7 @@ docker run -d --name midjourney-proxy \ -p 8080:8080 \ -v /xxx/xxx/config:/home/spring/config \ - kratos1937/midjourney-proxy:v1.0.7 + kratos1937/midjourney-proxy:v1.1.0 ``` 3. 访问 `http://ip:port/mj` 查看API文档 @@ -17,5 +17,5 @@ docker run -d --name midjourney-proxy \ -e mj.discord.guild-id=xxx \ -e mj.discord.channel-id=xxx \ -e mj.discord.user-token=xxx \ - kratos1937/midjourney-proxy:v1.0.8 + kratos1937/midjourney-proxy:v1.1.0 ``` diff --git a/pom.xml b/pom.xml index 6b50d7e3..140c6863 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 5.8.18 20220924 5.0.0-beta.9 - 1.1.1-beta0 + 1.1.2-beta0 2.0.0 4.1.0 1.21 diff --git a/src/main/java/com/github/novicezk/midjourney/ProxyProperties.java b/src/main/java/com/github/novicezk/midjourney/ProxyProperties.java index ae4ae488..2455f850 100644 --- a/src/main/java/com/github/novicezk/midjourney/ProxyProperties.java +++ b/src/main/java/com/github/novicezk/midjourney/ProxyProperties.java @@ -187,6 +187,10 @@ public static class NgDiscordConfig { * wss://gateway.discord.gg 反代. */ private String wss; + /** + * https://discord-attachments-uploads-prd.storage.googleapis.com 反代. + */ + private String uploadServer; } @Data diff --git a/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstance.java b/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstance.java index 61994dbf..fcb89704 100644 --- a/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstance.java +++ b/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstance.java @@ -2,7 +2,6 @@ import com.github.novicezk.midjourney.domain.DiscordAccount; -import com.github.novicezk.midjourney.enums.TaskAction; import com.github.novicezk.midjourney.result.Message; import com.github.novicezk.midjourney.result.SubmitResultVO; import com.github.novicezk.midjourney.service.DiscordService; diff --git a/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstanceImpl.java b/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstanceImpl.java index b68399b0..2c922f22 100644 --- a/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstanceImpl.java +++ b/src/main/java/com/github/novicezk/midjourney/loadbalancer/DiscordInstanceImpl.java @@ -42,13 +42,12 @@ public class DiscordInstanceImpl implements DiscordInstance { private final Map> taskFutureMap = Collections.synchronizedMap(new HashMap<>()); public DiscordInstanceImpl(DiscordAccount account, UserWebSocketStarter socketStarter, RestTemplate restTemplate, - TaskStoreService taskStoreService, NotifyService notifyService, - String discordServer, Map paramsMap) { + TaskStoreService taskStoreService, NotifyService notifyService, Map paramsMap) { this.account = account; this.socketStarter = socketStarter; this.taskStoreService = taskStoreService; this.notifyService = notifyService; - this.service = new DiscordServiceImpl(account, restTemplate, discordServer, paramsMap); + this.service = new DiscordServiceImpl(account, restTemplate, paramsMap); this.runningTasks = new CopyOnWriteArrayList<>(); this.taskExecutor = new ThreadPoolTaskExecutor(); this.taskExecutor.setCorePoolSize(account.getCoreSize()); diff --git a/src/main/java/com/github/novicezk/midjourney/loadbalancer/rule/BestWaitIdleRule.java b/src/main/java/com/github/novicezk/midjourney/loadbalancer/rule/BestWaitIdleRule.java index f214df79..c277f099 100644 --- a/src/main/java/com/github/novicezk/midjourney/loadbalancer/rule/BestWaitIdleRule.java +++ b/src/main/java/com/github/novicezk/midjourney/loadbalancer/rule/BestWaitIdleRule.java @@ -1,12 +1,16 @@ package com.github.novicezk.midjourney.loadbalancer.rule; +import cn.hutool.core.util.RandomUtil; import com.github.novicezk.midjourney.loadbalancer.DiscordInstance; +import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * 最少等待空闲. - * 选择等待数最少的实例,如果都不需要等待,则选择空闲数最多的实例 + * 选择等待数最少的实例,如果都不需要等待,则随机选择 */ public class BestWaitIdleRule implements IRule { @@ -15,17 +19,13 @@ public DiscordInstance choose(List instances) { if (instances.isEmpty()) { return null; } - return instances.stream().min((i1, i2) -> { - int wait1 = i1.getRunningFutures().size() - i1.account().getCoreSize(); - int wait2 = i2.getRunningFutures().size() - i2.account().getCoreSize(); - if (wait1 == wait2 && wait1 == 0) { - // 都不需要等待时,选择空闲数最多的 - int idle1 = i1.account().getCoreSize() - i1.getRunningTasks().size(); - int idle2 = i2.account().getCoreSize() - i2.getRunningTasks().size(); - return idle2 - idle1; - } - return wait1 - wait2; - }).orElse(null); + Map> map = instances.stream() + .collect(Collectors.groupingBy(i -> { + int wait = i.getRunningFutures().size() - i.account().getCoreSize(); + return wait >= 0 ? wait : -1; + })); + List instanceList = map.entrySet().stream().min(Comparator.comparingInt(Map.Entry::getKey)).orElseThrow().getValue(); + return RandomUtil.randomEle(instanceList); } } diff --git a/src/main/java/com/github/novicezk/midjourney/service/DiscordServiceImpl.java b/src/main/java/com/github/novicezk/midjourney/service/DiscordServiceImpl.java index babe6430..e600b80c 100644 --- a/src/main/java/com/github/novicezk/midjourney/service/DiscordServiceImpl.java +++ b/src/main/java/com/github/novicezk/midjourney/service/DiscordServiceImpl.java @@ -6,11 +6,17 @@ import com.github.novicezk.midjourney.domain.DiscordAccount; import com.github.novicezk.midjourney.enums.BlendDimensions; import com.github.novicezk.midjourney.result.Message; +import com.github.novicezk.midjourney.support.DiscordHelper; +import com.github.novicezk.midjourney.support.SpringContextHolder; import eu.maxschuster.dataurl.DataUrl; import lombok.extern.slf4j.Slf4j; import org.json.JSONArray; import org.json.JSONObject; -import org.springframework.http.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; @@ -24,21 +30,21 @@ public class DiscordServiceImpl implements DiscordService { private final DiscordAccount account; private final Map paramsMap; private final RestTemplate restTemplate; + private final DiscordHelper discordHelper; private final String discordInteractionUrl; private final String discordAttachmentUrl; private final String discordMessageUrl; - private final String regionUrl; - - public DiscordServiceImpl(DiscordAccount account, RestTemplate restTemplate, String discordServer, Map paramsMap) { + public DiscordServiceImpl(DiscordAccount account, RestTemplate restTemplate, Map paramsMap) { this.account = account; this.restTemplate = restTemplate; + this.discordHelper = SpringContextHolder.getApplicationContext().getBean(DiscordHelper.class); this.paramsMap = paramsMap; + String discordServer = this.discordHelper.getServer(); this.discordInteractionUrl = discordServer + "/api/v9/interactions"; this.discordAttachmentUrl = discordServer + "/api/v9/channels/" + account.getChannelId() + "/attachments"; this.discordMessageUrl = discordServer + "/api/v9/channels/" + account.getChannelId() + "/messages"; - this.regionUrl = "https://936929561302675456.discordsays.com/inpaint/api/submit-job"; } @Override @@ -116,7 +122,6 @@ public Message vary(String messageId, String messageHash, String nonce, St .replace("$vary",vary) .replace("$message_id", messageId) .replace("$message_hash", messageHash); - return postJsonAndCheckStatus(paramsStr); } @@ -222,6 +227,7 @@ public Message sendImageMessage(String content, String finalFileName) { } private void putFile(String uploadUrl, DataUrl dataUrl) { + uploadUrl = this.discordHelper.getDiscordUploadUrl(uploadUrl); HttpHeaders headers = new HttpHeaders(); headers.add("User-Agent", this.account.getUserAgent()); headers.setContentType(MediaType.valueOf(dataUrl.getMimeType())); diff --git a/src/main/java/com/github/novicezk/midjourney/support/DiscordAccountHelper.java b/src/main/java/com/github/novicezk/midjourney/support/DiscordAccountHelper.java index 4ce5875f..1d15a978 100644 --- a/src/main/java/com/github/novicezk/midjourney/support/DiscordAccountHelper.java +++ b/src/main/java/com/github/novicezk/midjourney/support/DiscordAccountHelper.java @@ -38,7 +38,6 @@ public DiscordInstance createDiscordInstance(DiscordAccount account) { var messageListener = new UserMessageListener(account, this.messageHandlers); var webSocketStarter = new UserWebSocketStarter(this.discordHelper.getWss(), account, messageListener, this.properties.getProxy()); return new DiscordInstanceImpl(account, webSocketStarter, this.restTemplate, - this.taskStoreService, this.notifyService, - this.discordHelper.getServer(), this.paramsMap); + this.taskStoreService, this.notifyService, this.paramsMap); } } diff --git a/src/main/java/com/github/novicezk/midjourney/support/DiscordHelper.java b/src/main/java/com/github/novicezk/midjourney/support/DiscordHelper.java index 0107c112..44ec2c26 100644 --- a/src/main/java/com/github/novicezk/midjourney/support/DiscordHelper.java +++ b/src/main/java/com/github/novicezk/midjourney/support/DiscordHelper.java @@ -21,6 +21,10 @@ public class DiscordHelper { * DISCORD_WSS_URL. */ public static final String DISCORD_WSS_URL = "wss://gateway.discord.gg"; + /** + * DISCORD_UPLOAD_URL. + */ + public static final String DISCORD_UPLOAD_URL = "https://discord-attachments-uploads-prd.storage.googleapis.com"; public String getServer() { if (CharSequenceUtil.isBlank(this.properties.getNgDiscord().getServer())) { @@ -55,6 +59,17 @@ public String getWss() { return wssUrl; } + public String getDiscordUploadUrl(String uploadUrl) { + if (CharSequenceUtil.isBlank(this.properties.getNgDiscord().getUploadServer()) || CharSequenceUtil.isBlank(uploadUrl)) { + return uploadUrl; + } + String uploadServer = this.properties.getNgDiscord().getUploadServer(); + if (uploadServer.endsWith("/")) { + uploadServer = uploadServer.substring(0, uploadServer.length() - 1); + } + return uploadUrl.replaceFirst(DISCORD_UPLOAD_URL, uploadServer); + } + public String findTaskIdWithCdnUrl(String url) { if (!CharSequenceUtil.startWith(url, DISCORD_CDN_URL)) { return null; diff --git a/src/main/java/com/github/novicezk/midjourney/support/SpringContextHolder.java b/src/main/java/com/github/novicezk/midjourney/support/SpringContextHolder.java new file mode 100644 index 00000000..058c201f --- /dev/null +++ b/src/main/java/com/github/novicezk/midjourney/support/SpringContextHolder.java @@ -0,0 +1,23 @@ +package com.github.novicezk.midjourney.support; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class SpringContextHolder implements ApplicationContextAware { + private static ApplicationContext APPLICATION_CONTEXT; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + APPLICATION_CONTEXT = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + if (APPLICATION_CONTEXT == null) { + throw new IllegalStateException("SpringContextHolder is not ready."); + } + return APPLICATION_CONTEXT; + } +} diff --git a/src/main/resources/api-params/list-settings.json b/src/main/resources/api-params/list-settings.json new file mode 100644 index 00000000..c8cc8c8f --- /dev/null +++ b/src/main/resources/api-params/list-settings.json @@ -0,0 +1,32 @@ +{ + "type": 2, + "application_id": "936929561302675456", + "guild_id": "$guild_id", + "channel_id": "$channel_id", + "session_id": "12b3d9d8dbc0db4536a0fc4664ab7bad", + "data": { + "version": "1166847114609958943", + "id": "1000850743479255081", + "name": "settings", + "type": 1, + "options": [], + "application_command": { + "id": "1000850743479255081", + "application_id": "936929561302675456", + "version": "1166847114609958943", + "default_member_permissions": null, + "type": 1, + "nsfw": false, + "name": "settings", + "description": "View and adjust your personal settings.", + "dm_permission": true, + "contexts": null, + "integration_types": [ + 0 + ] + }, + "attachments": [] + }, + "nonce": "$nonce", + "analytics_location": "slash_ui" +} \ No newline at end of file diff --git a/src/main/resources/api-params/settings.json b/src/main/resources/api-params/settings.json index fe14072e..1f1f3f6e 100644 --- a/src/main/resources/api-params/settings.json +++ b/src/main/resources/api-params/settings.json @@ -4,7 +4,7 @@ "guild_id": "$guild_id", "channel_id": "$channel_id", "message_flags": 64, - "message_id": "1160405256170110986", + "message_id": "1174275851265781770", "application_id": "936929561302675456", "session_id": "$session_id", "data": { diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt index 5f7c1938..a3581415 100644 --- a/src/main/resources/banner.txt +++ b/src/main/resources/banner.txt @@ -5,4 +5,4 @@ ___ _(/ ___ __ __ _ __ __ _____/ .-/ .-/ .-/ / .-/ (_/ (_/ (_/ (_/ -:: MidJourney Proxy :: v2.5.4 +:: MidJourney Proxy :: v2.5.5 diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 0c607145..1ae61c20 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -13,7 +13,7 @@ knife4j: description: 代理 MidJourney 的discord频道,实现api形式调用AI绘图 concat: novicezk url: https://github.com/novicezk/midjourney-proxy - version: v2.5.4 + version: v2.5.5 terms-of-service-url: https://github.com/novicezk/midjourney-proxy group: api: