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 1 package cn.iocoder.yudao.module.ai.controller;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
3 4 import cn.iocoder.yudao.module.ai.service.AiImageService;
4 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 8 import io.swagger.v3.oas.annotations.Operation;
6 9 import io.swagger.v3.oas.annotations.tags.Tag;
7 10 import lombok.AllArgsConstructor;
8 11 import lombok.extern.slf4j.Slf4j;
9 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 15 import org.springframework.web.bind.annotation.RequestMapping;
13 16 import org.springframework.web.bind.annotation.RestController;
14 17 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
... ... @@ -30,10 +33,16 @@ public class AiImageController {
30 33 private final AiImageService aiImageService;
31 34  
32 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 38 Utf8SseEmitter sseEmitter = new Utf8SseEmitter();
36 39 aiImageService.dallDrawing(req, sseEmitter);
37 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 2  
3 3 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter;
4 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 9 * ai 作图
... ... @@ -19,4 +21,12 @@ public interface AiImageService {
19 21 * @param sseEmitter
20 22 */
21 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 8 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageModelEnum;
9 9 import cn.iocoder.yudao.framework.ai.imageopenai.OpenAiImageOptions;
10 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 15 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  16 +import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
12 17 import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter;
13 18 import cn.iocoder.yudao.module.ai.dal.dataobject.AiImageDO;
14 19 import cn.iocoder.yudao.module.ai.enums.AiChatDrawingStatusEnum;
15 20 import cn.iocoder.yudao.module.ai.mapper.AiImageMapper;
16 21 import cn.iocoder.yudao.module.ai.service.AiImageService;
17 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 26 import lombok.AllArgsConstructor;
19 27 import lombok.extern.slf4j.Slf4j;
20 28 import org.springframework.http.MediaType;
21 29 import org.springframework.stereotype.Service;
  30 +import org.springframework.transaction.annotation.Transactional;
22 31  
23 32 import java.io.IOException;
24 33  
... ... @@ -36,6 +45,24 @@ public class AiImageServiceImpl implements AiImageService {
36 45  
37 46 private final AiImageMapper aiImageMapper;
38 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 67 @Override
41 68 public void dallDrawing(AiImageDallDrawingReq req, Utf8SseEmitter sseEmitter) {
... ... @@ -55,15 +82,33 @@ public class AiImageServiceImpl implements AiImageService {
55 82 // 发送信息
56 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 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 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 112 private static void sendSseEmitter(Utf8SseEmitter sseEmitter, Object object) {
68 113 try {
69 114 sseEmitter.send(object, MediaType.APPLICATION_JSON);
... ... @@ -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 130 Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
81 131 AiImageDO aiImageDO = new AiImageDO();
82 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 136 aiImageDO.setUserId(loginUserId);
87 137 aiImageDO.setDrawingImageUrl(imageUrl);
88 138 aiImageDO.setDrawingStatus(drawingStatusEnum.getStatus());
... ...