diff --git a/src/main/java/com/ai/da/common/utils/SendRequestUtil.java b/src/main/java/com/ai/da/common/utils/SendRequestUtil.java index 1b170d64..05cc4415 100644 --- a/src/main/java/com/ai/da/common/utils/SendRequestUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendRequestUtil.java @@ -9,6 +9,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import java.util.Map; + @Slf4j @Component public class SendRequestUtil { @@ -68,6 +70,26 @@ public class SendRequestUtil { } } + public String sendFluxPost(String url, String requestBodyStr){ + int status; + String body; + try (HttpResponse execute = HttpRequest.post(url) + .header(Header.CONTENT_TYPE, "application/json") + .header("x-key", "d447a0ac-2291-4f1c-9a36-f7614c385989") + .body(requestBodyStr) // Hutool 会自动处理 JSON 序列化 + .timeout(180000) // 设置超时(毫秒) + .execute()) { + + status = execute.getStatus(); + body = execute.body(); + if (status == 200) { + return body; + } + } + log.warn("请求失败,状态码为 : {}, body: {}", status, body); + return null; + } + public String sendPost(String url, String requestBodyStr){ int status; String body; @@ -87,6 +109,27 @@ public class SendRequestUtil { return null; } + public String sendGet(String url, Map params) { + int status; + String body; + try (HttpResponse execute = HttpRequest.get(url) + .form(params) // 直接传入Map,Hutool会正确处理 + .timeout(180000) + .execute()) { + + status = execute.getStatus(); + body = execute.body(); + if (status == 200) { + return body; + } + } catch (Exception e) { + log.error("请求发生异常: {}", e.getMessage(), e); + return null; + } + log.warn("请求失败,状态码为: {}, body: {}", status, body); + return body; + } + } diff --git a/src/main/java/com/ai/da/controller/GenerateController.java b/src/main/java/com/ai/da/controller/GenerateController.java index 26529c0c..8aa1db37 100644 --- a/src/main/java/com/ai/da/controller/GenerateController.java +++ b/src/main/java/com/ai/da/controller/GenerateController.java @@ -1,5 +1,6 @@ package com.ai.da.controller; +import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.response.Response; import com.ai.da.model.dto.*; import com.ai.da.model.vo.*; @@ -188,7 +189,28 @@ public class GenerateController { return Response.success(generateService.getImageDescription(path)); } +// @ApiOperation(value = "试用flux") +// @GetMapping("/flux") + public Response flux(@RequestParam("path") String path, + @RequestParam("type") int type, + @RequestParam(value = "prompt", required = false) String prompt){ + CreditsEventsEnum typeEnum = CreditsEventsEnum.RELIGHT; + switch (type){ + case 1: + typeEnum = CreditsEventsEnum.TO_PRODUCT_IMAGE; + break; + case 2: + typeEnum = CreditsEventsEnum.IMAGE_TO_SKETCH; + break; + } + return Response.success(generateService.flux(typeEnum, prompt, path)); + } +// @ApiOperation(value = "获取flux结果") +// @GetMapping("/fluxResult") + public Response fluxResult(@RequestParam("taskId") String taskId){ + return Response.success(generateService.getFluxResult(taskId, 87L)); + } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ToProductImageResult.java b/src/main/java/com/ai/da/mapper/primary/entity/ToProductImageResult.java index c6b601cd..4180643d 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/ToProductImageResult.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/ToProductImageResult.java @@ -20,6 +20,11 @@ public class ToProductImageResult implements Serializable { @ApiModelProperty(value = "elementId") private Long elementId; + /** + * 取值类型: DesignOutfit 以design的结果作为图片来源 + * ProductElement 上传的图片 + * ToProductImage 以to product image的结果作为图片来源(relight) + */ @ApiModelProperty(value = "elementType") private String elementType; @@ -53,4 +58,6 @@ public class ToProductImageResult implements Serializable { private Long projectId; private String taskIdBatch; + + private String modelName; } diff --git a/src/main/java/com/ai/da/model/dto/ToProductImageDTO.java b/src/main/java/com/ai/da/model/dto/ToProductImageDTO.java index 769a0519..657de1ba 100644 --- a/src/main/java/com/ai/da/model/dto/ToProductImageDTO.java +++ b/src/main/java/com/ai/da/model/dto/ToProductImageDTO.java @@ -16,4 +16,5 @@ public class ToProductImageDTO { private Double brightenValue; private BigDecimal imageStrengthMin; private BigDecimal imageStrengthMax; + private String modelName; } diff --git a/src/main/java/com/ai/da/model/vo/MagicToolResultVO.java b/src/main/java/com/ai/da/model/vo/MagicToolResultVO.java index 1c26db5a..24b2a7ed 100644 --- a/src/main/java/com/ai/da/model/vo/MagicToolResultVO.java +++ b/src/main/java/com/ai/da/model/vo/MagicToolResultVO.java @@ -28,4 +28,8 @@ public class MagicToolResultVO { private String elementType; private Long elementId; + + public MagicToolResultVO(String status) { + this.status = status; + } } diff --git a/src/main/java/com/ai/da/service/GenerateService.java b/src/main/java/com/ai/da/service/GenerateService.java index ab396881..b8ea36f2 100644 --- a/src/main/java/com/ai/da/service/GenerateService.java +++ b/src/main/java/com/ai/da/service/GenerateService.java @@ -1,5 +1,6 @@ package com.ai.da.service; +import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.mapper.primary.entity.Generate; import com.ai.da.mapper.primary.entity.GenerateDetail; import com.ai.da.model.dto.*; @@ -81,4 +82,10 @@ public interface GenerateService extends IService { String reimagineFreePik(String path, String prompt, String style) throws IOException; String getImageDescription(String imagePath); + + String flux(CreditsEventsEnum func, String prompt, String imagePath); + + String getFluxResult(String taskId, Long accountId); + + byte[] downloadVideoOrImage(String url); } diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index e9db0230..f7264a53 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -62,6 +62,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.ai.da.common.enums.CollectionLevel1TypeEnum.*; +import static com.ai.da.common.enums.CreditsEventsEnum.TO_PRODUCT_IMAGE; @Slf4j @Service @@ -326,8 +327,8 @@ public class GenerateServiceImpl extends ServiceImpl i Boolean b = creditsService.taskCreditsDeduction(accountId, taskId); // 3、记录积分变更 if (b) creditsService.insertToCreditsDetail(accountId, - CreditsEventsEnum.TO_PRODUCT_IMAGE.getName(), - CreditsEventsEnum.TO_PRODUCT_IMAGE.getValue(), + TO_PRODUCT_IMAGE.getName(), + TO_PRODUCT_IMAGE.getValue(), "negative", null); } } @@ -993,7 +994,7 @@ public class GenerateServiceImpl extends ServiceImpl i String upgradeImageUrl = data.getBeanList("generated", String.class).get(0); String taskId = data.getStr("task_id"); - // 下载图片 + // 下载图片 freepik // byte[] bytes = downloadWithProxy(upgradeImageUrl); byte[] bytes = downloadVideoOrImage(upgradeImageUrl); // 2、上传图片到minio保存 @@ -1833,7 +1834,7 @@ public class GenerateServiceImpl extends ServiceImpl i poseTransformationMapper.updateById(poseTransformation); } - private byte[] downloadVideoOrImage(String url) { + public byte[] downloadVideoOrImage(String url) { try (CloseableHttpClient client = HttpClients.createDefault(); InputStream in = client.execute(new HttpGet(url)).getEntity().getContent()) { return IOUtils.toByteArray(in); @@ -1988,4 +1989,84 @@ public class GenerateServiceImpl extends ServiceImpl i } return null; // 未匹配到性别 } + + /** + * 接入flux模型,用于imageToSketch(sketch extract) || relighting || to product image + * @param func 功能枚举名 + * @param prompt 用户输入 + * @param imagePath 图片minio路径 + * @return 返回taskId,用于异步获取结果 + */ + public String flux(CreditsEventsEnum func, String prompt, String imagePath){ + String fluxRequestUrl = "https://api.bfl.ai/v1/flux-kontext-pro"; + if (StringUtil.isNullOrEmpty(prompt)){ + switch (func){ + case RELIGHT: + prompt = "a model standing on the beautiful beach, ultra high quality, 8k"; + break; + case IMAGE_TO_SKETCH: + prompt = "generate the sketch of the image, simple line, ultra high quality"; + break; + case TO_PRODUCT_IMAGE: + prompt = "change the image to real style, ultra high quality, 8k"; + break; + } + } + JSONObject requestBody = new JSONObject(); + + requestBody.set("prompt", prompt); + requestBody.set("seed", 42); +// requestBody.set("aspect_ratio", "9:16"); + requestBody.set("output_format", "png"); + + if (!StringUtil.isNullOrEmpty(imagePath)){ + try { + String imageAsBase64 = minioUtil.getImageAsBase64(imagePath); + requestBody.set("input_image", imageAsBase64); + } catch (IOException e) { + log.error("获取图片的base64格式失败,{}", String.valueOf(e)); + throw new BusinessException("Failed to obtain the image in base64 format."); + } + } + + String resp = sendRequestUtil.sendFluxPost(fluxRequestUrl, requestBody.toString()); + JSONObject respObj = JSONUtil.parseObj(resp); + log.info("flux 发起生成请求返回结果: {}", respObj); + if (StringUtil.isNullOrEmpty(respObj.getStr("id"))){ + return null; + } + return respObj.getStr("id"); + } + + public String getFluxResult(String taskId, Long accountId){ + String fluxResultRequestUrl = "https://api.bfl.ai/v1/get_result"; + HashMap params = new HashMap<>(); + params.put("id", taskId); + String resp = sendRequestUtil.sendGet(fluxResultRequestUrl, params); + log.info("获取flux生成的结果为:{}", resp); + JSONObject respObj = JSONUtil.parseObj(resp); + String status = respObj.getStr("status"); + switch (status){ + case "Task not found": + return "Failed"; + case "Pending": + case "Request Moderated": + case "Content Moderated": + // 处理中 + return "Pending"; + case "Ready": + // 已完成 获取结果 + String fluxResult = JSONUtil.parseObj(respObj.getStr("result")).getStr("sample"); + byte[] bytes = downloadVideoOrImage(fluxResult); + String objectName = accountId + "/product_image/" + taskId + ".png"; + minioUtil.uploadToMinio(bytes, userBucket, objectName, "image/png"); + +// return minioUtil.getPreSignedUrl(userBucket + "/" + objectName, CommonConstant.MINIO_IMAGE_EXPIRE_TIME); + return userBucket + "/" + objectName; + case "Error": + // 出错 + return "Failed"; + } + return null; + } } diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 0415fe05..8f0b03b7 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -440,9 +440,18 @@ public class UserLikeGroupServiceImpl extends ServiceImpl results = new ArrayList<>(); Set collect = new HashSet<>(); taskIdList.forEach(taskId -> { + // 查记录 + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(ToProductImageResult::getTaskId, taskId); + ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw); + if (Objects.isNull(toProductImageResult)) { + throw new BusinessException("The source image does not exist."); + } + // 判断当任务从哪个模型获取结果 + if (!StringUtil.isNullOrEmpty(toProductImageResult.getModelName()) && toProductImageResult.getModelName().equals("flux")){ + Project project = projectMapper.selectById(toProductImageResult.getProjectId()); + if (Objects.isNull(project)){ + throw new BusinessException("unknown project"); + } + String fluxResult = generateService.getFluxResult(taskId, project.getAccountId()); + if (StringUtil.isNullOrEmpty(fluxResult)){ + results.add(new MagicToolResultVO()); + } else if (fluxResult.equals("Failed") || fluxResult.equals("Pending")) { + results.add(new MagicToolResultVO(fluxResult)); + } else { + results.add(processFluxResult(fluxResult, toProductImageResult, taskId)); + } + return; + } + String key = toProductImageResultKey + ":" + taskId; MagicToolResultVO magicToolResultVO = new Gson().fromJson(redisUtil.getFromString(key), MagicToolResultVO.class); if (!Objects.isNull(magicToolResultVO) && !StringUtil.isNullOrEmpty(magicToolResultVO.getUrl())) { @@ -620,12 +662,6 @@ public class UserLikeGroupServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); - qw.lambda().eq(ToProductImageResult::getTaskId, taskId); - ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw); - if (Objects.isNull(toProductImageResult)) { - throw new BusinessException("The source image does not exist."); - } magicToolResultVO.setResultType(toProductImageResult.getResultType()); magicToolResultVO.setElementId(toProductImageResult.getElementId()); magicToolResultVO.setElementType(toProductImageResult.getElementType()); @@ -646,6 +682,31 @@ public class UserLikeGroupServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); @@ -894,9 +955,16 @@ public class UserLikeGroupServiceImpl extends ServiceImpl results = new ArrayList<>(); Set collect = new HashSet<>(); taskIdList.forEach(taskId -> { + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(ToProductImageResult::getTaskId, taskId); + ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw); + if (Objects.isNull(toProductImageResult)) { + throw new BusinessException("The source image does not exist."); + } + // 判断当任务从哪个模型获取结果 + if (!StringUtil.isNullOrEmpty(toProductImageResult.getModelName()) + && toProductImageResult.getModelName().equals("flux")){ + Project project = projectMapper.selectById(toProductImageResult.getProjectId()); + if (Objects.isNull(project)){ + throw new BusinessException("unknown project"); + } + String fluxResult = generateService.getFluxResult(taskId, project.getAccountId()); + + if (StringUtil.isNullOrEmpty(fluxResult)){ + results.add(new MagicToolResultVO()); + } else if (fluxResult.equals("Failed") || fluxResult.equals("Pending")) { + results.add(new MagicToolResultVO(fluxResult)); + } else { + results.add(processFluxResult(fluxResult, toProductImageResult, taskId)); + } + return; + } + String key = relightResultKey + ":" + taskId; MagicToolResultVO magicToolResultVO = new Gson().fromJson(redisUtil.getFromString(key), MagicToolResultVO.class); if (!Objects.isNull(magicToolResultVO) && !StringUtil.isNullOrEmpty(magicToolResultVO.getUrl())) { @@ -959,12 +1059,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); - qw.lambda().eq(ToProductImageResult::getTaskId, taskId); - ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(qw); - if (Objects.isNull(toProductImageResult)) { - throw new BusinessException("The source image does not exist."); - } + magicToolResultVO.setResultType(toProductImageResult.getResultType()); magicToolResultVO.setElementId(toProductImageResult.getElementId()); magicToolResultVO.setElementType(toProductImageResult.getElementType());