Explorar o código

midjourney回调

zwhui %!s(int64=2) %!d(string=hai) anos
pai
achega
6d6100cb05

+ 5 - 2
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -1,5 +1,6 @@
 package com.cyksj.redis;
 
+import com.cyksj.common.constant.RandomConstant;
 import com.cyksj.common.util.StringUtil;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
@@ -213,7 +214,7 @@ public class RedisService {
      * @param map 对应多个键值
      * @return true 成功 false 失败
      */
-    public Boolean hmset(String key, Map<String, Object> map) {
+    public Boolean hmset(String key, Map<Object, Object> map) {
         try {
             redisTemplate.opsForHash().putAll(key, map);
             return true;
@@ -838,7 +839,9 @@ public class RedisService {
         MIDJOURNEY_RELAX_LIMIT("midjourney:relax:limit:", "midjourney relax次数", 60 * 60 * 48L),
         MIDJOURNEY_EXPIRE_TIME("midjourney:expire:time:", "midjourney expire time", 60 * 60 * 48L),
         MIDJOURNEY_USER("midjourney:user:", "midjourney user", 60 * 60 * 2L),
-
+        MIDJOURNEY_CONVERSATION("midjourney:conversation:", "midjourney conversation", 60 * 60 * 2L),
+        MIDJOURNEY_ACCOUNT("midjourney:account:", "midjourney account", 60 * 60 * 48L),
+        MIDJOURNEY_QUERY("midjourney:query:", "midjourney query", 60 * 60 * 2L),
         ;
 
         private String name;

+ 5 - 1
netflix-service/src/main/java/com/cyksj/service/midjourney/MidjourneyService.java

@@ -3,8 +3,10 @@ package com.cyksj.service.midjourney;
 import com.cyksj.model.dto.BlendDimensions;
 import com.cyksj.model.entity.MidjourneyUser;
 import com.cyksj.model.entity.MidjourneyUserConversation;
+import com.cyksj.model.response.SubmitResult;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author zwhui
@@ -23,7 +25,9 @@ public interface MidjourneyService {
 
     List<MidjourneyUserConversation> listConversationByIds(Integer mode, List<Long> ids) throws Exception;
 
-    MidjourneyUserConversation submitAction(MidjourneyUser user, Long taskId, String customId) throws Exception;
+    SubmitResult submitAction(MidjourneyUser user, Long taskId, String customId, Long num) throws Exception;
 
     MidjourneyUserConversation cancelConversation(MidjourneyUser user, Long id);
+
+    void notifyHook(String conversation) throws Exception;
 }

+ 195 - 51
netflix-service/src/main/java/com/cyksj/service/midjourney/impl/MidjourneyServiceImpl.java

@@ -7,27 +7,44 @@ import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.EnvCommonService;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.common.util.Codec;
+import com.cyksj.common.util.J11HttpC;
 import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
 import com.cyksj.mapper.MidjourneyUserConversationMapper;
+import com.cyksj.mapper.MidjourneyUserMapper;
 import com.cyksj.model.dto.BlendDimensions;
 import com.cyksj.model.dto.MessageButton;
+import com.cyksj.model.entity.MidjourneyAccount;
 import com.cyksj.model.entity.MidjourneyUser;
 import com.cyksj.model.entity.MidjourneyUserConversation;
 import com.cyksj.model.response.SubmitResult;
 import com.cyksj.redis.RedisService;
+import com.cyksj.service.midjourney.MidjourneyAccountService;
 import com.cyksj.service.midjourney.MidjourneyService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import javax.imageio.ImageIO;
 import javax.imageio.stream.FileImageOutputStream;
-import java.io.IOException;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.net.http.HttpResponse;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.time.ZoneOffset;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
@@ -52,8 +69,17 @@ public class MidjourneyServiceImpl implements MidjourneyService {
 
     private final RedisService redisService;
 
+    private final MidjourneyUserMapper midjourneyUserMapper;
+
+    @Value("${midjourney.url}")
+    private String midjourneyHost;
+
+    private final EnvCommonService envCommonService;
+
     private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
 
+    private final MidjourneyAccountService midjourneyAccountService;
+
 
     @Override
     public MidjourneyUserConversation submitImagine(MidjourneyUser user, String prompt, List<String> base64Array) throws Exception {
@@ -62,7 +88,7 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         if (CollectionUtil.isNotEmpty(base64Array)) {
             imagineParam.put("base64Array", base64Array);
         }
-        SubmitResult result = submit(user.getMode(),"imagine", imagineParam);
+        SubmitResult result = submit(user.getMode(),"imagine", null,imagineParam);
         return saveConversation(user.getId(), user.getMode(),Long.parseLong(result.getResult()),result.getProperties(),"IMAGINE", StringUtils.EMPTY);
     }
 
@@ -84,7 +110,7 @@ public class MidjourneyServiceImpl implements MidjourneyService {
     @Override
     public MidjourneyUserConversation submitDescribe(MidjourneyUser user, String base64) throws Exception {
         Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>()).put("state", user.getId()).put("base64", base64).build();
-        SubmitResult result = submit(user.getMode(),"describe", param);
+        SubmitResult result = submit(user.getMode(),"describe", null, param);
         return saveConversation(user.getId(), user.getMode(),Long.parseLong(result.getResult()),result.getProperties(),"DESCRIBE", StringUtils.EMPTY);
     }
 
@@ -95,14 +121,14 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         if (dimensions != null) {
             param.put("dimensions", dimensions);
         }
-        SubmitResult result = submit(user.getMode(),"blend", param);
+        SubmitResult result = submit(user.getMode(),"blend", null, param);
         Map<String, Object> properties = result.getProperties();
-        if (user.getMode() == 1) {
-            String finalPrompt = "%s --ar %s --style raw --s 250";
-            List<String> picList = uploadBase64Pic(base64Array);
-            String pics = picList.stream().map(pic -> "<" + pic + ">").collect(Collectors.joining(" "));
-            properties.put("finalPrompt", String.format(finalPrompt, pics,dimensions.getValue()));
-        }
+//        if (user.getMode() == 1) {
+//            String finalPrompt = "%s --ar %s --style raw --s 250";
+//            List<String> picList = uploadBase64Pic(base64Array);
+//            String pics = picList.stream().map(pic -> "<" + pic + ">").collect(Collectors.joining(" "));
+//            properties.put("finalPrompt", String.format(finalPrompt, pics,dimensions.getValue()));
+//        }
         return saveConversation(user.getId(), user.getMode(), Long.parseLong(result.getResult()),properties,"BLEND", StringUtils.EMPTY);
     }
 
@@ -116,7 +142,7 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         if (StringUtils.isNotBlank(maskBase64)) {
             param.put("maskBase64", maskBase64);
         }
-        SubmitResult result = submit(user.getMode(),"modal", param);
+        SubmitResult result = submit(user.getMode(),"modal", null, param);
         return saveConversation(user.getId(),  user.getMode(),Long.parseLong(result.getResult()),result.getProperties(),"MODAL", StringUtils.EMPTY);
     }
 
@@ -124,25 +150,45 @@ public class MidjourneyServiceImpl implements MidjourneyService {
     public MidjourneyUserConversation submitShorten(MidjourneyUser user, String prompt) throws Exception {
         Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
                 .put("prompt", prompt).put("state", user.getId()).build();
-        SubmitResult result = submit(user.getMode(),"shorten", param);
+        SubmitResult result = submit(user.getMode(),"shorten", null, param);
         return saveConversation(user.getId(), user.getMode(), Long.parseLong(result.getResult()),result.getProperties(),"SHORTEN", StringUtils.EMPTY);
     }
 
     /**
      * 恢复次数
      */
-    public void recoverUserLimit(Long id,Integer mode,Integer num){
+    public Long recoverUserLimit(Long id,Integer mode,Long num){
         if (mode == 1){
-            redisService.incr(RedisService.key.MIDJOURNEY_FAST_LIMIT.getName() + id, 1L);
+            num =  redisService.incr(RedisService.key.MIDJOURNEY_FAST_LIMIT.getName() + id, 1L);
         }
         if (mode == 2){
             if (num != null) {
-                redisService.incr(RedisService.key.MIDJOURNEY_RELAX_LIMIT.getName() + id, 1L);
+                num = redisService.incr(RedisService.key.MIDJOURNEY_RELAX_LIMIT.getName() + id, 1L);
             }
         }
+        return num;
+    }
+    /**
+     * 同步数据库
+     */
+    public void syncUser(Long id,Integer mode,Long num){
+        log.info("同步次数 id:{},mode:{},num:{}",id,mode,num);
+        if (num == null){
+            return;
+        }
+        LambdaUpdateWrapper<MidjourneyUser> wrapper = Wrappers.lambdaUpdate(MidjourneyUser.class)
+                .eq(MidjourneyUser::getId, id);
+        if (mode == 1){
+            wrapper.set(MidjourneyUser::getMjFastNum, num);
+        }
+        if (mode == 2){
+            wrapper.set(MidjourneyUser::getMjRelaxNum, num);
+        }
+        midjourneyUserMapper.update(null, wrapper);
     }
+
     @Override
-    public MidjourneyUserConversation submitAction(MidjourneyUser user, Long taskId, String customId) throws Exception {
+    public SubmitResult submitAction(MidjourneyUser user, Long taskId, String customId,Long num) throws Exception {
         MidjourneyUserConversation conversation = conversationMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUserConversation.class).eq(MidjourneyUserConversation::getTaskId, taskId).last("limit 1"));
         if (conversation == null) {
             throw BusinessRuntimeException.getInstance("关联任务不存在或已失效");
@@ -150,44 +196,50 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         if (!user.getMode().equals(conversation.getMode())) {
             throw BusinessRuntimeException.getInstance("当前出图模式与关联任务出图模式不符");
         }
-        AtomicBoolean flag = new AtomicBoolean(false);
         if (StringUtils.isNotBlank(conversation.getButtons())){
             List<MessageButton> messageButtons = Jsons.parseList(conversation.getButtons(), MessageButton.class);
             messageButtons.forEach(button -> {
                 if (button.getCustomId().equals(customId)) {
                     log.info("action customId:{}", customId);
                     button.setStyle(3);
-                    if (button.getLabel().contains("Vary") || button.getCustomId().contains("::pan_")
-                            || button.getEmoji().equals("🔄") || button.getCustomId().contains("PromptAnalyzer:")
-                            || button.getCustomId().contains("PicReader::") || button.getCustomId().contains("::variation::")
-                            || button.getCustomId().contains("::CustomZoom::")) {
-                        flag.set(true);
-                    }
                 }
             });
             conversation.setButtons(Jsons.toJson(messageButtons));
         }
-        conversation.setBookmark(customId.contains("BOOKMARK"));
-        conversationMapper.updateById(conversation);
-        if (conversation.getBookmark()) {
-            return conversation;
+        if (customId.contains("BOOKMARK")) {
+            conversation.setBookmark(true);
+            conversationMapper.updateById(conversation);
+            return null;
         }
         Map<String, Object> param = MapUtil.builder(new HashMap<String,Object>())
                 .put("taskId", taskId).put("state", user.getId()).put("customId", customId).build();
-        SubmitResult result = submit(user.getMode(),"action", param);
-        if (flag.get()) {
+        SubmitResult result = submit(user.getMode(),"action", conversation.getInstanceId(),param);
+        if (result.getCode() == 21) {
             // 以上操作有弹窗确认,恢复次数
-            recoverUserLimit(user.getId(), user.getMode(),user.getMjRelaxNum());
+            recoverUserLimit(user.getId(), user.getMode(),num);
+        }else {
+            syncUser(user.getId(), user.getMode(),num);
         }
-        return saveConversation(user.getId(), user.getMode(), Long.parseLong(result.getResult()),result.getProperties(),"ACTION", StringUtils.EMPTY);
+        saveConversation(user.getId(), user.getMode(), Long.parseLong(result.getResult()),result.getProperties(),"ACTION", StringUtils.EMPTY);
+        return result;
     }
 
 
-    public SubmitResult submit(Integer mode,String action, Map<String, Object> param) throws Exception {
+    public SubmitResult submit(Integer mode,String action,Long instanceId, Map<String, Object> param) throws Exception {
+        String url = "";
         if (mode == 1) {
             param.put("mode", "FAST");
+            url = FAST_HOST;
+        } else if (mode == 2) {
+            url = RELAX_HOST;
+            String accountWithMinUsage;
+            //慢速查询在使用次数最少的账号
+            accountWithMinUsage = getAccountWithMinUsage(instanceId);
+            param.put("accountFilter",MapUtil.builder(new HashMap<String,Object>())
+                    .put("instanceId",accountWithMinUsage).build());
         }
-        String url = (mode == 1 ? FAST_HOST : RELAX_HOST) + getActionUrl(action);
+        url = url + getActionUrl(action);
+        param.put("notifyHook",midjourneyHost +(EnvCommonService.active.equals(envCommonService.getEnv()) ? "/8081":"/8082") + "/api/applets/midjourney/notifyHook");
         String body = HttpRequest.post(url).body(Jsons.toJson(param)).header("Authorization", FAST_TOKEN).execute().body();
         log.info("action body:{}", body);
         SubmitResult submitResult = Jsons.parseObject(body, SubmitResult.class);
@@ -207,6 +259,42 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         }
         return submitResult;
     }
+
+    public String getAccountWithMinUsage(Long instanceId) {
+        String key = RedisService.key.MIDJOURNEY_ACCOUNT.getName();
+        try {
+            // 获取所有账号ID和使用次数
+            Map<Object, Object> accountsUsage = redisService.hmget(key);
+
+            if (accountsUsage == null || accountsUsage.isEmpty()) {
+                Map<Object, Object> map = midjourneyAccountService.list(Wrappers.lambdaQuery(MidjourneyAccount.class)).stream().collect(Collectors.toMap(k -> k.getInstanceId().toString(), v -> 0));
+                // 保存所有账号ID和使用次数
+                redisService.hmset(key, map);
+            }
+
+            // 找到使用次数最少的账号ID
+            String minAccountId = null;
+            if (instanceId != null) {
+                minAccountId = instanceId.toString();
+            }else {
+                int minUsage = Integer.MAX_VALUE;
+                for (Map.Entry<Object, Object> entry : accountsUsage.entrySet()) {
+                    int usage = Integer.parseInt(entry.getValue().toString());
+                    if (usage < minUsage) {
+                        minUsage = usage;
+                        minAccountId = entry.getKey().toString();
+                    }
+                }
+            }
+            // 增加使用次数
+            if (minAccountId != null) {
+                redisService.hincr(key, minAccountId, 1.0);
+            }
+            return minAccountId;
+        } catch (Exception e) {
+            throw BusinessRuntimeException.getInstance("获取账号失败");
+        }
+    }
     private String getActionUrl(String action) {
          switch (action) {
             case "imagine":
@@ -225,21 +313,33 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         }
     }
     @Override
-    public List<MidjourneyUserConversation> listConversationByIds(Integer mode, List<Long> ids) throws Exception {
+    public List<MidjourneyUserConversation> listConversationByIds(Integer mode, List<Long> ids) {
         List<MidjourneyUserConversation> list = new ArrayList<>();
-        listByIds(mode,ids).forEach(json -> {
-            JSONObject jsons = JSONUtil.parseObj(json);
-            MidjourneyUserConversation conversation = JSONUtil.toBean(jsons, MidjourneyUserConversation.class);
-            conversation.setUserId(jsons.getLong("state"));
-            conversation.setTaskId(jsons.getLong("id"));
-            list.add(conversation);
-            TASK_EXECUTOR.execute(() -> {
+        ids.forEach(id ->{
+            String queryKey = RedisService.key.MIDJOURNEY_QUERY.getName();
+            Long count = redisService.incr(queryKey + id, 1L);
+            if (count%5 == 0) {
                 try {
-                    sync(conversation);
-                } catch (IOException e) {
+                    listByIds(mode,List.of(id)).forEach(json ->{
+                        JSONObject jsons = JSONUtil.parseObj(json);
+                        MidjourneyUserConversation conversation = JSONUtil.toBean(jsons, MidjourneyUserConversation.class);
+                        conversation.setUserId(jsons.getLong("state"));
+                        conversation.setTaskId(jsons.getLong("id"));
+                        list.add(conversation);
+                        TASK_EXECUTOR.execute(() -> {
+                            try {
+                                sync(conversation);
+                            } catch (IOException e) {
+                                throw new RuntimeException(e);
+                            }
+                        });
+                    });
+                } catch (Exception e) {
                     throw new RuntimeException(e);
                 }
-            });
+            }else {
+                list.add((MidjourneyUserConversation) redisService.get(RedisService.key.MIDJOURNEY_CONVERSATION.getName() + id));
+            }
         });
         return list;
     }
@@ -248,18 +348,42 @@ public class MidjourneyServiceImpl implements MidjourneyService {
     public void sync(MidjourneyUserConversation conversation) throws IOException {
         if ((StringUtils.isNotBlank(conversation.getProgress()) && progress.contains(conversation.getProgress())) || status.contains(conversation.getStatus())) {
             log.info("同步任务:{},进度:{}",conversation.getTaskId(),conversation.getProgress());
+            Long userId = conversation.getUserId();
             MidjourneyUserConversation dbConversation = conversationMapper.selectOne(Wrappers.lambdaQuery(MidjourneyUserConversation.class).eq(MidjourneyUserConversation::getTaskId, conversation.getTaskId())
-                    .eq(MidjourneyUserConversation::getUserId, conversation.getUserId()).last("limit 1"));
+                    .eq(MidjourneyUserConversation::getUserId, userId).orderByDesc(MidjourneyUserConversation::getId).last("limit 1"));
             if (dbConversation != null) {
                 try {
-                    if (StringUtils.isNotBlank(conversation.getImageUrl())) {
-                        conversation.setImageUrl(uploadPic(conversation.getImageUrl(), "conversation"+dbConversation.getId()));
+                    String imageUrl = conversation.getImageUrl();
+                    if (StringUtil.isNotBlank(imageUrl)) {
+                        conversation.setImageUrl(uploadPic(imageUrl, "conversation"+dbConversation.getId()));
                     }
                 } catch (IOException e) {
                     log.error("上传图片失败",e);
                 }finally {
                     conversation.setId(dbConversation.getId());
                     conversationMapper.updateById(conversation);
+                    if (dbConversation.getMode() == 2){
+                        redisService.hdecr(RedisService.key.MIDJOURNEY_ACCOUNT.getName() , dbConversation.getInstanceId().toString(), 1.0);
+                    }
+                }
+                //失败返还次数
+
+                if ("FAILURE".equals(conversation.getStatus())){
+                    Object num = redisService.get(RedisService.key.MIDJOURNEY_RELAX_LIMIT.getName() + userId);
+                    LambdaUpdateWrapper<MidjourneyUser> wrapper = Wrappers.lambdaUpdate(MidjourneyUser.class)
+                            .eq(MidjourneyUser::getId, userId);
+                    Integer mode = dbConversation.getMode();
+                    if (mode == 1){
+                        num =  redisService.incr(RedisService.key.MIDJOURNEY_FAST_LIMIT.getName() + userId, 1L);
+                        wrapper.set(MidjourneyUser::getMjFastNum, num);
+                    }
+                    if (mode == 2){
+                        if (num != null) {
+                            num = redisService.incr(RedisService.key.MIDJOURNEY_RELAX_LIMIT.getName() + userId, 1L);
+                        }
+                        wrapper.set(MidjourneyUser::getMjRelaxNum, num);
+                    }
+                    midjourneyUserMapper.update(null, wrapper);
                 }
             }
         }
@@ -274,8 +398,9 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         }
         Map<String, Object> paramMap = new HashMap<>();
         paramMap.put("file", tempFile.toFile());
-        JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
-        return result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
+        String json = HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap);
+        log.info("上传图片结果:url:{},json:{}",url, json);
+        return new JSONObject(json).getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl");
     }
 
     private static List<String> uploadBase64Pic(List<String> base64Array) throws IOException {
@@ -293,8 +418,8 @@ public class MidjourneyServiceImpl implements MidjourneyService {
             }
             Map<String, Object> paramMap = new HashMap<>();
             paramMap.put("file", tempFile.toFile());
-            JSONObject result = JSONUtil.parseObj(HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap));
-            list.add(result.getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl"));
+            String json = HttpUtil.post("https://files.liuliangbang.vip/pic/ups", paramMap);
+            list.add(new JSONObject(json).getJSONObject("value").getJSONArray("saved").getJSONObject(0).getJSONObject("info").getStr("cdnUrl"));
         }
         return list;
     }
@@ -331,4 +456,23 @@ public class MidjourneyServiceImpl implements MidjourneyService {
         }
     }
 
+    @Override
+    public void notifyHook(String json) {
+        log.info("notifyHook:{}", json);
+        JSONObject jsons = JSONUtil.parseObj(json);
+        MidjourneyUserConversation conversation = JSONUtil.toBean(jsons, MidjourneyUserConversation.class);
+        conversation.setUserId(jsons.getLong("state"));
+        conversation.setTaskId(jsons.getLong("id"));
+        if (StringUtil.isNotBlank(conversation.getImageUrl())) {
+            conversation.setImageUrl(conversation.getImageUrl().replace("cdn.discordapp.com", "mj.galaxydvd.com"));
+        }
+        redisService.set(RedisService.key.MIDJOURNEY_CONVERSATION.getName() + conversation.getTaskId(), conversation,RedisService.key.MIDJOURNEY_CONVERSATION.getTimeout());
+        TASK_EXECUTOR.execute(() -> {
+            try {
+                sync(conversation);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        });
+    }
 }

+ 27 - 4
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MidjourneyController.java

@@ -2,13 +2,16 @@ package com.cyksj.web.controller.mirror;
 
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.IoKit;
 import com.cyksj.dto.Result;
 import com.cyksj.model.dto.*;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.MidjourneyUserMapper;
 import com.cyksj.model.entity.MidjourneyUser;
 import com.cyksj.model.entity.MidjourneyUserConversation;
+import com.cyksj.model.response.SubmitResult;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.midjourney.MidjourneyService;
 import com.ejlchina.searcher.BeanSearcher;
@@ -20,8 +23,11 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author zwhui
@@ -160,6 +166,7 @@ public class MidjourneyController {
      * 提交Imagine任务
      */
     @PostMapping("/submit/imagine")
+    @NoSubmit
     public Result<MidjourneyUserConversation> submitImagine(@RequestBody SubmitImagineDTO submitImagineDTO) {
         log.info("提交Imagine任务,提示:{},base64数组长度:{}",submitImagineDTO.getPrompt(),submitImagineDTO.getBase64Array());
         MidjourneyUser user = getUser();
@@ -182,6 +189,7 @@ public class MidjourneyController {
      * 提交Describe任务
      */
     @PostMapping("/submit/describe")
+    @NoSubmit
     public Result<MidjourneyUserConversation> submitDescribe(@RequestBody SubmitDescribeDTO submitDescribeDTO) {
         log.info("提交Describe任务");
         MidjourneyUser user = getUser();
@@ -204,6 +212,7 @@ public class MidjourneyController {
      * 提交Blend任务
      */
     @PostMapping("/submit/blend")
+    @NoSubmit
     public Result<MidjourneyUserConversation> submitBlend(@RequestBody SubmitBlendDTO submitBlendDTO) {
         log.info("提交Blend任务 dimensions:{},base64数组长度:{}", submitBlendDTO.getDimensions(), submitBlendDTO.getBase64Array().size());
         MidjourneyUser user = getUser();
@@ -226,6 +235,7 @@ public class MidjourneyController {
      * 提交Modal任务
      */
     @PostMapping("/submit/modal")
+    @NoSubmit
     public Result<MidjourneyUserConversation> submitModal(@RequestBody SubmitModalDTO submitModalDTO) {
         log.info("提交Modal任务,taskId:{},提示:{},base64数组长度:{}",submitModalDTO.getTaskId(),submitModalDTO.getPrompt(),submitModalDTO.getMaskBase64());
         MidjourneyUser user = getUser();
@@ -248,6 +258,7 @@ public class MidjourneyController {
      * 提交Shorten任务
      */
     @PostMapping("/submit/shorten")
+    @NoSubmit
     public Result<MidjourneyUserConversation> submitShorten(@RequestBody SubmitShortenDTO submitShortenDTO) {
         log.info("提交Shorten任务 提示词:{}",submitShortenDTO.getPrompt());
         MidjourneyUser user = getUser();
@@ -270,21 +281,21 @@ public class MidjourneyController {
      * 执行动作
      */
     @PostMapping("/submit/action")
-    public Result<MidjourneyUserConversation> action(@RequestBody SubmitActionDTO actionDTO) {
+    @NoSubmit
+    public Result<SubmitResult> action(@RequestBody SubmitActionDTO actionDTO) {
         log.info("任务id:{},执行动作:{}",actionDTO.getTaskId(),actionDTO.getCustomId());
         MidjourneyUser user = getUser();
         Long num = checkUserLimit(user);
         if (num != null && num < 0){
             throw BusinessRuntimeException.getInstance("次数已用完");
         }
-        MidjourneyUserConversation conversation;
+        SubmitResult conversation;
         try {
-            conversation = midjourneyService.submitAction(user, actionDTO.getTaskId(), actionDTO.getCustomId());
+            conversation = midjourneyService.submitAction(user, actionDTO.getTaskId(), actionDTO.getCustomId(),num);
         } catch (Exception e) {
             recoverUserLimit(user.getId(), user.getMode(),num);
             throw BusinessRuntimeException.getInstance(e.getMessage());
         }
-        syncUser(user.getId(), user.getMode(), num);
         return GatewayResponse.SUCCESS.newBuilder().toResult(conversation);
     }
 
@@ -316,6 +327,7 @@ public class MidjourneyController {
      * 取消任务
      */
     @PostMapping("/conversation/{id}/cancel")
+    @NoSubmit
     public Result<MidjourneyUserConversation> conversationCancel(@PathVariable("id") Long id){
         MidjourneyUser user = getUser();
         log.info("取消任务 id:{}",id);
@@ -338,4 +350,15 @@ public class MidjourneyController {
         redisService.del(RedisService.key.MIDJOURNEY_USER.getName() + midjourneyUser.getUserToken());
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
+
+    /**
+     * midjourney 回调
+     */
+    @PostMapping("/notifyHook")
+    public void notifyHook(HttpServletRequest request) throws Exception {
+        InputStream inputStream = request.getInputStream();
+        byte[] bytes = IoKit.toBytes(inputStream);
+        String json = new String(bytes, StandardCharsets.UTF_8);
+        midjourneyService.notifyHook(json);
+    }
 }