添加comfyuo接口

master
xueqingkun 4 weeks ago
parent fe32142027
commit 7f75464e57

@ -72,10 +72,20 @@
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83_noneautotype</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.3</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,63 @@
package com.supervision.ai.service.hub.config;
import com.supervision.ai.service.hub.constant.ResultStatusEnum;
import com.supervision.ai.service.hub.dto.common.R;
import com.supervision.ai.service.hub.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
/**
*
*
* @author wb
* @date 2022/3/10 13:24
*/
@Slf4j
@Configuration
@RestControllerAdvice(annotations = RestController.class, basePackages = {"com.supervision.ai.service.**.controller"})
public class ExceptionHandlerConfig {
/**
*
*
* @param exception
* @return
*/
@ExceptionHandler(IllegalArgumentException.class)
public R<?> manualValidationExceptionResponse(IllegalArgumentException exception) {
log.error("=========手动校验参数异常=========>>>");
log.error(exception.getMessage(), exception);
log.error("<<<=========手动校验参数异常=========");
return R.fail(ResultStatusEnum.ILLEGAL_ARGUMENT.getCode(), exception.getMessage());
}
@ExceptionHandler(BusinessException.class)
public R<?> businessExceptionResponse(BusinessException exception) {
log.error("=========运行异常=========>>>");
log.error(exception.getMessage(), exception);
log.error("<<<=========运行异常=========");
return R.fail(511, exception.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public R<?> manualValidationExceptionResponse(RuntimeException exception) {
log.error("=========运行异常=========>>>");
log.error(exception.getMessage(), exception);
log.error("<<<=========运行异常=========");
return R.fail(ResultStatusEnum.RUNTIME_EXCEPTION.getCode(), exception.getMessage());
}
@ExceptionHandler(MaxUploadSizeExceededException.class)
public R<?> handleMaxSizeException(MaxUploadSizeExceededException exception) {
log.error("=========文件大小超出限制异常=========>>>");
log.error(exception.getMessage(), exception);
log.error("<<<=========文件大小超出限制异常=========");
return R.fail(ResultStatusEnum.EXCEED_FILE_SIZE.getCode(), exception.getMessage());
}
}

@ -0,0 +1,26 @@
package com.supervision.ai.service.hub.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import java.time.LocalDateTime;
/**
* @author Ray
*/
public class MyMetaObjectHandler implements MetaObjectHandler {
public MyMetaObjectHandler() {
}
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}

@ -0,0 +1,43 @@
package com.supervision.ai.service.hub.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MybatisPlus
*
* @author qmy
* @version 1.0.0 2020/10/22 9:47
* @since JDK1.8
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MyMetaObjectHandler myMetaObjectHandler() {
return new MyMetaObjectHandler();
}
/**
*
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(this.paginationInterceptor());
return interceptor;
}
private PaginationInnerInterceptor paginationInterceptor() {
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
paginationInterceptor.setOverflow(false);
/**
* ! .
*/
paginationInterceptor.setDbType(DbType.POSTGRE_SQL);
return paginationInterceptor;
}
}

@ -2,6 +2,8 @@ package com.supervision.ai.service.hub.config;
import com.supervision.ai.service.hub.filter.JwtAuthenticationFilter;
import com.supervision.ai.service.hub.service.impl.SysUserService;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -18,6 +20,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.Base64;
@Configuration
@ -70,4 +73,11 @@ public class SecurityConfig {
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
String s = Base64.getEncoder().encodeToString(Keys.secretKeyFor(SignatureAlgorithm.HS256).getEncoded());
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String encode = bCryptPasswordEncoder.encode("123456");
System.out.println(encode);
}
}

@ -0,0 +1,87 @@
package com.supervision.ai.service.hub.constant;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import lombok.Getter;
@Getter
public enum ComfyuiParamTypeEnum {
// 整数
INTEGER(0,"整数", Integer.class) {
@Override
public Object coverType(Object value) {
if (null == value){
return null;
}
if (value instanceof Integer){
return value;
}
Assert.isTrue(NumberUtil.isNumber(value.toString()),"参数类型错误");
return NumberUtil.parseInt(value.toString());
}
},
// 浮点型
FLOAT(1,"浮点型", Float.class) {
@Override
public Object coverType(Object value) {
if (null == value){
return null;
}
if (value instanceof Float){
return value;
}
Assert.isTrue(NumberUtil.isNumber(value.toString()),"参数类型错误");
return NumberUtil.parseFloat(value.toString());
}
},
// 字符串
STRING(2,"字符串",String.class) {
@Override
public Object coverType(Object value) {
if (null == value){
return null;
}
if (value instanceof String){
return value;
}
return value.toString();
}
},
// 布尔值
BOOLEAN(3,"布尔值",Boolean.class) {
@Override
public Object coverType(Object value) {
if (null == value){
return null;
}
if (value instanceof Boolean){
return value;
}
Assert.isTrue(false,"参数类型错误");
return null;
}
};
private final int code;
private final String desc;
private final Class<?> type;
ComfyuiParamTypeEnum(int code, String desc,Class<?> type) {
this.code = code;
this.desc = desc;
this.type = type;
}
public static ComfyuiParamTypeEnum getByCode(int code){
for (ComfyuiParamTypeEnum value : ComfyuiParamTypeEnum.values()) {
if (value.getCode() == code){
return value;
}
}
return null;
}
public abstract Object coverType(Object value);
}

@ -0,0 +1,55 @@
package com.supervision.ai.service.hub.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
*
* @author qimaoyu
* @create 2019-07-14 10:22
*/
@NoArgsConstructor
@AllArgsConstructor
public enum ResultStatusEnum {
AUTHENTICATION_FAILED(320, "token失效请重新登录"),
NO_ACCESS_TO_THIS_INTERFACE(320, "无权访问此接口!"),
FAILED_TO_GENERATE_TOKEN(321, "生成token失败"),
ACCOUNT_PASSWORD_INCORRECT(322, "账号或密码错误!"),
ACCOUNT_NOT_CREATE(323, "账号未创建!"),
HAS_BEEN_PULLED_BLACK(324, "已被删除或禁用,无法登录!"),
USERNAME_MAIL_IS_EXIST(341, "登录名称已经被注册!"),
USERNAME_IS_BLANK(342, "登录名称为空!"),
VERIFICATION_CODE_EXPIRED(350,"验证码已过期,请重新获取。"),
VERIFICATION_CODE_FAILURE(351,"验证码输入错误。"),
OPERATE_FAIL(360,"修改毕业生信息失败。"),
DATA_IS_EMPTY(370,"查询到的结果为空"),
SYSTEM_ABNORMAL(500, "系统繁忙,请稍后重试!"),
UPLOAD_EXCEPTION(501, "文件上传异常!"),
EXPORT_EXCEPTION(502, "文件导出异常!"),
INCORRECT_FILE_FORMAT(503, "文件格式不正确!"),
PARAMETER_CANNOT_BE_EMPTY(504, "参数不能为空,操作失败!"),
NO_TEMP_UPLOADFILEPATH(505,"未配置文件上传临时存储路径"),
USER_DOES_NOT_EXIST(507, "用户不存在,操作失败!"),
ILLEGAL_ARGUMENT(508, "参数校验失败!"),
RUNTIME_EXCEPTION(509, "程序运行异常!"),
EXCEED_FILE_SIZE(510, "文件大小超出限制!"),
IMPORT_COMPANY_FORMAT_ERROR(521,"Excel表格格式错误"),
IMPORT_COMPANY_FAIL(522,"部分数据导入失败"),
INSERT_FAIL(600,"新增失败"),
DuplicateKeyException(601,"该条信息已经存在,请勿重复添加"),
UPDATE_FAIL(700,"更新失败"),
DELETE_FAIL(800,"删除失败"),
YEAR_IS_CLOSE(1001,"该年度暂未开启");
@Getter
@Setter
private int code;
@Getter
@Setter
private String message;
}

@ -0,0 +1,48 @@
package com.supervision.ai.service.hub.controller;
import com.supervision.ai.service.hub.dto.common.R;
import com.supervision.ai.service.hub.service.ComfyUIService;
import com.supervision.ai.service.hub.vo.comfyui.RunPromptReqVo;
import com.supervision.ai.service.hub.vo.comfyui.TaskResultResVo;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/comfyui")
@RequiredArgsConstructor
public class ComfyUIController {
private final ComfyUIService comfyUIService;
/**
* prompt
* @param runPromptReqVo prompt
* @return
*/
@PostMapping("/run")
public R<String> runPrompt(@RequestBody RunPromptReqVo runPromptReqVo) {
String taskId = comfyUIService.runPrompt(runPromptReqVo);
return R.ok(taskId);
}
@GetMapping("/queryHistory")
public R<List<TaskResultResVo>> queryHistory(@RequestParam(name = "promptId", required = false) String promptId) {
List<TaskResultResVo> taskResultResVos = comfyUIService.queryHistory(promptId);
return R.ok(taskResultResVos);
}
@PostMapping("/uploadImage")
public R<String> uploadImage(@RequestParam("file") MultipartFile file) throws Exception {
String imageId = comfyUIService.uploadImage(file);
return R.ok(imageId);
}
@GetMapping("/downloadView")
public void downloadView(@RequestParam("fileName") String fileName, HttpServletResponse response) throws Exception {
comfyUIService.downloadView(fileName, response);
}
}

@ -0,0 +1,58 @@
package com.supervision.ai.service.hub.domain;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Data;
/**
* comfyui
* @TableName comfyui_prompt
*/
@Data
@TableName(value ="comfyui_prompt",autoResultMap = true)
public class ComfyuiPrompt implements Serializable {
/**
*
*/
@TableId
private String id;
/**
*
*/
private String promptName;
/**
* 0: 1 2
*/
private String promptType;
/**
*
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject prompt;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
*
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}

@ -0,0 +1,59 @@
package com.supervision.ai.service.hub.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.Data;
/**
*
* @TableName comfyui_prompt_param
*/
@TableName(value ="comfyui_prompt_param")
@Data
public class ComfyuiPromptParam implements Serializable {
/**
*
*/
@TableId
private String id;
/**
* varchar(64)
*/
private String promptId;
/**
* key
*/
private String paramKey;
/**
* 0 1 2 3
*/
private Integer paramType;
/**
* true false:
*/
private Boolean required;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
*
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}

@ -0,0 +1,14 @@
package com.supervision.ai.service.hub.dto.comfyui;
import lombok.Data;
/**
*
*/
@Data
public class ImageUploadDTO {
private String name;
private String subfolder;
private String type;
}

@ -0,0 +1,19 @@
package com.supervision.ai.service.hub.dto.comfyui;
import lombok.Data;
import java.util.Map;
/**
*
*/
@Data
public class PromptRunDTO {
private String prompt_id;
private int number;
private Map<String,Object> node_errors;
private Map<String,Object> error;
}

@ -0,0 +1,22 @@
package com.supervision.ai.service.hub.dto.comfyui;
import lombok.Data;
@Data
public class ResourceViewDTO {
private String fileName;
private String contentType;
private byte[] content;
public ResourceViewDTO() {
}
public ResourceViewDTO(String fileName, String contentType, byte[] content) {
this.fileName = fileName;
this.contentType = contentType;
this.content = content;
}
}

@ -0,0 +1,76 @@
/*
* : CustomException
* :
* : <>
* : RedName
* : 2022/8/5
* : <>
* : <>
* : <>
*/
package com.supervision.ai.service.hub.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
/**
* <>
*
*
* @author ljt
* @version [, 2022/8/5]
* @see [/]
* @since [/]
*/
@Slf4j
public class BusinessException extends RuntimeException {
/**
*
*/
private final Integer code;
/**
*
*/
private final String message;
public BusinessException(Throwable cause) {
super(cause);
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
this.message = null;
}
public BusinessException(Throwable cause, String message) {
super(cause);
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
this.message = message;
}
public BusinessException(String message) {
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
this.message = message;
}
public BusinessException(String message, Integer code) {
this.message = message;
this.code = code;
}
public BusinessException(String message, Throwable e) {
super(message, e);
log.error(message, e);
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public Integer getCode() {
return code;
}
}

@ -0,0 +1,18 @@
package com.supervision.ai.service.hub.mapper;
import com.supervision.ai.service.hub.domain.ComfyuiPrompt;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author Administrator
* @description comfyui_prompt(comfyui)Mapper
* @createDate 2025-03-31 17:49:56
* @Entity com.supervision.ai.service.hub.domain.ComfyuiPrompt
*/
public interface ComfyuiPromptMapper extends BaseMapper<ComfyuiPrompt> {
}

@ -0,0 +1,18 @@
package com.supervision.ai.service.hub.mapper;
import com.supervision.ai.service.hub.domain.ComfyuiPromptParam;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author Administrator
* @description comfyui_prompt_paramMapper
* @createDate 2025-03-31 17:49:56
* @Entity com.supervision.ai.service.hub.domain.ComfyuiPromptParam
*/
public interface ComfyuiPromptParamMapper extends BaseMapper<ComfyuiPromptParam> {
}

@ -0,0 +1,32 @@
package com.supervision.ai.service.hub.service;
import com.alibaba.fastjson.JSONObject;
import com.supervision.ai.service.hub.dto.comfyui.ImageUploadDTO;
import com.supervision.ai.service.hub.dto.comfyui.PromptRunDTO;
import com.supervision.ai.service.hub.dto.comfyui.ResourceViewDTO;
import java.util.Map;
public interface ComfyUIApiService {
/**
* prompt
* @param prompt
* @return
*/
PromptRunDTO runPrompt(JSONObject prompt);
/**
*
* @param promptId id
* @return
*/
Map<String,Object> queryHistory(String promptId);
ImageUploadDTO uploadImage(byte[] file, String fileName);
ResourceViewDTO downloadView(String imageId);
}

@ -0,0 +1,37 @@
package com.supervision.ai.service.hub.service;
import com.supervision.ai.service.hub.domain.ComfyuiPromptParam;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
* @description comfyui_prompt_paramService
* @createDate 2025-03-31 17:49:56
*/
public interface ComfyUIPromptParamService extends IService<ComfyuiPromptParam> {
/**
*
* @param params
* @param promptId id
* @return true false
*/
boolean requiredCheck(Map<String,Object> params, String promptId);
boolean requiredCheck(Map<String,Object> params, List<ComfyuiPromptParam> promptParamList);
/**
* promptId
* @param promptId id
* @return
*/
List<ComfyuiPromptParam> listByPromptId(String promptId);
ComfyuiPromptParam selectPromptParam(String paramKey,List<ComfyuiPromptParam> promptParamList);
}

@ -0,0 +1,21 @@
package com.supervision.ai.service.hub.service;
import com.supervision.ai.service.hub.domain.ComfyuiPrompt;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author Administrator
* @description comfyui_prompt(comfyui)Service
* @createDate 2025-03-31 17:49:56
*/
public interface ComfyUIPromptService extends IService<ComfyuiPrompt> {
/**
*
* @param promptId id
* @return true false
*/
boolean promptExist(String promptId);
}

@ -0,0 +1,20 @@
package com.supervision.ai.service.hub.service;
import com.supervision.ai.service.hub.vo.comfyui.RunPromptReqVo;
import com.supervision.ai.service.hub.vo.comfyui.TaskResultResVo;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
public interface ComfyUIService {
String runPrompt(RunPromptReqVo runPromptReqVo);
List<TaskResultResVo> queryHistory(String promptId);
String uploadImage(MultipartFile file) throws IOException;
void downloadView(String imageId, HttpServletResponse response) throws IOException;
}

@ -0,0 +1,105 @@
package com.supervision.ai.service.hub.service.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.supervision.ai.service.hub.dto.comfyui.ImageUploadDTO;
import com.supervision.ai.service.hub.dto.comfyui.PromptRunDTO;
import com.supervision.ai.service.hub.dto.comfyui.ResourceViewDTO;
import com.supervision.ai.service.hub.service.ComfyUIApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Map;
@Slf4j
@Service
public class ComfyUIApiServiceImpl implements ComfyUIApiService {
@Value("${comfyUI.server.ip}")
private String comfyUIServiceIp;
@Value("${comfyUI.server.port}")
private String comfyUIServicePort;
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public PromptRunDTO runPrompt(JSONObject prompt) {
String url = "http://" + comfyUIServiceIp + ":" + comfyUIServicePort + "/prompt";
log.info("comfyUI runPrompt 请求地址:{}",url);
HttpRequest request = HttpUtil.createPost(url).body(prompt.toJSONString());
try (HttpResponse execute = request.execute()){
String body = execute.body();
log.info("comfyUI runPrompt 请求结果:{}",body);
if (execute.isOk()){
try {
return objectMapper.readValue(body, PromptRunDTO.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}else {
throw new RuntimeException("/prompt请求失败");
}
}
}
@Override
public Map<String, Object> queryHistory(String promptId) {
String url = "http://" + comfyUIServiceIp + ":" + comfyUIServicePort + "/history" + (StrUtil.isEmpty(promptId)? "" : "/"+promptId);
log.info("comfyUI queryHistory 请求地址:{}",url);
try (HttpResponse execute = HttpUtil.createGet(url).execute()){
if (execute.isOk()){
String body = execute.body();
try {
return objectMapper.readValue(body, Map.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}else {
throw new RuntimeException("/history请求失败");
}
}
}
@Override
public ImageUploadDTO uploadImage(byte[] file, String fileName) {
String url = "http://" + comfyUIServiceIp + ":" + comfyUIServicePort + "/upload/image";
HttpRequest request = HttpUtil.createPost(url);
request.form("image",file,fileName);
try (HttpResponse execute = request.execute()){
if (execute.isOk()){
String body = execute.body();
log.info("comfyUI uploadImage 请求结果:{}",body);
try {
return objectMapper.readValue(body, ImageUploadDTO.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}else {
throw new RuntimeException("/upload/image请求失败");
}
}
}
@Override
public ResourceViewDTO downloadView(String imageId) {
Assert.notEmpty(imageId,"imageId不能为空");
String url = "http://" + comfyUIServiceIp + ":" + comfyUIServicePort + "/view?filename=" + imageId;
log.info("comfyUI downloadImage 请求地址:{}",url);
try (HttpResponse execute = HttpUtil.createGet(url).execute()){
if (execute.isOk()){
return new ResourceViewDTO(execute.getFileNameFromDisposition("filename"),
execute.header("content-type"), execute.bodyBytes());
}else {
throw new RuntimeException("下载图片请求失败");
}
}
}
}

@ -0,0 +1,76 @@
package com.supervision.ai.service.hub.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.supervision.ai.service.hub.domain.ComfyuiPromptParam;
import com.supervision.ai.service.hub.service.ComfyUIPromptParamService;
import com.supervision.ai.service.hub.mapper.ComfyuiPromptParamMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
* @description comfyui_prompt_paramService
* @createDate 2025-03-31 17:49:56
*/
@Slf4j
@Service
public class ComfyUIPromptParamServiceImpl extends ServiceImpl<ComfyuiPromptParamMapper, ComfyuiPromptParam>
implements ComfyUIPromptParamService {
@Override
public boolean requiredCheck(Map<String, Object> params, String promptId) {
Assert.notEmpty(promptId, "promptId不能为空");
List<ComfyuiPromptParam> list = this.lambdaQuery()
.eq(ComfyuiPromptParam::getPromptId, promptId).eq(ComfyuiPromptParam::getRequired, true).list();
return requiredCheck(params, list);
}
@Override
public boolean requiredCheck(Map<String, Object> params, List<ComfyuiPromptParam> promptParamList) {
if (CollUtil.isEmpty(promptParamList)) {
return true;
}
if (CollUtil.isEmpty(params)){
return false;
}
for (ComfyuiPromptParam comfyuiPromptParam : promptParamList) {
Object value = params.get(comfyuiPromptParam.getParamKey());
if (null == value || "".equals(value)) {
log.error("参数{}为必填项,请检查",comfyuiPromptParam.getParamKey());
return false;
}
}
return true;
}
@Override
public List<ComfyuiPromptParam> listByPromptId(String promptId) {
return super.lambdaQuery().eq(ComfyuiPromptParam::getPromptId, promptId).list();
}
@Override
public ComfyuiPromptParam selectPromptParam(String paramKey, List<ComfyuiPromptParam> promptParamList) {
if (CollUtil.isEmpty(promptParamList)){
return null;
}
for (ComfyuiPromptParam comfyuiPromptParam : promptParamList) {
if (StrUtil.equals(comfyuiPromptParam.getParamKey(), paramKey)){
return comfyuiPromptParam;
}
}
return null;
}
}

@ -0,0 +1,28 @@
package com.supervision.ai.service.hub.service.impl;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.supervision.ai.service.hub.domain.ComfyuiPrompt;
import com.supervision.ai.service.hub.service.ComfyUIPromptService;
import com.supervision.ai.service.hub.mapper.ComfyuiPromptMapper;
import org.springframework.stereotype.Service;
/**
* @author Administrator
* @description comfyui_prompt(comfyui)Service
* @createDate 2025-03-31 17:49:56
*/
@Service
public class ComfyUIPromptServiceImpl extends ServiceImpl<ComfyuiPromptMapper, ComfyuiPrompt>
implements ComfyUIPromptService {
@Override
public boolean promptExist(String promptId) {
Assert.notEmpty(promptId,"promptId不能为空");
return this.lambdaQuery().eq(ComfyuiPrompt::getId, promptId).exists();
}
}

@ -0,0 +1,137 @@
package com.supervision.ai.service.hub.service.impl;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.supervision.ai.service.hub.constant.ComfyuiParamTypeEnum;
import com.supervision.ai.service.hub.domain.ComfyuiPrompt;
import com.supervision.ai.service.hub.domain.ComfyuiPromptParam;
import com.supervision.ai.service.hub.dto.comfyui.ImageUploadDTO;
import com.supervision.ai.service.hub.dto.comfyui.PromptRunDTO;
import com.supervision.ai.service.hub.dto.comfyui.ResourceViewDTO;
import com.supervision.ai.service.hub.service.ComfyUIApiService;
import com.supervision.ai.service.hub.service.ComfyUIService;
import com.supervision.ai.service.hub.service.ComfyUIPromptParamService;
import com.supervision.ai.service.hub.service.ComfyUIPromptService;
import com.supervision.ai.service.hub.vo.comfyui.RunPromptReqVo;
import com.supervision.ai.service.hub.vo.comfyui.TaskResultResVo;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class ComfyUIServiceImpl implements ComfyUIService {
private final ComfyUIApiService comfyUIApiService;
private final ComfyUIPromptService comfyuiPromptService;
private final ComfyUIPromptParamService comfyuiPromptParamService;
@Override
public String runPrompt(RunPromptReqVo runPromptReqVo) {
Assert.notEmpty(runPromptReqVo.getPromptId(),"promptId不能为空");
boolean exist = comfyuiPromptService.promptExist(runPromptReqVo.getPromptId());
Assert.isTrue(exist,"promptId不存在");
// 必填参数校验
List<ComfyuiPromptParam> promptParams = comfyuiPromptParamService.listByPromptId(runPromptReqVo.getPromptId());
List<ComfyuiPromptParam> requiredParams = promptParams.stream().filter(ComfyuiPromptParam::getRequired).toList();
boolean checkPass = comfyuiPromptParamService.requiredCheck(runPromptReqVo.getParams(), requiredParams);
Assert.isTrue(checkPass,
"必填参数"+requiredParams.stream().map(ComfyuiPromptParam::getParamKey).collect(Collectors.joining(","))+"不能为空");
ComfyuiPrompt comfyuiPrompt = comfyuiPromptService.getById(runPromptReqVo.getPromptId());
Assert.notNull(comfyuiPrompt.getPrompt(), "prompt不能为空");
// 设置参数
JSONObject prompt = comfyuiPrompt.getPrompt();
Map<String, Object> params = runPromptReqVo.getParams();
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (null != entry.getValue()){
ComfyuiPromptParam comfyuiPromptParam = comfyuiPromptParamService.selectPromptParam(entry.getKey(), promptParams);
if (null == comfyuiPromptParam){
continue;
}
ComfyuiParamTypeEnum comfyuiParamTypeEnum = ComfyuiParamTypeEnum.getByCode(comfyuiPromptParam.getParamType());
Assert.notNull(comfyuiParamTypeEnum,"不支持的数据类型");
Object value = comfyuiParamTypeEnum.coverType(entry.getValue());
log.info("设置参数key{},参数value:{}", entry.getKey(), value);
BeanPath.create(entry.getKey()).set(prompt, value);
}
}
// 运行提示词
PromptRunDTO promptRunDTO = comfyUIApiService.runPrompt(prompt);
Map<String, Object> error = promptRunDTO.getError();
if (CollUtil.isNotEmpty(error)){
String errorMessage = (String) error.get("message");
Assert.isTrue(StrUtil.isNotEmpty(errorMessage),errorMessage);
}
return promptRunDTO.getPrompt_id();
}
@Override
public List<TaskResultResVo> queryHistory(String promptId) {
Map<String, Object> history = comfyUIApiService.queryHistory(promptId);
if (CollUtil.isEmpty(history)){
return new ArrayList<>();
}
List<TaskResultResVo> resultResVos = new ArrayList<>();
for (Map.Entry<String, Object> entry : history.entrySet()) {
TaskResultResVo taskResultResVo = new TaskResultResVo();
Object value = entry.getValue();
taskResultResVo.setPromptId(entry.getKey());
if (null != value){
Map<String, Object> status = (Map<String, Object>) ((Map<String, Object>) value).get("status");
Boolean completed = (Boolean) status.get("completed");
if (completed){
Map<String, Object> outputs = (Map<String, Object>) ((Map<String, Object>) value).get("outputs");
if (CollUtil.isNotEmpty(outputs)){
for (Map.Entry<String, Object> outputEntry : outputs.entrySet()) {
Map<String,Object> outputEntryValue = (Map<String, Object>) outputEntry.getValue();
List<Map<String,Object>> images = (List<Map<String, Object>>) outputEntryValue.get("images");
taskResultResVo.setImages(images.stream().map(image -> (String)(image.get("filename"))).collect(Collectors.toList()));
}
}
}
}
resultResVos.add(taskResultResVo);
}
return resultResVos;
}
@Override
public String uploadImage(MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
byte[] bytes = file.getBytes();
ImageUploadDTO imageUploadDTO = comfyUIApiService.uploadImage(bytes, filename);
if (StrUtil.isNotEmpty(imageUploadDTO.getSubfolder())){
return imageUploadDTO.getSubfolder() + "/" + imageUploadDTO.getName();
}
return imageUploadDTO.getName();
}
@Override
public void downloadView(String imageId, HttpServletResponse response) throws IOException {
Assert.notEmpty(imageId,"imageId不能为空");
ResourceViewDTO resourceViewDTO = comfyUIApiService.downloadView(imageId);
response.setContentType(resourceViewDTO.getContentType());
response.setHeader("Content-Disposition", "attachment; filename=" + resourceViewDTO.getFileName());
try (ServletOutputStream outputStream = response.getOutputStream()){
outputStream.write(resourceViewDTO.getContent());
}
}
}

@ -38,7 +38,7 @@ public class HeygemApiServiceImpl implements HeygemApiService {
TimeInterval timer = DateUtil.timer();
HttpRequest request = HttpUtil.createPost(url).body(JSONUtil.toJsonStr(tranReqDTO));
try (HttpResponse response = request.execute()) {
log.info("/v1/preprocess_and_tran请求耗时:{}", timer.intervalMs());
log.info("/v1/preprocess_and_tran请求耗时:{}毫秒", timer.intervalMs());
if (!response.isOk()){
throw new RuntimeException("请求失败");
}
@ -59,7 +59,7 @@ public class HeygemApiServiceImpl implements HeygemApiService {
HttpRequest request = HttpUtil.createPost(url).body(JSONUtil.toJsonStr(textToAudioReqDTO));
TimeInterval timer = DateUtil.timer();
try (HttpResponse response = request.execute()) {
log.info("/v1/invoke请求耗时:{}", timer.intervalMs());
log.info("/v1/invoke请求耗时:{}毫秒", timer.intervalMs());
if (!response.isOk()&& response.header("Content-Type").equals("application/json")){
try {
String body = response.body();
@ -88,7 +88,7 @@ public class HeygemApiServiceImpl implements HeygemApiService {
HttpRequest request = HttpUtil.createPost(url).body(JSONUtil.toJsonStr(videoGenerateReqDTO));
TimeInterval timer = DateUtil.timer();
try (HttpResponse response = request.execute()) {
log.info("请求/easy/submit耗时:{}", timer.intervalMs());
log.info("请求/easy/submit耗时:{}毫秒", timer.intervalMs());
String body = response.body();
log.info("/easy/submit接口response:{}", body);
try {
@ -110,7 +110,7 @@ public class HeygemApiServiceImpl implements HeygemApiService {
log.info("url:{}", url);
TimeInterval timer = DateUtil.timer();
try (HttpResponse response = HttpUtil.createGet(url).form("taskCode", taskCode).execute()) {
log.info("请求/easy/query耗时:{}", timer.intervalMs());
log.info("请求/easy/query耗时:{}毫秒", timer.intervalMs());
String body = response.body();
log.info("/easy/query接口response:{}", body);
try {

@ -0,0 +1,20 @@
package com.supervision.ai.service.hub.vo.comfyui;
import lombok.Data;
import java.util.Map;
@Data
public class RunPromptReqVo {
/**
* ID
*/
private String promptId;
/**
*
*/
private Map<String,Object> params;
}

@ -0,0 +1,17 @@
package com.supervision.ai.service.hub.vo.comfyui;
import lombok.Data;
import java.util.List;
/**
*
*/
@Data
public class TaskResultResVo {
private String promptId;
private boolean completed;
private List<String> images;
}

@ -6,7 +6,10 @@ spring:
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
server:
port: 9901
servlet:
@ -28,3 +31,7 @@ heygem:
port: 18180
f2f:
port: 8383
comfyUI:
server:
ip: 192.168.10.113
port: 8188

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.ai.service.hub.mapper.ComfyuiPromptMapper">
<resultMap id="BaseResultMap" type="com.supervision.ai.service.hub.domain.ComfyuiPrompt">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="promptName" column="prompt_name" jdbcType="VARCHAR"/>
<result property="promptType" column="prompt_type" jdbcType="VARCHAR"/>
<result property="prompt" column="prompt" jdbcType="OTHER" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,prompt_name,prompt_type,
prompt,create_time,update_time
</sql>
</mapper>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.supervision.ai.service.hub.mapper.ComfyuiPromptParamMapper">
<resultMap id="BaseResultMap" type="com.supervision.ai.service.hub.domain.ComfyuiPromptParam">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="promptId" column="prompt_id" jdbcType="VARCHAR"/>
<result property="paramKey" column="param_key" jdbcType="VARCHAR"/>
<result property="paramType" column="param_type" jdbcType="INTEGER"/>
<result property="required" column="required" jdbcType="BOOLEAN"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,prompt_id,param_key,
param_type,required,create_time,
update_time
</sql>
</mapper>

@ -0,0 +1,60 @@
package com.supervision.ai.service.hub;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.supervision.ai.service.hub.domain.ComfyuiPrompt;
import com.supervision.ai.service.hub.dto.comfyui.ImageUploadDTO;
import com.supervision.ai.service.hub.dto.comfyui.PromptRunDTO;
import com.supervision.ai.service.hub.dto.comfyui.ResourceViewDTO;
import com.supervision.ai.service.hub.service.ComfyUIApiService;
import com.supervision.ai.service.hub.service.ComfyUIPromptService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Map;
@Slf4j
@SpringBootTest
public class ComfyUIApiServiceTest {
@Autowired
private ComfyUIApiService comfyUIApiService;
@Test
public void uploadImageTest() {
byte[] bytes = FileUtil.readBytes("C:\\Users\\Administrator\\Downloads\\Arya.png");
ImageUploadDTO res = comfyUIApiService.uploadImage(bytes, "图片1");
log.info(JSONUtil.toJsonStr(res));
}
@Test
public void runPromptTest() {
String prompt = "{\"prompt\":{\"4\":{\"inputs\":{\"ckpt_name\":\"sd_xl_base_1.0.safetensors\"},\"class_type\":\"CheckpointLoaderSimple\",\"_meta\":{\"title\":\"Load Checkpoint - BASE\"}},\"5\":{\"inputs\":{\"width\":1024,\"height\":1024,\"batch_size\":1},\"class_type\":\"EmptyLatentImage\",\"_meta\":{\"title\":\"空Latent图像\"}},\"6\":{\"inputs\":{\"text\":\"a cat under the snow with blue eyes, covered by snow, cinematic style, medium shot, professional photo, animal\",\"clip\":[\"4\",1]},\"class_type\":\"CLIPTextEncode\",\"_meta\":{\"title\":\"CLIP文本编码\"}},\"7\":{\"inputs\":{\"text\":\"text, watermark\",\"clip\":[\"4\",1]},\"class_type\":\"CLIPTextEncode\",\"_meta\":{\"title\":\"CLIP文本编码\"}},\"10\":{\"inputs\":{\"add_noise\":\"enable\",\"noise_seed\":2025,\"steps\":25,\"cfg\":8,\"sampler_name\":\"euler\",\"scheduler\":\"normal\",\"start_at_step\":0,\"end_at_step\":20,\"return_with_leftover_noise\":\"enable\",\"model\":[\"4\",0],\"positive\":[\"6\",0],\"negative\":[\"7\",0],\"latent_image\":[\"5\",0]},\"class_type\":\"KSamplerAdvanced\",\"_meta\":{\"title\":\"KSampler (Advanced) - BASE\"}},\"11\":{\"inputs\":{\"add_noise\":\"disable\",\"noise_seed\":0,\"steps\":25,\"cfg\":8,\"sampler_name\":\"euler\",\"scheduler\":\"normal\",\"start_at_step\":20,\"end_at_step\":10000,\"return_with_leftover_noise\":\"disable\",\"model\":[\"12\",0],\"positive\":[\"15\",0],\"negative\":[\"16\",0],\"latent_image\":[\"10\",0]},\"class_type\":\"KSamplerAdvanced\",\"_meta\":{\"title\":\"KSampler (Advanced) - REFINER\"}},\"12\":{\"inputs\":{\"ckpt_name\":\"sd_xl_refiner_1.0.safetensors\"},\"class_type\":\"CheckpointLoaderSimple\",\"_meta\":{\"title\":\"Load Checkpoint - REFINER\"}},\"15\":{\"inputs\":{\"text\":\"evening sunset scenery blue sky nature, glass bottle with a galaxy in it\",\"clip\":[\"12\",1]},\"class_type\":\"CLIPTextEncode\",\"_meta\":{\"title\":\"CLIP文本编码\"}},\"16\":{\"inputs\":{\"text\":\"text, watermark\",\"clip\":[\"12\",1]},\"class_type\":\"CLIPTextEncode\",\"_meta\":{\"title\":\"CLIP文本编码\"}},\"17\":{\"inputs\":{\"samples\":[\"11\",0],\"vae\":[\"12\",2]},\"class_type\":\"VAEDecode\",\"_meta\":{\"title\":\"VAE解码\"}},\"19\":{\"inputs\":{\"filename_prefix\":\"ComfyUI\",\"images\":[\"17\",0]},\"class_type\":\"SaveImage\",\"_meta\":{\"title\":\"保存图像\"}}}}";
PromptRunDTO res = comfyUIApiService.runPrompt(JSON.parseObject(prompt));
log.info(JSONUtil.toJsonStr(res));
}
@Test
public void queryHistoryTest() {
Map<String, Object> res = comfyUIApiService.queryHistory("512f2ad2-2c7b-4227-8e52-86be11c3d5b9");
log.info(JSONUtil.toJsonStr(res));
}
@Test
public void downloadImageTest() {
ResourceViewDTO resourceViewDTO = comfyUIApiService.downloadView("ComfyUI_00070_.png");
FileUtil.writeBytes(resourceViewDTO.getContent(), "C:\\Users\\Administrator\\Downloads\\ComfyUI_00070_.png");
}
@Autowired
private ComfyUIPromptService comfyUIPromptService;
@Test
public void test() {
ComfyuiPrompt comfyuiPrompt = comfyUIPromptService.getById("1");
System.out.println(comfyuiPrompt);
}
}
Loading…
Cancel
Save