Commit 937992fd163d76a66ae04a7e14646b27b513023c
1 parent
1ac1c007
【临时提交】增加 MidjourneyApi
Showing
10 changed files
with
412 additions
and
0 deletions
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/MidjourneyProperties.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * Midjourney 属性 | ||
| 7 | + * | ||
| 8 | + * @author fansili | ||
| 9 | + * @time 2024/6/5 15:02 | ||
| 10 | + * @since 1.0 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +public class MidjourneyProperties { | ||
| 14 | + | ||
| 15 | + private String key; | ||
| 16 | + private String url; | ||
| 17 | + private String notifyUrl; | ||
| 18 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/api/MidjourneyApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.api; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.MidjourneyProperties; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyActionRequest; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyImagineRequest; | ||
| 6 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneyNotifyRequest; | ||
| 7 | +import cn.iocoder.yudao.framework.ai.core.model.midjourney.vo.MidjourneySubmitResponse; | ||
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 9 | +import com.google.common.collect.ImmutableMap; | ||
| 10 | +import lombok.extern.slf4j.Slf4j; | ||
| 11 | +import org.springframework.ai.openai.api.ApiUtils; | ||
| 12 | +import org.springframework.web.reactive.function.client.WebClient; | ||
| 13 | +import reactor.core.publisher.Mono; | ||
| 14 | + | ||
| 15 | +import java.util.Collection; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Midjourney api | ||
| 20 | + * | ||
| 21 | + * @author fansili | ||
| 22 | + * @time 2024/6/11 15:46 | ||
| 23 | + * @since 1.0 | ||
| 24 | + */ | ||
| 25 | +@Slf4j | ||
| 26 | +public class MidjourneyApi { | ||
| 27 | + | ||
| 28 | + private static final String URI_IMAGINE = "/submit/imagine"; | ||
| 29 | + private static final String URI_ACTON = "/submit/action"; | ||
| 30 | + private static final String URI_LIST_BY_CONDITION = "/task/list-by-condition"; | ||
| 31 | + private final WebClient webClient; | ||
| 32 | + private final MidjourneyProperties midjourneyProperties; | ||
| 33 | + | ||
| 34 | + public MidjourneyApi(MidjourneyProperties midjourneyProperties) { | ||
| 35 | + this.midjourneyProperties = midjourneyProperties; | ||
| 36 | + this.webClient = WebClient.builder() | ||
| 37 | + .baseUrl(midjourneyProperties.getUrl()) | ||
| 38 | + .defaultHeaders(ApiUtils.getJsonContentHeaders(midjourneyProperties.getKey())) | ||
| 39 | + .build(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * imagine - 根据提示词提交绘画任务 | ||
| 45 | + * | ||
| 46 | + * @param imagineReqVO | ||
| 47 | + * @return | ||
| 48 | + */ | ||
| 49 | + public MidjourneySubmitResponse imagine(MidjourneyImagineRequest imagineReqVO) { | ||
| 50 | + // 1、发送 post 请求 | ||
| 51 | + String res = post(URI_IMAGINE, imagineReqVO); | ||
| 52 | + // 2、转换 resp | ||
| 53 | + return JsonUtils.parseObject(res, MidjourneySubmitResponse.class); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * action - 放大、缩小、U1、U2... | ||
| 58 | + * | ||
| 59 | + * @param actionReqVO | ||
| 60 | + */ | ||
| 61 | + public MidjourneySubmitResponse action(MidjourneyActionRequest actionReqVO) { | ||
| 62 | + // 1、发送 post 请求 | ||
| 63 | + String res = post(URI_ACTON, actionReqVO); | ||
| 64 | + // 2、转换 resp | ||
| 65 | + return JsonUtils.parseObject(res, MidjourneySubmitResponse.class); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 批量查询 task 任务 | ||
| 70 | + * | ||
| 71 | + * @param taskIds | ||
| 72 | + * @return | ||
| 73 | + */ | ||
| 74 | + public List<MidjourneyNotifyRequest> listByCondition(Collection<String> taskIds) { | ||
| 75 | + // 1、发送 post 请求 | ||
| 76 | + String res = post(URI_LIST_BY_CONDITION, ImmutableMap.of("ids", taskIds)); | ||
| 77 | + // 2、转换 对象 | ||
| 78 | + return JsonUtils.parseArray(res, MidjourneyNotifyRequest.class); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + private String post(String uri, Object body) { | ||
| 82 | + // 1、发送 post 请求 | ||
| 83 | + return webClient.post() | ||
| 84 | + .uri(uri) | ||
| 85 | + .body(Mono.just(JsonUtils.toJsonString(body)), String.class) | ||
| 86 | + .retrieve() | ||
| 87 | + .onStatus(status -> !status.is2xxSuccessful(), | ||
| 88 | + response -> response.bodyToMono(String.class) | ||
| 89 | + .handle((respBody, sink) -> { | ||
| 90 | + log.error("【Midjourney api】调用失败!resp: 【{}】", respBody); | ||
| 91 | + sink.error(new IllegalStateException("【Midjourney api】调用失败!")); | ||
| 92 | + })) | ||
| 93 | + .bodyToMono(String.class) | ||
| 94 | + .block(); | ||
| 95 | + } | ||
| 96 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyModelEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Getter; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 来源于 midjourney-proxy | ||
| 9 | + */ | ||
| 10 | +@Getter | ||
| 11 | +@AllArgsConstructor | ||
| 12 | +public enum MidjourneyModelEnum { | ||
| 13 | + | ||
| 14 | + MIDJOURNEY("midjourney", "midjourney"), | ||
| 15 | + NIJI("Niji", "Niji"), | ||
| 16 | + | ||
| 17 | + ; | ||
| 18 | + | ||
| 19 | + private String model; | ||
| 20 | + private String name; | ||
| 21 | + | ||
| 22 | + public static MidjourneyModelEnum valueOfModel(String model) { | ||
| 23 | + for (MidjourneyModelEnum itemEnum : MidjourneyModelEnum.values()) { | ||
| 24 | + if (itemEnum.getModel().equals(model)) { | ||
| 25 | + return itemEnum; | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + throw new IllegalArgumentException("Invalid MessageType value: " + model); | ||
| 29 | + } | ||
| 30 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneySubmitCodeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums; | ||
| 2 | + | ||
| 3 | +import com.google.common.collect.Lists; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Getter; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +// TODO @fan:待定 | ||
| 10 | +/** | ||
| 11 | + * Midjourney 提交任务 code 枚举 | ||
| 12 | + * | ||
| 13 | + * @author fansili | ||
| 14 | + */ | ||
| 15 | +@Getter | ||
| 16 | +@AllArgsConstructor | ||
| 17 | +public enum MidjourneySubmitCodeEnum { | ||
| 18 | + | ||
| 19 | + SUBMIT_SUCCESS("1", "提交成功"), | ||
| 20 | + ALREADY_EXISTS("21", "已存在"), | ||
| 21 | + QUEUING("22", "排队中"), | ||
| 22 | + ; | ||
| 23 | + | ||
| 24 | + public static final List<String> SUCCESS_CODES = Lists.newArrayList( | ||
| 25 | + SUBMIT_SUCCESS.code, | ||
| 26 | + ALREADY_EXISTS.code, | ||
| 27 | + QUEUING.code | ||
| 28 | + ); | ||
| 29 | + | ||
| 30 | + private final String code; | ||
| 31 | + private final String name; | ||
| 32 | + | ||
| 33 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskActionEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums; | ||
| 2 | + | ||
| 3 | +import lombok.Getter; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 来源于 midjourney-proxy | ||
| 7 | + */ | ||
| 8 | +@Getter | ||
| 9 | +public enum MidjourneyTaskActionEnum { | ||
| 10 | + /** | ||
| 11 | + * 生成图片. | ||
| 12 | + */ | ||
| 13 | + IMAGINE, | ||
| 14 | + /** | ||
| 15 | + * 选中放大. | ||
| 16 | + */ | ||
| 17 | + UPSCALE, | ||
| 18 | + /** | ||
| 19 | + * 选中其中的一张图,生成四张相似的. | ||
| 20 | + */ | ||
| 21 | + VARIATION, | ||
| 22 | + /** | ||
| 23 | + * 重新执行. | ||
| 24 | + */ | ||
| 25 | + REROLL, | ||
| 26 | + /** | ||
| 27 | + * 图转prompt. | ||
| 28 | + */ | ||
| 29 | + DESCRIBE, | ||
| 30 | + /** | ||
| 31 | + * 多图混合. | ||
| 32 | + */ | ||
| 33 | + BLEND | ||
| 34 | + | ||
| 35 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/enums/MidjourneyTaskStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.enums; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 来源于 midjourney-proxy | ||
| 8 | + */ | ||
| 9 | +public enum MidjourneyTaskStatusEnum { | ||
| 10 | + /** | ||
| 11 | + * 未启动. | ||
| 12 | + */ | ||
| 13 | + NOT_START(0), | ||
| 14 | + /** | ||
| 15 | + * 已提交. | ||
| 16 | + */ | ||
| 17 | + SUBMITTED(1), | ||
| 18 | + /** | ||
| 19 | + * 执行中. | ||
| 20 | + */ | ||
| 21 | + IN_PROGRESS(3), | ||
| 22 | + /** | ||
| 23 | + * 失败. | ||
| 24 | + */ | ||
| 25 | + FAILURE(4), | ||
| 26 | + /** | ||
| 27 | + * 成功. | ||
| 28 | + */ | ||
| 29 | + SUCCESS(4); | ||
| 30 | + | ||
| 31 | + @Getter | ||
| 32 | + private final int order; | ||
| 33 | + | ||
| 34 | + MidjourneyTaskStatusEnum(int order) { | ||
| 35 | + this.order = order; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyActionRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Midjourney:action 请求 | ||
| 8 | + * | ||
| 9 | + * @author fansili | ||
| 10 | + * @time 2024/5/30 14:02 | ||
| 11 | + * @since 1.0 | ||
| 12 | + */ | ||
| 13 | +@Data | ||
| 14 | +public class MidjourneyActionRequest { | ||
| 15 | + | ||
| 16 | + @Schema(description = "操作按钮id", required = true) | ||
| 17 | + private String customId; | ||
| 18 | + | ||
| 19 | + @Schema(description = "操作按钮id", required = true) | ||
| 20 | + private String taskId; | ||
| 21 | + | ||
| 22 | + @Schema(description = "通知地址", required = false) | ||
| 23 | + private String notifyHook; | ||
| 24 | + | ||
| 25 | + @Schema(description = "自定义参数", required = false) | ||
| 26 | + private String state; | ||
| 27 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyImagineRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +// TODO @fan:待定 | ||
| 9 | +/** | ||
| 10 | + * Midjourney:Imagine 请求 | ||
| 11 | + * | ||
| 12 | + * @author fansili | ||
| 13 | + * @time 2024/5/30 14:02 | ||
| 14 | + * @since 1.0 | ||
| 15 | + */ | ||
| 16 | +@Data | ||
| 17 | +public class MidjourneyImagineRequest { | ||
| 18 | + | ||
| 19 | + @Schema(description = "垫图(参考图)base64数组", required = false) | ||
| 20 | + private List<String> base64Array; | ||
| 21 | + | ||
| 22 | + @Schema(description = "通知地址", required = false) | ||
| 23 | + private String notifyHook; | ||
| 24 | + | ||
| 25 | + @Schema(description = "提示词", required = true) | ||
| 26 | + private String prompt; | ||
| 27 | + | ||
| 28 | + @Schema(description = "自定义参数", required = false) | ||
| 29 | + private String state; | ||
| 30 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneyNotifyRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Midjourney Proxy 通知回调 | ||
| 10 | + * | ||
| 11 | + * - Midjourney Proxy:通知回调 bean 是 com.github.novicezk.midjourney.support.Task | ||
| 12 | + * - 毫秒 api 通知回调文档地址:https://gpt-best.apifox.cn/doc-3530863 | ||
| 13 | + * | ||
| 14 | + * @author fansili | ||
| 15 | + * @time 2024/5/31 10:37 | ||
| 16 | + * @since 1.0 | ||
| 17 | + */ | ||
| 18 | +@Data | ||
| 19 | +public class MidjourneyNotifyRequest { | ||
| 20 | + | ||
| 21 | + @Schema(description = "job id") | ||
| 22 | + private String id; | ||
| 23 | + | ||
| 24 | + @Schema(description = "任务类型 MidjourneyTaskActionEnum") | ||
| 25 | + private String action; | ||
| 26 | + @Schema(description = "任务状态 MidjourneyTaskStatusEnum") | ||
| 27 | + private String status; | ||
| 28 | + | ||
| 29 | + @Schema(description = "提示词") | ||
| 30 | + private String prompt; | ||
| 31 | + @Schema(description = "提示词-英文") | ||
| 32 | + private String promptEn; | ||
| 33 | + | ||
| 34 | + @Schema(description = "任务描述") | ||
| 35 | + private String description; | ||
| 36 | + @Schema(description = "自定义参数") | ||
| 37 | + private String state; | ||
| 38 | + | ||
| 39 | + @Schema(description = "提交时间") | ||
| 40 | + private Long submitTime; | ||
| 41 | + @Schema(description = "开始执行时间") | ||
| 42 | + private Long startTime; | ||
| 43 | + @Schema(description = "结束时间") | ||
| 44 | + private Long finishTime; | ||
| 45 | + | ||
| 46 | + @Schema(description = "图片url") | ||
| 47 | + private String imageUrl; | ||
| 48 | + | ||
| 49 | + @Schema(description = "任务进度") | ||
| 50 | + private String progress; | ||
| 51 | + @Schema(description = "失败原因") | ||
| 52 | + private String failReason; | ||
| 53 | + | ||
| 54 | + @Schema(description = "任务完成后的可执行按钮") | ||
| 55 | + private List<Button> buttons; | ||
| 56 | + | ||
| 57 | + @Data | ||
| 58 | + public static class Button { | ||
| 59 | + | ||
| 60 | + @Schema(description = "MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识") | ||
| 61 | + private String customId; | ||
| 62 | + | ||
| 63 | + @Schema(description = "图标 emoji") | ||
| 64 | + private String emoji; | ||
| 65 | + | ||
| 66 | + @Schema(description = "Make Variations 文本") | ||
| 67 | + private String label; | ||
| 68 | + | ||
| 69 | + @Schema(description = "类型,系统内部使用") | ||
| 70 | + private String type; | ||
| 71 | + | ||
| 72 | + @Schema(description = "样式: 2(Primary)、3(Green)") | ||
| 73 | + private String style; | ||
| 74 | + } | ||
| 75 | +} |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/midjourney/vo/MidjourneySubmitResponse.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.core.model.midjourney.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.Map; | ||
| 7 | + | ||
| 8 | +// TODO @fan:待定 | ||
| 9 | +/** | ||
| 10 | + * Midjourney:Imagine 请求 | ||
| 11 | + * | ||
| 12 | + * @author fansili | ||
| 13 | + * @time 2024/5/30 14:02 | ||
| 14 | + * @since 1.0 | ||
| 15 | + */ | ||
| 16 | +@Data | ||
| 17 | +public class MidjourneySubmitResponse { | ||
| 18 | + | ||
| 19 | + @Schema(description = "状态码: 1(提交成功), 21(已存在), 22(排队中), other(错误)") | ||
| 20 | + private String code; | ||
| 21 | + | ||
| 22 | + @Schema(description = "描述") | ||
| 23 | + private String description; | ||
| 24 | + | ||
| 25 | + @Schema(description = "扩展字段") | ||
| 26 | + private Map<String, Object> properties; | ||
| 27 | + | ||
| 28 | + @Schema(description = "任务ID") | ||
| 29 | + private String result; | ||
| 30 | +} |