| 
					
				 | 
			
			
				@@ -1,7 +1,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package cn.iocoder.yudao.module.ai.service.image; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import cn.hutool.core.util.IdUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.hutool.http.HttpUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageModelEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.framework.ai.core.enums.OpenAiImageStyleEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.framework.ai.core.exception.AiException; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -11,6 +11,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.AiCommonConstants; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.ErrorCodeConstants; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.iocoder.yudao.module.ai.client.MidjourneyProxyClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.iocoder.yudao.module.ai.client.vo.MidjourneyImagineReqVO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.iocoder.yudao.module.ai.client.vo.MidjourneySubmitCodeEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.iocoder.yudao.module.ai.client.vo.MidjourneySubmitRespVO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -18,21 +22,22 @@ import cn.iocoder.yudao.module.ai.enums.AiImagePublicStatusEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.ai.enums.AiImageStatusEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import cn.iocoder.yudao.module.infra.api.file.FileApi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.google.common.collect.ImmutableMap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import jakarta.annotation.PostConstruct; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import jakarta.annotation.Resource; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import lombok.extern.slf4j.Slf4j; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.ai.image.ImageGeneration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.ai.image.ImagePrompt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.ai.image.ImageResponse; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import org.springframework.ai.models.midjourney.api.MidjourneyInteractionsApi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import org.springframework.ai.models.midjourney.webSocket.MidjourneyWebSocketStarter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.ai.openai.OpenAiImageClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.ai.openai.OpenAiImageOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.beans.factory.annotation.Autowired; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.beans.factory.annotation.Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.scheduling.annotation.Async; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.stereotype.Service; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.transaction.annotation.Transactional; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.HashMap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Map; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -59,28 +64,11 @@ public class AiImageServiceImpl implements AiImageService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private FileApi fileApi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private OpenAiImageClient openAiImageClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private MidjourneyWebSocketStarter midjourneyWebSocketStarter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private MidjourneyInteractionsApi midjourneyInteractionsApi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // TODO @fan:接 mj proxy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    @PostConstruct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public void startMidjourney() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // todo @fan 暂时注释掉 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//        log.info("midjourney web socket starter..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//        midjourneyWebSocketStarter.start(new WssNotify() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//            @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//            public void notify(int code, String message) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                log.info("code: {}, message: {}", code, message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                if (message.contains("Authentication failed")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                    // TODO 芋艿,这里看怎么处理,token无效的时候会认证失败! 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                    // 认证失败 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                    log.error("midjourney socket 认证失败,检查token是否失效!"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private MidjourneyProxyClient midjourneyProxyClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Value("${ai.midjourney-proxy.notifyUrl:http://127.0.0.1:48080/admin-api/ai/image/midjourney-notify}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private String midjourneyNotifyUrl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public PageResult<AiImageDO> getImagePageMy(Long loginUserId, AiImageListReqVO req) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -143,18 +131,53 @@ public class AiImageServiceImpl implements AiImageService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Transactional(rollbackFor = Exception.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public void midjourney(AiImageMidjourneyReqVO req) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 保存数据库 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        String messageId = String.valueOf(IdUtil.getSnowflakeNextId()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // todo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//        AiImageDO aiImageDO = doSave(req.getPrompt(), null, "midjoureny", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                null, null, AiImageStatusEnum.SUBMIT, null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                messageId, null, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 提交 midjourney 任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        Boolean imagine = midjourneyInteractionsApi.imagine(messageId, req.getPrompt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (!imagine) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_IMAGINE_FAIL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public Long midjourneyImagine(Long loginUserId, AiImageMidjourneyImagineReqVO req) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 1、构建 AiImageDO 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        AiImageDO aiImageDO = new AiImageDO(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setId(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setUserId(loginUserId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setPrompt(req.getPrompt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setPlatform(AiPlatformEnum.MIDJOURNEY.getPlatform()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // todo @范 平台需要转换(mj 模型一般分版本) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setModel(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setWidth(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setHeight(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setStatus(AiImageStatusEnum.IN_PROGRESS.getStatus()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setPublicStatus(AiImagePublicStatusEnum.PRIVATE.getStatus()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setPicUrl(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setOriginalPicUrl(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setDrawRequest(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setDrawResponse(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        aiImageDO.setErrorMessage(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 2、保存 image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        imageMapper.insert(aiImageDO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 3、调用 MidjourneyProxy 提交任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        MidjourneyImagineReqVO imagineReqVO = BeanUtils.toBean(req, MidjourneyImagineReqVO.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        imagineReqVO.setNotifyHook(midjourneyNotifyUrl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        imagineReqVO.setState(String.valueOf(aiImageDO.getId())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        MidjourneySubmitRespVO submitRespVO = midjourneyProxyClient.imagine(imagineReqVO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 4、保存任务 id (状态码: 1(提交成功), 21(已存在), 22(排队中), other(错误)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String updateStatus = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String errorMessage = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<String, Object> drawResponse = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!MidjourneySubmitCodeEnum.SUCCESS_CODES.contains(submitRespVO.getCode())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            updateStatus = AiImageStatusEnum.FAIL.getStatus(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMessage = submitRespVO.getDescription(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            drawResponse.put("jobId", submitRespVO.getResult()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        imageMapper.updateById(new AiImageDO() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .setId(aiImageDO.getId()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .setStatus(updateStatus) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .setErrorMessage(errorMessage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .setDrawResponse(drawResponse) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return aiImageDO.getId(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Transactional(rollbackFor = Exception.class) 
			 |