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 | +} | ... | ... |