【临时提交】增加 MidjourneyApi

This commit is contained in:
cherishsince 2024-06-11 17:36:30 +08:00
parent 1ac1c007ad
commit 937992fd16
10 changed files with 412 additions and 0 deletions

View File

@ -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;
}

View File

@ -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 - 放大缩小U1U2...
*
* @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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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;
/**
* Midjourneyaction 请求
*
* @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;
}

View File

@ -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待定
/**
* MidjourneyImagine 请求
*
* @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;
}

View File

@ -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 = "样式: 2Primary、3Green")
private String style;
}
}

View File

@ -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待定
/**
* MidjourneyImagine 请求
*
* @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;
}