Commit 330fd52b3e2ffc2f6045b736b05ddd2f5762864a

Authored by cherishsince
1 parent 24479dac

【添加】midjourney 增加 imagine 接口

yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/AiImageController.java
1 package cn.iocoder.yudao.module.ai.controller; 1 package cn.iocoder.yudao.module.ai.controller;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
3 import cn.iocoder.yudao.module.ai.service.AiImageService; 4 import cn.iocoder.yudao.module.ai.service.AiImageService;
4 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq; 5 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq;
  6 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyReq;
  7 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyRes;
5 import io.swagger.v3.oas.annotations.Operation; 8 import io.swagger.v3.oas.annotations.Operation;
6 import io.swagger.v3.oas.annotations.tags.Tag; 9 import io.swagger.v3.oas.annotations.tags.Tag;
7 import lombok.AllArgsConstructor; 10 import lombok.AllArgsConstructor;
8 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
9 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
10 -import org.springframework.web.bind.annotation.GetMapping;  
11 -import org.springframework.web.bind.annotation.ModelAttribute; 13 +import org.springframework.web.bind.annotation.PostMapping;
  14 +import org.springframework.web.bind.annotation.RequestBody;
12 import org.springframework.web.bind.annotation.RequestMapping; 15 import org.springframework.web.bind.annotation.RequestMapping;
13 import org.springframework.web.bind.annotation.RestController; 16 import org.springframework.web.bind.annotation.RestController;
14 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 17 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@@ -30,10 +33,16 @@ public class AiImageController { @@ -30,10 +33,16 @@ public class AiImageController {
30 private final AiImageService aiImageService; 33 private final AiImageService aiImageService;
31 34
32 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!") 35 @Operation(summary = "dall2/dall3绘画", description = "openAi dall3是付费的!")
33 - @GetMapping("/dallDrawing")  
34 - public SseEmitter dallDrawing(@Validated @ModelAttribute AiImageDallDrawingReq req) { 36 + @PostMapping("/dallDrawing")
  37 + public SseEmitter dallDrawing(@Validated @RequestBody AiImageDallDrawingReq req) {
35 Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); 38 Utf8SseEmitter sseEmitter = new Utf8SseEmitter();
36 aiImageService.dallDrawing(req, sseEmitter); 39 aiImageService.dallDrawing(req, sseEmitter);
37 return sseEmitter; 40 return sseEmitter;
38 } 41 }
  42 +
  43 + @Operation(summary = "midjourney", description = "midjourney图片绘画流程:1、提交任务 2、获取完成的任务 3、选择对应功能 4、获取最终结果")
  44 + @PostMapping("/midjourney")
  45 + public CommonResult<AiImageMidjourneyRes> midjourney(@Validated @RequestBody AiImageMidjourneyReq req) {
  46 + return CommonResult.success(aiImageService.midjourney(req));
  47 + }
39 } 48 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiImageService.java
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.ai.service; @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.ai.service;
2 2
3 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; 3 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter;
4 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq; 4 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq;
  5 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyReq;
  6 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyRes;
5 7
6 /** 8 /**
7 * ai 作图 9 * ai 作图
@@ -19,4 +21,12 @@ public interface AiImageService { @@ -19,4 +21,12 @@ public interface AiImageService {
19 * @param sseEmitter 21 * @param sseEmitter
20 */ 22 */
21 void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter); 23 void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter);
  24 +
  25 + /**
  26 + * midjourney 图片生成
  27 + *
  28 + * @param req
  29 + * @return
  30 + */
  31 + AiImageMidjourneyRes midjourney(AiImageMidjourneyReq req);
22 } 32 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiImageServiceImpl.java
@@ -8,17 +8,26 @@ import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageClient; @@ -8,17 +8,26 @@ import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageClient;
8 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum; 8 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum;
9 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions; 9 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions;
10 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum; 10 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageStyleEnum;
  11 +import cn.iocoder.yudao.framework.ai.midjourney.api.MidjourneyInteractionsApi;
  12 +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.MidjourneyWebSocketStarter;
  13 +import cn.iocoder.yudao.framework.ai.midjourney.webSocket.WssNotify;
  14 +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
11 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; 15 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  16 +import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
12 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; 17 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter;
13 import cn.iocoder.yudao.module.ai.dal.dataobject.AiImageDO; 18 import cn.iocoder.yudao.module.ai.dal.dataobject.AiImageDO;
14 import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum; 19 import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum;
15 import cn.iocoder.yudao.module.ai.mapper.AiImageMapper; 20 import cn.iocoder.yudao.module.ai.mapper.AiImageMapper;
16 import cn.iocoder.yudao.module.ai.service.AiImageService; 21 import cn.iocoder.yudao.module.ai.service.AiImageService;
17 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq; 22 import cn.iocoder.yudao.module.ai.vo.AiImageDallDrawingReq;
  23 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyReq;
  24 +import cn.iocoder.yudao.module.ai.vo.AiImageMidjourneyRes;
  25 +import jakarta.annotation.PostConstruct;
18 import lombok.AllArgsConstructor; 26 import lombok.AllArgsConstructor;
19 import lombok.extern.slf4j.Slf4j; 27 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.http.MediaType; 28 import org.springframework.http.MediaType;
21 import org.springframework.stereotype.Service; 29 import org.springframework.stereotype.Service;
  30 +import org.springframework.transaction.annotation.Transactional;
22 31
23 import java.io.IOException; 32 import java.io.IOException;
24 33
@@ -36,6 +45,24 @@ public class AiImageServiceImpl implements AiImageService { @@ -36,6 +45,24 @@ public class AiImageServiceImpl implements AiImageService {
36 45
37 private final AiImageMapper aiImageMapper; 46 private final AiImageMapper aiImageMapper;
38 private final OpenAiImageClient openAiImageClient; 47 private final OpenAiImageClient openAiImageClient;
  48 + private final MidjourneyWebSocketStarter midjourneyWebSocketStarter;
  49 + private final MidjourneyInteractionsApi midjourneyInteractionsApi;
  50 +
  51 + @PostConstruct
  52 + public void startMidjourney() {
  53 + log.info("midjourney web socket starter...");
  54 + midjourneyWebSocketStarter.start(new WssNotify() {
  55 + @Override
  56 + public void notify(int code, String message) {
  57 + log.info("code: {}, message: {}", code, message);
  58 + if (message.contains("Authentication failed")) {
  59 + // TODO 芋艿,这里看怎么处理,token无效的时候会认证失败!
  60 + // 认证失败
  61 + log.error("midjourney socket 认证失败,检查token是否失效!");
  62 + }
  63 + }
  64 + });
  65 + }
39 66
40 @Override 67 @Override
41 public void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter) { 68 public void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter) {
@@ -55,15 +82,33 @@ public class AiImageServiceImpl implements AiImageService { @@ -55,15 +82,33 @@ public class AiImageServiceImpl implements AiImageService {
55 // 发送信息 82 // 发送信息
56 sendSseEmitter(sseEmitter, imageGeneration); 83 sendSseEmitter(sseEmitter, imageGeneration);
57 // 保存数据库 84 // 保存数据库
58 - doSave(req, imageGeneration.getOutput().getUrl(), AiChatDrawingStatusEnum.COMPLETE, null); 85 + doSave(req.getPrompt(), req.getSize(), req.getModal(),
  86 + imageGeneration.getOutput().getUrl(), AiChatDrawingStatusEnum.COMPLETE, null);
59 } catch (AiException aiException) { 87 } catch (AiException aiException) {
60 // 保存数据库 88 // 保存数据库
61 - doSave(req, null, AiChatDrawingStatusEnum.FAIL, aiException.getMessage()); 89 + doSave(req.getPrompt(), req.getSize(), req.getModal(),
  90 + null, AiChatDrawingStatusEnum.FAIL, aiException.getMessage());
62 // 发送错误信息 91 // 发送错误信息
63 sendSseEmitter(sseEmitter, aiException.getMessage()); 92 sendSseEmitter(sseEmitter, aiException.getMessage());
64 } 93 }
65 } 94 }
66 95
  96 + @Override
  97 + @Transactional(rollbackFor = Exception.class)
  98 + public AiImageMidjourneyRes midjourney(AiImageMidjourneyReq req) {
  99 + // 保存数据库
  100 + doSave(req.getPrompt(), null, "midjoureny",
  101 + null, AiChatDrawingStatusEnum.SUBMIT, null);
  102 + // 提交 midjourney 任务
  103 + Boolean imagine = midjourneyInteractionsApi.imagine(req.getPrompt());
  104 + if (!imagine) {
  105 + throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_MIDJOURNEY_IMAGINE_FAIL);
  106 + }
  107 + //
  108 +
  109 + return null;
  110 + }
  111 +
67 private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) { 112 private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) {
68 try { 113 try {
69 sseEmitter.send(object, MediaType.APPLICATION_JSON); 114 sseEmitter.send(object, MediaType.APPLICATION_JSON);
@@ -75,14 +120,19 @@ public class AiImageServiceImpl implements AiImageService { @@ -75,14 +120,19 @@ public class AiImageServiceImpl implements AiImageService {
75 } 120 }
76 } 121 }
77 122
78 - private void doSave(AiImageDallDrawingReq req, String imageUrl, AiChatDrawingStatusEnum drawingStatusEnum, String drawingError) { 123 + private void doSave(String prompt,
  124 + String size,
  125 + String model,
  126 + String imageUrl,
  127 + AiChatDrawingStatusEnum drawingStatusEnum,
  128 + String drawingError) {
79 // 保存数据库 129 // 保存数据库
80 Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); 130 Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
81 AiImageDO aiImageDO = new AiImageDO(); 131 AiImageDO aiImageDO = new AiImageDO();
82 aiImageDO.setId(null); 132 aiImageDO.setId(null);
83 - aiImageDO.setPrompt(req.getPrompt());  
84 - aiImageDO.setSize(req.getSize());  
85 - aiImageDO.setModal(req.getModal()); 133 + aiImageDO.setPrompt(prompt);
  134 + aiImageDO.setSize(size);
  135 + aiImageDO.setModal(model);
86 aiImageDO.setUserId(loginUserId); 136 aiImageDO.setUserId(loginUserId);
87 aiImageDO.setDrawingImageUrl(imageUrl); 137 aiImageDO.setDrawingImageUrl(imageUrl);
88 aiImageDO.setDrawingStatus(drawingStatusEnum.getStatus()); 138 aiImageDO.setDrawingStatus(drawingStatusEnum.getStatus());