Bladeren bron

【临时提交】增加 MidjourneyApi

cherishsince 1 jaar geleden
bovenliggende
commit
937992fd16
10 gewijzigde bestanden met toevoegingen van 412 en 0 verwijderingen
  1. 18 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/MidjourneyProperties.java
  2. 96 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/api/MidjourneyApi.java
  3. 30 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyModelEnum.java
  4. 33 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneySubmitCodeEnum.java
  5. 35 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskActionEnum.java
  6. 38 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskStatusEnum.java
  7. 27 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyActionRequest.java
  8. 30 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyImagineRequest.java
  9. 75 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyNotifyRequest.java
  10. 30 0
      yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneySubmitResponse.java

+ 18 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/MidjourneyProperties.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney;
+
+import lombok.Data;
+
+/**
+ * Midjourney 属性
+ *
+ * @author fansili
+ * @time 2024/6/5 15:02
+ * @since 1.0
+ */
+@Data
+public class MidjourneyProperties {
+
+    private String key;
+    private String url;
+    private String notifyUrl;
+}

+ 96 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/api/MidjourneyApi.java

@@ -0,0 +1,96 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.api;
+
+import cn.iocoder.yudao.framework.ai.core.model.midjourney.MidjourneyProperties;
+import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyActionRequest;
+import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyImagineRequest;
+import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyNotifyRequest;
+import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneySubmitResponse;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import com.google.common.collect.ImmutableMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.openai.api.ApiUtils;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Midjourney api
+ *
+ * @author fansili
+ * @time 2024/6/11 15:46
+ * @since 1.0
+ */
+@Slf4j
+public class MidjourneyApi {
+
+    private static final String URI_IMAGINE = "/submit/imagine";
+    private static final String URI_ACTON = "/submit/action";
+    private static final String URI_LIST_BY_CONDITION = "/task/list-by-condition";
+    private final WebClient webClient;
+    private final MidjourneyProperties midjourneyProperties;
+
+    public MidjourneyApi(MidjourneyProperties midjourneyProperties) {
+        this.midjourneyProperties = midjourneyProperties;
+        this.webClient = WebClient.builder()
+                .baseUrl(midjourneyProperties.getUrl())
+                .defaultHeaders(ApiUtils.getJsonContentHeaders(midjourneyProperties.getKey()))
+                .build();
+    }
+
+
+    /**
+     * imagine - 根据提示词提交绘画任务
+     *
+     * @param imagineReqVO
+     * @return
+     */
+    public MidjourneySubmitResponse imagine(MidjourneyImagineRequest imagineReqVO) {
+        // 1、发送 post 请求
+        String res = post(URI_IMAGINE, imagineReqVO);
+        // 2、转换 resp
+        return JsonUtils.parseObject(res, MidjourneySubmitResponse.class);
+    }
+
+    /**
+     * action - 放大、缩小、U1、U2...
+     *
+     * @param actionReqVO
+     */
+    public MidjourneySubmitResponse action(MidjourneyActionRequest actionReqVO) {
+        // 1、发送 post 请求
+        String res = post(URI_ACTON, actionReqVO);
+        // 2、转换 resp
+        return JsonUtils.parseObject(res, MidjourneySubmitResponse.class);
+    }
+
+    /**
+     * 批量查询 task 任务
+     *
+     * @param taskIds
+     * @return
+     */
+    public List<MidjourneyNotifyRequest> listByCondition(Collection<String> taskIds) {
+        // 1、发送 post 请求
+        String res = post(URI_LIST_BY_CONDITION, ImmutableMap.of("ids", taskIds));
+        // 2、转换 对象
+        return JsonUtils.parseArray(res, MidjourneyNotifyRequest.class);
+    }
+
+    private String post(String uri, Object body) {
+        // 1、发送 post 请求
+        return webClient.post()
+                .uri(uri)
+                .body(Mono.just(JsonUtils.toJsonString(body)), String.class)
+                .retrieve()
+                .onStatus(status -> !status.is2xxSuccessful(),
+                        response -> response.bodyToMono(String.class)
+                                .handle((respBody, sink) -> {
+                                    log.error("【Midjourney api】调用失败!resp: 【{}】", respBody);
+                                    sink.error(new IllegalStateException("【Midjourney api】调用失败!"));
+                                }))
+                .bodyToMono(String.class)
+                .block();
+    }
+}

+ 30 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyModelEnum.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 来源于 midjourney-proxy
+ */
+@Getter
+@AllArgsConstructor
+public enum MidjourneyModelEnum {
+
+	MIDJOURNEY("midjourney", "midjourney"),
+	NIJI("Niji", "Niji"),
+
+	;
+
+	private String model;
+	private String name;
+
+	public static MidjourneyModelEnum valueOfModel(String model) {
+		for (MidjourneyModelEnum itemEnum : MidjourneyModelEnum.values()) {
+			if (itemEnum.getModel().equals(model)) {
+				return itemEnum;
+			}
+		}
+		throw new IllegalArgumentException("Invalid MessageType value: " + model);
+	}
+}

+ 33 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneySubmitCodeEnum.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums;
+
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+// TODO @fan:待定
+/**
+ * Midjourney 提交任务 code 枚举
+ *
+ * @author fansili
+ */
+@Getter
+@AllArgsConstructor
+public enum MidjourneySubmitCodeEnum {
+
+    SUBMIT_SUCCESS("1", "提交成功"),
+    ALREADY_EXISTS("21", "已存在"),
+    QUEUING("22", "排队中"),
+    ;
+
+    public static final List<String> SUCCESS_CODES = Lists.newArrayList(
+            SUBMIT_SUCCESS.code,
+            ALREADY_EXISTS.code,
+            QUEUING.code
+    );
+
+    private final String code;
+    private final String name;
+
+}

+ 35 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskActionEnum.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums;
+
+import lombok.Getter;
+
+/**
+ * 来源于 midjourney-proxy
+ */
+@Getter
+public enum MidjourneyTaskActionEnum {
+	/**
+	 * 生成图片.
+	 */
+	IMAGINE,
+	/**
+	 * 选中放大.
+	 */
+	UPSCALE,
+	/**
+	 * 选中其中的一张图,生成四张相似的.
+	 */
+	VARIATION,
+	/**
+	 * 重新执行.
+	 */
+	REROLL,
+	/**
+	 * 图转prompt.
+	 */
+	DESCRIBE,
+	/**
+	 * 多图混合.
+	 */
+	BLEND
+
+}

+ 38 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskStatusEnum.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums;
+
+
+import lombok.Getter;
+
+/**
+ * 来源于 midjourney-proxy
+ */
+public enum MidjourneyTaskStatusEnum {
+	/**
+	 * 未启动.
+	 */
+	NOT_START(0),
+	/**
+	 * 已提交.
+	 */
+	SUBMITTED(1),
+	/**
+	 * 执行中.
+	 */
+	IN_PROGRESS(3),
+	/**
+	 * 失败.
+	 */
+	FAILURE(4),
+	/**
+	 * 成功.
+	 */
+	SUCCESS(4);
+
+	@Getter
+	private final int order;
+
+	MidjourneyTaskStatusEnum(int order) {
+		this.order = order;
+	}
+
+}

+ 27 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyActionRequest.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * Midjourney:action 请求
+ *
+ * @author fansili
+ * @time 2024/5/30 14:02
+ * @since 1.0
+ */
+@Data
+public class MidjourneyActionRequest {
+
+    @Schema(description = "操作按钮id", required = true)
+    private String customId;
+
+    @Schema(description = "操作按钮id", required = true)
+    private String taskId;
+
+    @Schema(description = "通知地址", required = false)
+    private String notifyHook;
+
+    @Schema(description = "自定义参数", required = false)
+    private String state;
+}

+ 30 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyImagineRequest.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+// TODO @fan:待定
+/**
+ * Midjourney:Imagine 请求
+ *
+ * @author fansili
+ * @time 2024/5/30 14:02
+ * @since 1.0
+ */
+@Data
+public class MidjourneyImagineRequest {
+
+    @Schema(description = "垫图(参考图)base64数组", required = false)
+    private List<String> base64Array;
+
+    @Schema(description = "通知地址", required = false)
+    private String notifyHook;
+
+    @Schema(description = "提示词", required = true)
+    private String prompt;
+
+    @Schema(description = "自定义参数", required = false)
+    private String state;
+}

+ 75 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyNotifyRequest.java

@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Midjourney Proxy 通知回调
+ *
+ *  - Midjourney Proxy:通知回调 bean 是 com.github.novicezk.midjourney.support.Task
+ *  - 毫秒 api 通知回调文档地址:https://gpt-best.apifox.cn/doc-3530863
+ *
+ * @author fansili
+ * @time 2024/5/31 10:37
+ * @since 1.0
+ */
+@Data
+public class MidjourneyNotifyRequest {
+
+    @Schema(description = "job id")
+    private String id;
+
+    @Schema(description = "任务类型 MidjourneyTaskActionEnum")
+    private String action;
+    @Schema(description = "任务状态 MidjourneyTaskStatusEnum")
+    private String status;
+
+    @Schema(description = "提示词")
+    private String prompt;
+    @Schema(description = "提示词-英文")
+    private String promptEn;
+
+    @Schema(description = "任务描述")
+    private String description;
+    @Schema(description = "自定义参数")
+    private String state;
+
+    @Schema(description = "提交时间")
+    private Long submitTime;
+    @Schema(description = "开始执行时间")
+    private Long startTime;
+    @Schema(description = "结束时间")
+    private Long finishTime;
+
+    @Schema(description = "图片url")
+    private String imageUrl;
+
+    @Schema(description = "任务进度")
+    private String progress;
+    @Schema(description = "失败原因")
+    private String failReason;
+
+    @Schema(description = "任务完成后的可执行按钮")
+    private List<Button> buttons;
+
+    @Data
+    public static class Button {
+
+        @Schema(description = "MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识")
+        private String customId;
+
+        @Schema(description = "图标 emoji")
+        private String emoji;
+
+        @Schema(description = "Make Variations 文本")
+        private String label;
+
+        @Schema(description = "类型,系统内部使用")
+        private String type;
+
+        @Schema(description = "样式: 2(Primary)、3(Green)")
+        private String style;
+    }
+}

+ 30 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneySubmitResponse.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Map;
+
+// TODO @fan:待定
+/**
+ * Midjourney:Imagine 请求
+ *
+ * @author fansili
+ * @time 2024/5/30 14:02
+ * @since 1.0
+ */
+@Data
+public class MidjourneySubmitResponse {
+
+    @Schema(description = "状态码: 1(提交成功), 21(已存在), 22(排队中), other(错误)")
+    private String code;
+
+    @Schema(description = "描述")
+    private String description;
+
+    @Schema(description = "扩展字段")
+    private Map<String, Object> properties;
+
+    @Schema(description = "任务ID")
+    private String result;
+}