90 Commits

Author SHA1 Message Date
798c7b0592 Merge branch 'release/3.1' into dev/3.1_release_merge 2026-04-10 23:09:33 +08:00
9bd10581f4 BUGFIX:获取relight结果时删除了排序记录 2026-04-10 23:03:15 +08:00
1f288fe5e3 BUGFIX 2026-04-10 22:55:44 +08:00
72602eb245 BUGFIX 2026-04-10 22:51:00 +08:00
983d53268d DEBUG 2026-04-10 22:32:55 +08:00
f3aeeb3584 DEBUG 2026-04-10 22:21:56 +08:00
5d3692a204 BUGFIX:支付失败后的邮件通知类型错误(临时处理) 2026-04-08 13:52:38 +08:00
f2a074b2f6 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-03-31 15:19:56 +08:00
6a7a37dcec BUGFIX:只有Printboard时,首次design没有使用元素 2026-03-31 14:12:43 +08:00
litianxiang
c4d2780f0e TO DEV 2026-03-31 13:55:32 +08:00
litianxiang
1da6b7728c Merge remote-tracking branch 'origin/dev/3.1_release_merge' into release/3.1 2026-03-30 17:05:43 +08:00
litianxiang
0faf77899b fix:PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致导致积分扣除错误 2026-03-27 16:49:10 +08:00
litianxiang
e4940019bf 框选适配py 2026-03-27 15:19:38 +08:00
litianxiang
0da66ff210 print t2i模型替换 2026-03-27 15:16:33 +08:00
litianxiang
5dd862ff79 MOOD_BOARD high 去掉翻译 2026-03-26 16:13:43 +08:00
litianxiang
edaec9884d TO PROD 2026-03-25 22:28:44 +08:00
litianxiang
76eeb2be53 moodboard基础模型修改 2026-03-25 10:39:22 +08:00
litianxiang
cb6f94d2d4 py api fix 2026-03-25 10:19:06 +08:00
litianxiang
28656c44c8 FIX FLUX2 2026-03-24 16:24:43 +08:00
litianxiang
6757a89d04 Pattern模式参数fix 2026-03-24 15:54:53 +08:00
litianxiang
9be1a1e307 加锁解决不同线程读取前还未保存的问题 2026-03-24 15:49:16 +08:00
litianxiang
2168978f61 print pattern也改为flux2 2026-03-24 15:32:06 +08:00
litianxiang
54466b935d debug 2026-03-24 15:23:33 +08:00
litianxiang
c970ebe691 debug 2026-03-24 15:15:59 +08:00
litianxiang
1c5a3a12b9 debug 2026-03-24 15:04:40 +08:00
litianxiang
6e06000083 debug 2026-03-24 14:46:01 +08:00
litianxiang
dea2b3be42 debug 2026-03-24 14:29:08 +08:00
litianxiang
bcf51aea23 debug 2026-03-24 14:20:39 +08:00
litianxiang
0c9d5404c6 flux2失败状态判断 2026-03-24 14:05:27 +08:00
litianxiang
93429839c0 本地flux改为flux2 2026-03-24 13:39:38 +08:00
litianxiang
27859c3e28 Merge remote-tracking branch 'origin/release/3.1' into dev/3.1_release_merge 2026-03-23 14:11:33 +08:00
litianxiang
f02c0930a6 日志切面(controller层报错打印) 2026-03-23 13:56:47 +08:00
litianxiang
d57bb83b25 Merge remote-tracking branch 'origin/release/3.1' into release/3.1 2026-03-23 13:50:44 +08:00
731e34f133 TO DEV 2026-03-23 13:38:10 +08:00
75eca8d6ba Merge branch 'release/3.1' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2026-03-23 13:22:18 +08:00
3e53401f76 TASK:返回符合查询条件的金额总计 2026-03-23 11:55:07 +08:00
litianxiang
b6a068ebcd SKETCHBOARD传入的text改为获取第一个,为分割获取style的方式 2026-03-23 11:50:24 +08:00
litianxiang
dc291ea086 加入非空校验 2026-03-14 01:50:39 +08:00
litianxiang
2e846e671a romantic风格缺少下装fix 2026-03-13 10:06:26 +08:00
litianxiang
a5093311f9 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 19:06:54 +08:00
litianxiang
aed338a6d7 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:59:17 +08:00
litianxiang
8bdb49d25c 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:49:57 +08:00
litianxiang
5d53a8cd42 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:49:28 +08:00
litianxiang
61b7f3072f 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:36:21 +08:00
litianxiang
a1f489f3a1 比赛url修改 2026-03-12 17:39:05 +08:00
litianxiang
fc3fd877a8 transpose和rotate获取位置修改 2026-03-05 16:58:17 +08:00
litianxiang
fc72d2c430 transpose和rotate获取位置修改 2026-03-05 13:29:14 +08:00
litianxiang
1ac01dd090 测试token恢复 2026-02-25 16:36:06 +08:00
litianxiang
3bbdf7c672 fix:按编号导出参赛选手文件 2026-02-09 10:33:25 +08:00
litianxiang
0646484fba 按编号导出参赛选手文件 2026-02-09 10:21:40 +08:00
litianxiang
96b8613741 映射temp到服务器 2026-02-06 17:29:42 +08:00
litianxiang
cf30226a51 映射temp到服务器 2026-02-06 17:24:43 +08:00
litianxiang
3c15a3ff68 映射temp到服务器 2026-02-06 17:21:07 +08:00
litianxiang
0c904be227 测试临时token 2026-02-06 11:42:34 +08:00
litianxiang
7759b56123 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-02-05 17:39:15 +08:00
litianxiang
d5bfaa8822 fix:允许图生图不带提示词 2026-02-05 17:38:38 +08:00
967c0cbc01 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-05 16:55:24 +08:00
417e34b41a BUGFIX:1.首次design没有使用library和生成的印花2.design overall印花太小 2026-02-05 16:54:45 +08:00
litianxiang
d51aa84647 fix:参赛者根据链接返回文件参数 2026-02-05 09:41:10 +08:00
litianxiang
5895bc6ab6 Revert "fix:参赛者根据链接返回文件参数"
This reverts commit 3301869f20.
2026-02-05 09:40:35 +08:00
litianxiang
3301869f20 fix:参赛者根据链接返回文件参数 2026-02-05 09:40:15 +08:00
litianxiang
1ec42f4ad5 fix:参赛者id逻辑更改 2026-02-04 17:20:22 +08:00
cc506ff7e9 Merge branch 'dev/3.1_release_merge' into release/3.1 2026-02-04 17:05:59 +08:00
litianxiang
f2d43f06f4 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-02-04 15:28:08 +08:00
litianxiang
9251df49f8 比赛新增文件大小和视频时长 2026-02-04 15:27:51 +08:00
430156f4e8 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-04 14:48:38 +08:00
litianxiang
d1123aedcc fix:导出为页面下载 2026-02-04 14:45:11 +08:00
8c007077a3 BUGFIX: detail中的merge模式下没有存储partialDesign的图片 2026-02-04 14:43:29 +08:00
litianxiang
d63b4b4e63 fix:参赛选手加入编号 2026-02-04 14:03:30 +08:00
litianxiang
b826f0bf39 参赛选手加入编号,增加导出功能 2026-02-04 13:41:16 +08:00
litianxiang
1decd8e258 参赛选手加入编号,增加导出功能 2026-02-04 13:41:09 +08:00
litianxiang
1286e84488 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-02-04 13:21:19 +08:00
a252fdf7f9 BUGFIX: detail中的default模式报错 2026-02-03 16:56:15 +08:00
807d802178 TASK:motion 参数数据类型变更 2026-02-02 15:30:04 +08:00
53f1b548be CONFIG 2026-02-02 15:28:54 +08:00
45dd78032a BUGFIX: 1.token过期,重新登录无法解决 2.motion生成参数数据类型变更 2026-02-02 15:04:27 +08:00
c160da5132 BUGFIX: token过期,重新登录无法解决 2026-02-02 14:57:32 +08:00
b23faeeee2 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-02 13:32:55 +08:00
67789abca4 TASK:getAllPose id的数据类型改为整型 2026-02-02 13:32:27 +08:00
1c78d66aab Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-30 17:14:50 +08:00
528bc69923 BUGFIX: design single merge模式下取消传递print及elements等元素 2026-01-30 17:10:37 +08:00
litianxiang
22880d128d Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-01-30 15:40:25 +08:00
9c56a102cc Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-29 14:38:20 +08:00
2f59fe074f BUGFIX: 管理员修改用户身份为游客 2026-01-29 14:37:54 +08:00
9c61b1c8fe Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-29 10:12:47 +08:00
e30fdf7401 BUGFIX:模特上传,事务管理不统一导致library出现孤儿数据 2026-01-29 10:10:21 +08:00
ba2d10afbc paymentMethodConfiguration切换 2026-01-28 15:41:52 +08:00
6146112d04 TO PROD 2026-01-27 16:39:39 +08:00
412550df27 BUGFIX:管理员查design频次与chart中获取到的数量有区别 2026-01-27 14:59:39 +08:00
litianxiang
3e334d7956 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-01-26 11:16:46 +08:00
38 changed files with 1822 additions and 841 deletions

View File

@@ -99,6 +99,8 @@ jobs:
volumes:
# 数据挂载
- ./log:/log
- ./temp:/temp
- ./uploads:/temp/uploads
ports:
- '10090:5567'
restart: always

View File

@@ -427,6 +427,11 @@
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -28,6 +28,11 @@ public class MQPublisher {
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm);
}
public void sendGenerateResultMessage(String mm) {
log.info("send generate result message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerateResult(), mm);
}
/**
*
* @param mailParams 含有的字段

View File

@@ -0,0 +1,170 @@
package com.ai.da.common.aspect;
import com.ai.da.common.context.UserContext;
import com.ai.da.model.vo.AuthPrincipalVo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* Controller日志切面
* 记录所有Controller接口的请求参数和用户信息
*/
@Aspect
@Component
public class ControllerLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(ControllerLoggingAspect.class);
/**
* 定义切点所有Controller方法
*/
@Pointcut("execution(* com.ai.da.controller..*(..))")
public void controllerMethods() {
}
/**
* Controller方法执行前记录日志
*/
// @Before("controllerMethods()")
public void logControllerBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 获取当前用户ID
Long userId = null;
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId();
}
// 获取请求参数
Map<String, Object> params = getRequestParams(joinPoint, request);
logger.info("=== 请求开始 ===");
logger.info("用户ID: {}", userId);
logger.info("请求URL: {}", request.getRequestURL().toString());
logger.info("请求方法: {}", request.getMethod());
logger.info("请求IP: {}", getClientIpAddress(request));
logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
logger.info("请求参数: {}", params);
}
}
/**
* 获取请求参数
*/
private Map<String, Object> getRequestParams(JoinPoint joinPoint, HttpServletRequest request) {
Map<String, Object> params = new HashMap<>();
// 1. 获取Query String参数
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
params.put("queryString", queryString);
}
// 2. 获取方法参数(包含 @PathVariable, @RequestParam, @RequestBody 等)
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0) {
Map<String, Object> methodParams = new HashMap<>();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
// 过滤掉不可序列化的参数
if (arg != null) {
if (isIgnorable(arg)) {
// 对于可忽略的类型,记录类型名
methodParams.put("arg" + i, "[" + arg.getClass().getSimpleName() + "]");
} else {
try {
methodParams.put("arg" + i, arg);
} catch (Exception e) {
methodParams.put("arg" + i, arg.toString());
}
}
}
}
if (!methodParams.isEmpty()) {
params.put("methodParams", methodParams);
}
}
return params;
}
/**
* 判断是否需要过滤的参数类型
*/
private boolean isIgnorable(Object obj) {
return obj instanceof HttpServletRequest
|| obj instanceof HttpServletResponse
|| obj instanceof MultipartFile
|| obj instanceof MultipartFile[];
}
/**
* Controller方法抛出异常时记录日志
*/
@AfterThrowing(pointcut = "controllerMethods()", throwing = "exception")
public void logControllerAfterThrowing(JoinPoint joinPoint, Throwable exception) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Long userId = null;
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId();
}
// 获取请求参数
Map<String, Object> params = new HashMap<>();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
params = getRequestParams(joinPoint, request);
}
logger.error("=== 请求异常 ===");
logger.error("用户ID: {}", userId);
logger.error("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
logger.error("请求参数: {}", params);
logger.error("异常信息: ", exception);
logger.error("=== 异常结束 ===");
}
/**
* 获取客户端真实IP地址
*/
private String getClientIpAddress(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
return xForwardedFor.split(",")[0];
}
String xRealIp = request.getHeader("X-Real-IP");
if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
return xRealIp;
}
String proxyClientIp = request.getHeader("Proxy-Client-IP");
if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
return proxyClientIp;
}
String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
return wlProxyClientIp;
}
return request.getRemoteAddr();
}
}

View File

@@ -202,7 +202,7 @@ public class MyTaskScheduler {
}
}
// @Scheduled(cron = "0 0 9 * * ?")
// @Scheduled(cron = "0 0 9 * * ?")
public void sendTrialOrderExcelToManagements() {
// 获取前一天日期
LocalDate yesterday = LocalDate.now().minusDays(1);

View File

@@ -23,6 +23,7 @@ public class CommonConstant {
}
public static final String GENERATE_PATH = "/api/generate_image";
public static final String GENERATE_PATH_FLUX2_KLEIN = "/api/generate_image_flux2_klein";
public static final String GENERATE_SINGLE_LOGO = "/api/generate_single_logo";

View File

@@ -20,7 +20,7 @@ public class ModelConstants {
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
public static final String MOODBOARD_ADVANCED = "doubao-seedream-3-0-t2i-250415";
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
public static final String PRINTBOARD_HIGH_I2I = "doubao-seededit-3-0-i2i-250628";
public static final String PRINTBOARD_HIGH_I2I = "doubao-seedream-4-0-250828-fast";
public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";
public static final String NANO_BANANA = "gemini-2.5-flash-image";

View File

@@ -63,7 +63,8 @@ public class AuthenticationFilter extends OncePerRequestFilter {
//GlobalAwardController
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode"
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export",
"/api/global-award/contestants/export/files"
);
@Override

View File

@@ -34,7 +34,7 @@ public class AccountTask {
accountService.refreshCreditsMonthly();
}
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void getPaidUser() {
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
accountService.extendValidityForCC();

View File

@@ -45,7 +45,7 @@ public class PaymentTask {
@Resource
private PayPalCheckoutService payPalCheckoutService;
// @Scheduled(cron = "0/30 * * * * ?")
// @Scheduled(cron = "0/30 * * * * ?")
public void orderConfirmForPaypal() throws SerializeException {
// log.info("PayPal orderConfirm 被执行......");
@@ -97,7 +97,7 @@ public class PaymentTask {
//
}
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void updateAffiliateInfoWithPayment(){
// log.info("佣金计算定时器");
affiliateService.updateAffiliateInfoWithPayment();
@@ -109,7 +109,7 @@ public class PaymentTask {
affiliateService.syncLinkViewCountToDB();
}
// @Scheduled(cron = "0 0 8 28-31 * ?")
// @Scheduled(cron = "0 0 8 28-31 * ?")
public void commissionSummaryReminder(){
// 每个月末的最后一天的早上八点执行
LocalDate today = LocalDate.now();

View File

@@ -40,7 +40,7 @@ public class SubscriptionReminderTask {
REMINDER_DAYS_CONFIG.put("year", 14);
}
// @Scheduled(cron = "0 0 9 * * ?")
// @Scheduled(cron = "0 0 9 * * ?")
public void subscriptionReminder() {
// 获取所有需要通知的订阅
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
@@ -97,7 +97,7 @@ public class SubscriptionReminderTask {
return subscriptionInfoMapper.selectList(qw);
}
// @Scheduled(cron = "0 0 9 * * ?")
// @Scheduled(cron = "0 0 9 * * ?")
public void trialReminder() {
// 今天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -163,6 +164,24 @@ public class GlobalAwardController {
return Response.success(globalAwardService.checkCode(email, code));
}
@GetMapping("/contestants/export")
@ApiOperation(value = "导出参赛者列表为Excel", notes = "导出所有参赛者信息为xlsx并触发下载")
public void exportContestants(HttpServletResponse response) throws Exception {
byte[] data = globalAwardService.exportContestants();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"contestants.xlsx\"");
response.setContentLength(data.length);
response.getOutputStream().write(data);
response.getOutputStream().flush();
}
@PostMapping("/contestants/export/files")
@ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录")
public Response<Integer> exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception {
int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber());
return Response.success(exportedCount);
}
}

View File

@@ -19,7 +19,7 @@ public interface DesignMapper extends CommonMapper<Design> {
Long insertDesign(Design design);
List<UserDesignStatisticDTO> getDesignStatistic(String startTime, String endTime, List<Long> ids, String email,
String role, String organizationName);
String role, String organizationName, boolean filterBySecond);
List<Design> selectDeleteList();
}

View File

@@ -26,6 +26,9 @@ public class Contestant {
private String email;
@TableField("contestant_number")
private Integer contestantNumber;
@TableField("first_name")
private String firstName;
@@ -56,6 +59,15 @@ public class Contestant {
@TableField("video_path")
private String videoPath;
@TableField("video_duration")
private Integer videoDuration;
@TableField("video_size")
private Long videoSize;
@TableField("pdf_size")
private Long pdfSize;
@TableField("created_at")
private LocalDateTime createdAt;

View File

@@ -49,6 +49,15 @@ public class ContestantDTO {
@ApiModelProperty(value = "视频文件路径", required = false, example = "contestants/user@example.com/2024/01/video_1234567890.mp4")
private String videoPath;
@ApiModelProperty(value = "视频时长(秒)", required = false, example = "120")
private Integer videoDuration;
@ApiModelProperty(value = "视频大小(字节)", required = false, example = "10485760")
private Long videoSize;
@ApiModelProperty(value = "PDF 文件大小(字节)", required = false, example = "524288")
private Long pdfSize;
// /**
// * 是否确认覆盖已存在记录false 表示发现已有记录时仅返回 existingRecord不覆盖
@@ -58,6 +67,8 @@ public class ContestantDTO {
@NotBlank
private String secureToken;
}

View File

@@ -0,0 +1,19 @@
package com.ai.da.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 参赛者文件导出请求DTO
*/
@Data
@ApiModel(value = "参赛者文件导出请求", description = "用于导出指定范围的参赛者文件")
public class ContestantExportRequest {
@ApiModelProperty(value = "最小参赛者编号", required = true, example = "10000")
private Integer minContestantNumber;
@ApiModelProperty(value = "最大参赛者编号", required = true, example = "10010")
private Integer maxContestantNumber;
}

View File

@@ -0,0 +1,55 @@
package com.ai.da.model.dto;
import lombok.Builder;
import lombok.Data;
import java.util.List;
/**
* 图片处理请求体
*/
@Data
@Builder
public class ImageProcessRequest {
/**
* OSS桶名bucket_name
*/
private String bucket_name;
/**
* OSS对象名object_name
*/
private String object_name;
/**
* 输入图片路径列表input_image_paths
*/
private List<String> input_image_paths;
/**
* 图像宽度width
*/
private Integer width;
/**
* 图像高度height
*/
private Integer height;
/**
* 文本提示prompt
*/
private String prompt;
/**
* 推理步数steps
*/
private Integer steps;
/**
* 引导系数guidance
*/
private Double guidance;
}

View File

@@ -2,8 +2,10 @@ package com.ai.da.python;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.ai.da.common.RabbitMQ.RabbitMQProperties;
import com.ai.da.common.config.FileProperties;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.*;
import com.ai.da.common.utils.*;
@@ -20,6 +22,7 @@ import com.ai.da.model.vo.*;
import com.ai.da.python.vo.*;
import com.ai.da.service.DesignHistoryService;
import com.ai.da.service.PythonTAllInfoService;
import com.ai.da.service.RabbitMQService;
import com.ai.da.service.SysFileService;
import com.alibaba.fastjson.*;
import com.alibaba.fastjson.serializer.SerializerFeature;
@@ -39,6 +42,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -68,6 +72,8 @@ public class PythonService {
private String accessPythonPort;
@Value("${minio.bucketName.gradient}")
private String gradientBucketName;
@Value("${minio.bucketName.users}")
private String userBucketName;
@Value("${access.python.generate_sr_port}")
private String srServicePort;
@@ -83,6 +89,12 @@ public class PythonService {
@Resource
private RedisUtil redisUtil;
@Resource
private RabbitMQService rabbitMQService;
@Resource
private RabbitMQProperties rabbitMQProperties;
/**
* 生成打印的图片 二合一 (废弃于2024/01/02)
*
@@ -279,7 +291,7 @@ public class PythonService {
if (isDuplicate) {
elementVO.setHasUseMd5List(beforeAssemblyHasUseMd5List);
i --;
i--;
switch (designPrintPictureType) {
case PIN:
@@ -406,13 +418,14 @@ public class PythonService {
// if (CollectionUtil.isEmpty(pinData)) {
// return 0;
// }
//// long topNum = sketchBoardElements.stream()
//// .filter(skecth -> skecth.getHasPin() == 1
//// && DesignPythonItem.OUTWEAR_DRESS_BLOUSE.contains(skecth.getLevel2Type())).count();
//// long bottomNum = sketchBoardElements.stream()
//// .filter(skecth -> skecth.getHasPin() == 1
//// && DesignPythonItem.SKIRT_TROUSERS.contains(skecth.getLevel2Type())).count();
//// int num = Arrays.asList(topNum, bottomNum).stream().max(Comparator.comparing(Long::valueOf)).get().intValue();
/// / long topNum = sketchBoardElements.stream()
/// / .filter(skecth -> skecth.getHasPin() == 1
/// / && DesignPythonItem.OUTWEAR_DRESS_BLOUSE.contains(skecth.getLevel2Type())).count();
/// / long bottomNum = sketchBoardElements.stream()
/// / .filter(skecth -> skecth.getHasPin() == 1
/// / && DesignPythonItem.SKIRT_TROUSERS.contains(skecth.getLevel2Type())).count();
/// / int num = Arrays.asList(topNum, bottomNum).stream().max(Comparator.comparing(Long::valueOf)).get().intValue();
// int num = pinData.size();
// return Math.min(num, 8);
// }
@@ -560,12 +573,12 @@ public class PythonService {
return 0;
} else {
long pinNum = printBoardElements.stream().filter(f -> f.getHasPin() == 1).count();
if (designNum - pinNum < 0){
return RandomsUtil.randomSysFile(0L, (long) (pinNum/2 + 1));
} else if (designNum - pinNum < designNum/2) {
if (designNum - pinNum < 0) {
return RandomsUtil.randomSysFile(0L, (long) (pinNum / 2 + 1));
} else if (designNum - pinNum < designNum / 2) {
return RandomsUtil.randomSysFile(0L, designNum - pinNum + 1);
} else {
return RandomsUtil.randomSysFile(0L, (long) (designNum/2 + 1));
return RandomsUtil.randomSysFile(0L, (long) (designNum / 2 + 1));
}
}
}
@@ -680,8 +693,7 @@ public class PythonService {
// 其他所有情况,都回退到使用系统推荐
String categoryParam = elementVO.getModelSex().toLowerCase() + "_" + styleCategory.toLowerCase();
List<String> recommentdUrlList = getSystemSketchByCategory(categoryParam, elementVO.getBrandId(), elementVO.getBrandScale(),elementVO.getStyle());
List<String> recommentdUrlList = getSystemSketchByCategory(categoryParam, elementVO.getBrandId(), elementVO.getBrandScale(), elementVO.getStyle());
if (CollectionUtils.isEmpty(recommentdUrlList)) {
throw new BusinessException("failed.to.obtain.system.sketch.recommendation");
}
@@ -1039,7 +1051,7 @@ public class PythonService {
if (!CollectionUtils.isEmpty(recommentdUrlList)) {
String recommendSystemSketch = recommentdUrlList.get(0);
return coverSystemSketchUrlToDesignPythonItem(recommendSystemSketch, category, validateElementVO);
}else {
} else {
throw new BusinessException("failed.to.obtain.system.sketch.recommendation");
}
// JSONObject attributeRecognition = getAttributeRecognitionBySameCategory(element, validateElementVO.getModelSex());
@@ -1062,7 +1074,7 @@ public class PythonService {
if (!CollectionUtils.isEmpty(recommentdUrlList)) {
String recommendSystemSketch = recommentdUrlList.get(0);
return coverSystemSketchUrlToDesignPythonItem(recommendSystemSketch, category, validateElementVO);
}else {
} else {
throw new BusinessException("failed.to.obtain.system.sketch.recommendation");
}
@@ -1098,7 +1110,7 @@ public class PythonService {
if (!CollectionUtils.isEmpty(recommentdUrlList)) {
String recommendSystemSketch = recommentdUrlList.get(0);
return coverSystemSketchUrlToDesignPythonItem(recommendSystemSketch, category, validateElementVO);
}else {
} else {
throw new BusinessException("failed.to.obtain.system.sketch.recommendation");
}
// JSONObject attributeRecognition = getAttributeRecognitionBySameCategory(element, validateElementVO.getModelSex());
@@ -1122,7 +1134,7 @@ public class PythonService {
if (!CollectionUtils.isEmpty(recommentdUrlList)) {
String recommendSystemSketch = recommentdUrlList.get(0);
return coverSystemSketchUrlToDesignPythonItem(recommendSystemSketch, category, validateElementVO);
}else {
} else {
throw new BusinessException("failed.to.obtain.system.sketch.recommendation");
}
// String tableName = getTableName(validateElementVO.getModelSex(), category);
@@ -2190,7 +2202,7 @@ public class PythonService {
basic.setScale_earrings(0.16);
if (Objects.nonNull(designLibraryModelPointVO)) {
basic.setBody_point_test(getMap(designLibraryModelPointVO));
}else {
} else {
basic.setBody_point_test(getMap(designLibraryModelPoint));
}
return basic;
@@ -2851,13 +2863,17 @@ public class PythonService {
gradientString = JSONObject.toJSONString(designSingleItem.getGradient());
}
PrintToPython printToPython = resolveDesignSinglePrint(designSingleItem.getPrintObject().getPrints(),
PrintToPython printToPython;
printToPython = resolveDesignSinglePrint(designSingleItem.getPrintObject().getPrints(),
designSingleItem.getPartialDesign().getPartialDesignMinioPath());
resolveDesignElement(designSingleItem.getTrims(), printToPython);
log.info("组装参数【服装:{}的maskUrl: {}】",designSingleItem.getType(), designSingleItem.getMaskUrl());
/*PrintToPython printToPython = resolveDesignSinglePrint(designSingleItem.getPrintObject().getPrints(),
designSingleItem.getPartialDesign().getPartialDesignMinioPath());*/
// resolveDesignElement(designSingleItem.getTrims(), printToPython);
log.info("组装参数【服装:{}的maskUrl: {}】", designSingleItem.getType(), designSingleItem.getMaskUrl());
String mergeImagePath = !StringUtil.isNullOrEmpty(printToPython.getPartial())
? printToPython.getPartial() : designSingleItem.getPath();
String partialDesign = designSingleItem.getPartialDesign().getPartialDesignMinioPath();
String mergeImagePath = !StringUtil.isNullOrEmpty(partialDesign)
? partialDesign : designSingleItem.getPath();
response.add(new DesignPythonItem(
designSingleItem.getType(),
designSingleItem.getPath(),
@@ -2880,7 +2896,7 @@ public class PythonService {
});
if (singleOverall.equals("overall")){
if (singleOverall.equals("overall")) {
String bodyPath;
if (Objects.nonNull(designLibraryModelPoint)) {
bodyPath = designLibraryModelPoint.getTemplateUrl();
@@ -2896,12 +2912,12 @@ public class PythonService {
private PrintToPython resolveDesignSinglePrint(List<DesignSinglePrint> printObject, String partialDesign) {
PrintToPython printToPython = new PrintToPython();
DesignPythonItemPrint printSingle = new DesignPythonItemPrint();
// DesignPythonItemPrint printSingle = new DesignPythonItemPrint();
DesignPythonItemPrint printOverall = new DesignPythonItemPrint();
printToPython.setSingle(printSingle);
// printToPython.setSingle(printSingle);
printToPython.setOverall(printOverall);
printToPython.setPartial(StringUtil.isNullOrEmpty(partialDesign) ? null : partialDesign);
if (Objects.isNull(printObject) || printObject.isEmpty()){
if (Objects.isNull(printObject) || printObject.isEmpty()) {
return printToPython;
}
@@ -2932,12 +2948,12 @@ public class PythonService {
Integer priority = p.getPriority();
setUriToMinioPath(p);
// todo 下标越界问题
if (p.getIfSingle()){
if (p.getIfSingle()) {
locationS.set(priority - 1, p.getLocation());
scaleS.set(priority - 1, p.getScale());
angleS.set( priority - 1, p.getAngle());
angleS.set(priority - 1, p.getAngle());
pathsS.set(priority - 1, p.getMinIOPath());
}else {
} else {
locationO.set(priority - 1, p.getLocation());
scaleO.set(priority - 1, p.getScale());
angleO.set(priority - 1, p.getAngle());
@@ -2945,14 +2961,14 @@ public class PythonService {
}
// log.info("本次print打点locations###{}###fileVO{}", p.getLocation(), JSON.toJSONString(fileVO));
});
locationS.removeAll(Collections.singleton(null));
/*locationS.removeAll(Collections.singleton(null));
scaleS.removeAll(Collections.singleton(null));
angleS.removeAll(Collections.singleton(null));
pathsS.removeAll(Collections.singleton(null));
printSingle.setLocation(locationS);
printSingle.setPrint_scale_list(scaleS);
printSingle.setPrint_angle_list(angleS);
printSingle.setPrint_path_list(pathsS);
printSingle.setPrint_path_list(pathsS);*/
locationO.removeAll(Collections.singleton(null));
scaleO.removeAll(Collections.singleton(null));
@@ -2967,9 +2983,9 @@ public class PythonService {
}
// 对印花类型为Generate的图片路径进行特殊处理
private void setUriToMinioPath(DesignSinglePrint print){
if (!StringUtil.isNullOrEmpty(print.getDesignType()) && print.getDesignType().equals("Generate")){
if (!StringUtil.isNullOrEmpty(print.getPath())){
private void setUriToMinioPath(DesignSinglePrint print) {
if (!StringUtil.isNullOrEmpty(print.getDesignType()) && print.getDesignType().equals("Generate")) {
if (!StringUtil.isNullOrEmpty(print.getPath())) {
try {
URI uri = new URI(print.getPath());
String path = uri.getPath(); // 获取路径部分: /aida-users/87/print/9ac32f65-6043-424d-a146-92c9c6d204ee-4-87.png
@@ -3329,7 +3345,7 @@ public class PythonService {
throw new BusinessException("system error!");
}
public Boolean generateSketchOrPrint(String params, String port, String servicePath) {
public Boolean generateSketchOrPrint(String params, String port, String servicePath, String taskId) {
//限流校验
// AccessLimitUtils.validate("generateSketchOrPrint", 5);
OkHttpClient client = new OkHttpClient().newBuilder()
@@ -3391,12 +3407,36 @@ public class PythonService {
if (result && jsonObject.get("code").equals(200)) {
log.info("Generate##responseObject###{}", jsonObject);
// return setGenerateImageList(jsonObject.getJSONObject("data"));
if (servicePath == CommonConstant.GENERATE_PATH_FLUX2_KLEIN) {
//放入结果到mq
JSONObject data = jsonObject.getJSONObject("data");
String outputPath = data.getString("output_path");
Map<String, String> mqMessage = new HashMap<>();
mqMessage.put("tasks_id", taskId);
mqMessage.put("status", "SUCCESS");
mqMessage.put("message", "success");
mqMessage.put("image_url", outputPath);
mqMessage.put("category", "");
String mqMessageBody = JSON.toJSONString(mqMessage);
rabbitMQService.publishMessageToGenerateResult(mqMessageBody);
}
return Boolean.TRUE;
} else {
log.info("generateSketchOrPrintPrint失败###{}", jsonObject);
log.info("Generate Exception! Code : " + jsonObject.get("code"));
Map<String, String> mqMessage = new HashMap<>();
mqMessage.put("tasks_id", taskId);
mqMessage.put("status", "ERROR");
mqMessage.put("message", "");
mqMessage.put("image_url", "");
mqMessage.put("category", "");
String mqMessageBody = JSON.toJSONString(mqMessage);
rabbitMQService.publishMessageToGenerateResult(mqMessageBody);
return Boolean.FALSE;
}
}
public Response sendPostToModel(String content, String portAndRoute, String functionName) {
@@ -3438,7 +3478,10 @@ public class PythonService {
return imageUrlList;
}*/
/** 废弃状态 */
/**
* 废弃状态
*/
public String composeLayers(List<OutfitDetailPythonItem> layersDetail) {
HashMap<String, List<OutfitDetailPythonItem>> layers = new HashMap<>();
HashMap<String, HashMap<String, List<OutfitDetailPythonItem>>> content = new HashMap<>();
@@ -3749,7 +3792,7 @@ public class PythonService {
throw new BusinessException("relightImage.interface.exception");
}
public String imageToSketch(String imagePath, String bucket, String objectName, String styleCode, String styleImageUrl){
public String imageToSketch(String imagePath, String bucket, String objectName, String styleCode, String styleImageUrl) {
OkHttpClient client = new OkHttpClient().newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
.pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒)
@@ -3796,7 +3839,7 @@ public class PythonService {
String sketchResult = jsonObject.get("data").toString();
log.info("ImageToSketch 结果 {}", sketchResult);
return sketchResult;
}else {
} else {
log.info("ImageToSketch 失败。 Response code {}", responseCode);
throw new BusinessException("ImageToSketch 失败。 Response code " + responseCode);
}
@@ -3849,7 +3892,7 @@ public class PythonService {
throw new BusinessException("bright.interface.exception");
}
public JSONObject attributeRecognition(List<String> pictureUrls,List<String> ids, List<String> category) {
public JSONObject attributeRecognition(List<String> pictureUrls, List<String> ids, List<String> category) {
//限流校验
AccessLimitUtils.validate("attributeRecognition", 20);
OkHttpClient client = new OkHttpClient().newBuilder()
@@ -3881,7 +3924,7 @@ public class PythonService {
} catch (IOException ioException) {
log.error("PythonService###attributeRecognition异常##{}", ExceptionUtil.getThrowableList(ioException));
}
log.info("识别python对应的属性标签值结果###{}",bodyStr.trim());
log.info("识别python对应的属性标签值结果###{}", bodyStr.trim());
//去除限流
AccessLimitUtils.validateOut("attributeRecognition");
if (Objects.isNull(response)) {
@@ -3965,7 +4008,7 @@ public class PythonService {
throw new BusinessException("design.interface.exception");
}
public List<String> getSystemSketchByCategory(String category, Long brandId, Double brandScale,String style) {
public List<String> getSystemSketchByCategory(String category, Long brandId, Double brandScale, String style) {
//******3.1.2版本临时使用java推荐方案去解决style未使用的问题**********
// try {
// //使用新库attribute_retrieval_style表命名修改为elementVO.getModelSex().toLowerCase() + "_" + styleCategory.toLowerCase()比如female_skirt,与传入的category保持一致
@@ -3989,6 +4032,14 @@ public class PythonService {
// throw new BusinessException("system.error");
// }
//**********************end***********************************
//临时补丁
if (category != null && style != null) {
String categoryPrefix = category.split("_")[0];
if ("male".equals(categoryPrefix) &&
(style.equalsIgnoreCase("lolita") || style.equalsIgnoreCase("romantic"))) {
style = null;
}
}
AuthPrincipalVo userHolder = UserContext.getUserHolder();
OkHttpClient client = new OkHttpClient().newBuilder()
@@ -4110,6 +4161,7 @@ public class PythonService {
//生成失败
throw new BusinessException("segProduct.interface.exception");
}
/**
* 转发 seg_anything 请求到 python 服务
* 请求 body 由调用方组装(包含 user_id, image_path, type, points, labels, box 等)
@@ -4122,6 +4174,9 @@ public class PythonService {
.writeTimeout(60, TimeUnit.SECONDS)
.build();
MediaType mediaType = MediaType.parse("application/json");
content.put("bucket", userBucketName);
content.put("object_name", content.get("user_id") + "/" + "segment" + "/" + UUID.randomUUID() + ".png");
content.remove("user_id");
RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content));
String url = accessPythonIp + ":" + accessPythonPort + "/api/seg_anything";
@@ -4152,18 +4207,18 @@ public class PythonService {
if (responseObject != null) {
JSONObject dataObj = responseObject.getJSONObject("data");
if (dataObj != null) {
String output = dataObj.getString("output");
if (!StringUtil.isNullOrEmpty(output)) {
try {
String presigned = minioUtil.getPreSignedUrl(output, 24 * 60);
return presigned;
} catch (Exception e) {
log.error("Failed to generate presigned url for {}: {}", output, e.getMessage());
throw new BusinessException("segAnything.presign.failed");
}
String output = dataObj.getString("output");
if (!StringUtil.isNullOrEmpty(output)) {
try {
String presigned = minioUtil.getPreSignedUrl(output, 24 * 60);
return presigned;
} catch (Exception e) {
log.error("Failed to generate presigned url for {}: {}", output, e.getMessage());
throw new BusinessException("segAnything.presign.failed");
}
}
}
}
} catch (Exception ex) {
log.error("PythonService##segAnything post-process error###{}", ex.getMessage());
@@ -4173,7 +4228,7 @@ public class PythonService {
throw new BusinessException("segAnything.missing.output");
}
throw new BusinessException("segAnything.interface.exception");
} catch (IOException |JSONException e) {
} catch (IOException | JSONException e) {
log.error("PythonService##segAnything异常###{}", e.getMessage());
throw new BusinessException("segAnything.interface.exception");
}
@@ -4181,6 +4236,7 @@ public class PythonService {
log.error("PythonService##segAnything异常response###{}", response);
throw new BusinessException("segAnything.interface.exception");
}
public Boolean poseTransformation(JSONObject content, String apiUri) {
OkHttpClient client = new OkHttpClient().newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
@@ -4284,7 +4340,7 @@ public class PythonService {
String modifiedModel = jsonObject.get("data").toString();
log.info("modifyModelProportion 结果 {}", modifiedModel);
return modifiedModel;
}else {
} else {
log.info("modifyModelProportion 失败。 Response code {}", responseCode);
throw new BusinessException("modifyModelProportion 失败。 Response code " + responseCode);
}
@@ -4387,10 +4443,11 @@ public class PythonService {
log.info("imageSegmentation 结果 {}", jsonObject.get("data").toString());
List<ImageSegmentation.ImageDate> seg = JSONObject.parseObject(
jsonObject.get("data").toString(),
new TypeReference<List<ImageSegmentation.ImageDate>>() {}
new TypeReference<List<ImageSegmentation.ImageDate>>() {
}
);
return seg;
}else {
} else {
log.info("imageSegmentation 失败。 Response code {}", responseCode);
throw new BusinessException("imageSegmentation 失败。 Response code " + responseCode);
}

View File

@@ -1,13 +1,13 @@
package com.ai.da.python.vo;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.Data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Data
public class DesignPythonItemPrint {
@@ -53,7 +53,7 @@ public class DesignPythonItemPrint {
if (ifDesign){
this.print_path_list = print_path_list;
this.location = Collections.singletonList(Arrays.asList(0.0f, 0.0f));
this.print_scale_list = Collections.singletonList(Arrays.asList(0.0f, 0.0f));
this.print_scale_list = Collections.singletonList(Arrays.asList(1.0f, 1.0f));
this.print_angle_list = Arrays.asList(0.0, 0.0);
}

View File

@@ -20,6 +20,25 @@ public interface GlobalAwardService {
CheckOTPVO checkCode(String email, String otp);
void checkSecurityToken(String email, String securityToken);
/**
* 导出参赛者列表为 Excel二进制
* @return Excel 文件的字节数组
*/
byte[] exportContestants() throws Exception;
/**
* 将参赛者列表导出并保存到服务端本地目录(使用服务配置的 uploadDir/exports
*/
void saveContestantsToLocal() throws Exception;
/**
* 根据参赛者编号范围导出参赛者文件到本地目录
* @param minContestantNumber 最小参赛者编号
* @param maxContestantNumber 最大参赛者编号
* @return 导出的参赛者数量
*/
int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception;
}

View File

@@ -7,6 +7,8 @@ public interface RabbitMQService {
void publishMessageToGenerate(String message);
void publishMessageToGenerateResult(String message);
void publishMessageToSR(String message);
Integer getMessageCount(String queueUrl);

View File

@@ -244,12 +244,13 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
response.setEmail(account.getUserEmail());
String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId()));
if (StringUtils.isNotBlank(token)) {
/*if (StringUtils.isNotBlank(token)) {
//用户已登入
response.setToken(token);
} else {
response.setToken(createAccountToken(account));
}
}*/
response.setToken(createAccountToken(account));
response.setUserId(account.getId());
response.setSystemUser(account.getSystemUser());
// 设置头像

View File

@@ -520,14 +520,16 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
.filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName()))
.map(DesignCollectionPrintElementDTO::getId)
.collect(Collectors.toList());
List<CollectionElement> printBoardElements = new ArrayList<>();
elementVO.setPrintBoardElements(printBoardElements);
if (!CollectionUtils.isEmpty(printBoardIds)) {
// 从数据库批量查询printBoard元素
List<CollectionElement> printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds);
printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds);
// 验证查询结果的完整性
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
throw new BusinessException("get.printBoards.data.is.mismatch");
}
elementVO.setPrintBoardElements(printBoardElements);
// elementVO.setPrintBoardElements(printBoardElements);
usedElementIds.addAll(printBoardIds); // 记录已使用的元素ID
}
// 处理类型为LIBRARY的printBoard元素
@@ -543,7 +545,8 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
Map<Long, DesignCollectionPrintElementDTO> idToMap = designDTO.getPrintBoards()
.stream()
.collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v));
libraryCollectionElements.addAll(covertLibrarysToPrintCollections(librarys, idToMap));
printBoardElements.addAll(covertLibrarysToPrintCollections(librarys, idToMap));
// libraryCollectionElements.addAll(covertLibrarysToPrintCollections(librarys, idToMap));
}
}
@@ -559,7 +562,8 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
Map<Long, DesignCollectionPrintElementDTO> idToMap = designDTO.getPrintBoards()
.stream()
.collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v));
generateCollectionElements.addAll(covertGeneratesToPrintCollections(generateDetailList, idToMap));
printBoardElements.addAll(covertGeneratesToPrintCollections(generateDetailList, idToMap));
// generateCollectionElements.addAll(covertGeneratesToPrintCollections(generateDetailList, idToMap));
}
}
}

View File

@@ -33,7 +33,6 @@ import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -149,7 +148,17 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
|| ADMIN_IDS.contains(account.getId())
|| ADMIN_IDS_READ_ONLY.contains(account.getId())
)) {
if (StringUtil.isNullOrEmpty(startTime)) startTime = "2024-02-01 00:00:00";
boolean filterBySecond ;
if (StringUtil.isNullOrEmpty(startTime)) {
startTime = "2024-02-01 00:00:00";
filterBySecond = true;
} else {
LocalDateTime thresholdTime = LocalDateTime.of(2024, 5, 1, 0, 0, 0);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime startDateTime = LocalDateTime.parse(startTime, formatter);
filterBySecond = startDateTime.isBefore(thresholdTime);
}
if (StringUtil.isNullOrEmpty(endTime)) {
// yyyy-MM-dd HH:mm:ss "HH"表示24小时制 "hh"表示12小时制
endTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
@@ -173,7 +182,7 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
default:
throw new BusinessException("have.no.permission", ResultEnum.PROMPT.getCode());
}
return designMapper.getDesignStatistic(startTime, endTime, ids, email, role, account.getOrganizationName());
return designMapper.getDesignStatistic(startTime, endTime, ids, email, role, account.getOrganizationName(), filterBySecond);
} else {
throw new BusinessException("have.no.permission", ResultEnum.PROMPT.getCode());
}
@@ -695,14 +704,19 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
String username = UserContext.getUserHolder().getUsername();
Account account = new Account();
account.setId(accountId);
// 修改用户有效期截止日期、用户类型、积分
if (!Objects.isNull(validEndTime)) {
account.setValidEndTime(validEndTime);
log.info("管理员:{},修改用户 {} 信息,将账号到期时间置为:{}", username, accountId, validEndTime);
}
if (!Objects.isNull(systemUser)) {
if (!Objects.isNull(systemUser) && !systemUser.equals(0)) {
account.setSystemUser(systemUser);
log.info("管理员:{},修改用户 {} 信息,将账号身份置为:{}", username, accountId, systemUser);
} else if (systemUser.equals(0)){
// 将用户身份设置为游客
accountService.toVisitor(account);
return true;
}
/*if (!StringUtils.isNullOrEmpty(systemUser)) {
int systemUser = 0;
@@ -728,7 +742,6 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
}
// todo 如果修改管理员账号的积分上限或子账号数量,则其所有子账号的积分上限需要重新计算
account.setId(accountId);
account.setUpdateDate(new Date());
return accountMapper.updateById(account) == 1;
// accountService.update(account,null);
@@ -857,19 +870,20 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
if (!StringUtil.isNullOrEmpty(queryPaymentInfoDTO.getOrder()) && queryPaymentInfoDTO.getOrder().equals("ASC")) {
order = "ASC";
}
String status = StringUtil.isNullOrEmpty(queryPaymentInfoDTO.getStatus()) ? "Success" : queryPaymentInfoDTO.getStatus();
List<PaymentInfoVO> paymentInfoVOS = paymentInfoMapper.queryPaymentInfo(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(),
queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(),
queryPaymentInfoDTO.getType(), status,
queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(),
queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(),
size, offset, order, queryPaymentInfoDTO.getPayer());
// 查询数据总量
Long total = paymentInfoMapper.queryPaymentInfoCount(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(),
queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(),
queryPaymentInfoDTO.getType(), status,
queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(),
queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), queryPaymentInfoDTO.getPayer());
// 查询符合查询条件的总金额
BigDecimal payerTotal = paymentInfoMapper.queryTotalPaymentAmount(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(),
queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(),
queryPaymentInfoDTO.getType(), status,
queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(),
queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), queryPaymentInfoDTO.getPayer());
// 总页数

View File

@@ -497,6 +497,10 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
.collect(Collectors.toMap(DesignSingleItemDTO::getPriority, DesignSingleItemDTO::getOffset));
}
// 创建 priority 到 DesignSingleItemDTO 的映射,用于获取 transpose 和 rotate
Map<Integer, DesignSingleItemDTO> priorityToItemDTOMap = designSingleItemDTOList.stream()
.collect(Collectors.toMap(DesignSingleItemDTO::getPriority, dto -> dto, (old, newVal) -> old));
List<TDesignPythonOutfitDetail> list = new ArrayList<>();
for (int i = 0; i < layers.size(); i++) {
JSONObject jsonObject = layers.getJSONObject(i);
@@ -525,8 +529,12 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
designPythonOutfitDetail.setOffset(String.valueOf(priorityOffset.get(Math.abs(priority))));
}
designPythonOutfitDetail.setPriority(priority);
designPythonOutfitDetail.setTranspose(jsonObject.getString("transpose"));
designPythonOutfitDetail.setRotate(jsonObject.getDouble("rotate"));
// 从前端传入的 DesignSingleItemDTO 中获取 transpose 和 rotate不再从 Python 返回的数据获取
DesignSingleItemDTO itemDTO = priorityToItemDTOMap.get(Math.abs(priority));
if (itemDTO != null) {
designPythonOutfitDetail.setTranspose(itemDTO.getTranspose() != null ? Arrays.toString(itemDTO.getTranspose()) : null);
designPythonOutfitDetail.setRotate(itemDTO.getRotate());
}
list.add(designPythonOutfitDetail);
}
@@ -1036,7 +1044,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
@Override
public Map<String, List<String>> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO) {
String designType = "default";
String designType = "default";
if (Objects.nonNull(designSingleIncludeLayersDTO)) {
designType = designSingleIncludeLayersDTO.getDesignType();
}

View File

@@ -46,6 +46,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
@@ -763,7 +764,20 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
getPrintboardLevel2TypeQw.lambda().orderByDesc(CollectionElement::getCreateDate);
getPrintboardLevel2TypeQw.last("limit 1");
CollectionElement one = collectionElementService.getOne(getPrintboardLevel2TypeQw);
print.setLevel2Type(one.getLevel2Type());
if (Objects.isNull(one)) {
QueryWrapper<Library> libraryQueryWrapper = new QueryWrapper<>();
libraryQueryWrapper.lambda().eq(Library::getUrl, print.getPath());
libraryQueryWrapper.lambda().orderByDesc(Library::getCreateDate);
getPrintboardLevel2TypeQw.last("limit 1");
Library library = libraryService.getOne(libraryQueryWrapper);
if (Objects.isNull(library)) {
print.setLevel2Type("Pattern");
} else {
print.setLevel2Type(library.getLevel2Type());
}
} else {
print.setLevel2Type(one.getLevel2Type());
}
print.setCreateDate(LocalDateTime.now());
designItemDetailPrintService.save(print);
}
@@ -1669,6 +1683,24 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
.lt("create_date", endTime)
.select("count(id) as count");
// 如果startTime早于2024-05-01 00:00:00添加额外的筛选条件
LocalDateTime thresholdTime = LocalDateTime.of(2024, 5, 1, 0, 0, 0);
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime startDateTime = LocalDateTime.parse(startTime, formatter);
if (startDateTime.isBefore(thresholdTime)) {
// 使用 notLike 来排除以 ":01" 或 ":02" 结尾的时间
// 方案2.1:使用 apply 方法执行数据库函数 create_date 字段的实际存储格式(可能包含毫秒),所以取最后三个字符进行匹配)
queryWrapper.apply("DATE_FORMAT(create_date, '%s') NOT IN ('01', '02')");
/*queryWrapper.notLike("create_date", "%:01")
.notLike("create_date", "%:02");*/
}
} catch (Exception e) {
log.warn("Failed to parse startTime: {}, skip time-based filtering", startTime, e);
}
if (!Objects.isNull(accountIds) && !accountIds.isEmpty()) {
queryWrapper.in("account_id", accountIds);
}
@@ -1676,7 +1708,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
List<Map<String, Object>> result = baseMapper.selectMaps(queryWrapper);
if (result != null && !result.isEmpty()) {
Object countObj = result.get(0).get("count");
return (Long) countObj;
return countObj != null ? ((Number) countObj).longValue() : 0L;
} else {
return 0L;
}

View File

@@ -48,6 +48,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.io.IOUtils;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
@@ -59,10 +61,12 @@ import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import jakarta.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
@@ -194,10 +198,13 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
generate.setText(text);
Long elementId = generateThroughImageTextDTO.getCollectionElementId();
// validateGeneraType(generate, text, elementId);
if (!StringUtil.isNullOrEmpty(text)) {
text = modifyPrompt(text, generate, generateThroughImageTextDTO.getLevel1Type(), generateThroughImageTextDTO.getAgeGroup());
if (!(generateThroughImageTextDTO.getLevel1Type().equals(MOOD_BOARD.getRealName())&&generateThroughImageTextDTO.getModelName().equals("high"))){
if (!StringUtil.isNullOrEmpty(text)) {
text = modifyPrompt(text, generate, generateThroughImageTextDTO.getLevel1Type(), generateThroughImageTextDTO.getAgeGroup());
}
}
// todo 这一步现在还是有必要的吗?
// 2.1 sketch或print在t_collection_element表/t_library表中的信息是否需要更新 如 level2Type
CollectionElement collectionElement = collectionElementService.editLevel2Type(elementId, generateThroughImageTextDTO.getLevel2Type(), generateThroughImageTextDTO.getDesignType());
@@ -218,6 +225,8 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
version = "fast";
params.put("version", "fast");
}
// 4、将请求信息落库,将本次generate的请求信息添加到t_generate表中
saveGenerateImmediately(generate);
// 3.1 确定不同类型的印花分别调哪个接口
if (generateThroughImageTextDTO.getLevel1Type().equals(PRINT_BOARD.getRealName())) {
switch (generateThroughImageTextDTO.getLevel2Type()) {
@@ -243,15 +252,28 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
jsonString = JSON.toJSONString(generateToPythonDTO, SerializerFeature.WriteMapNullValue);
}
} else {
GenerateToPythonDTO generateToPythonDTO = new GenerateToPythonDTO(generateThroughImageTextDTO.getUniqueId(), text, Objects.isNull(collectionElement) ? "" : collectionElement.getUrl(),
mode, category, generateThroughImageTextDTO.getGender(), version);
jsonString = JSON.toJSONString(generateToPythonDTO, SerializerFeature.WriteMapNullValue);
if (Objects.equals(version, "fast")) {
GenerateToPythonDTO generateToPythonDTO = new GenerateToPythonDTO(generateThroughImageTextDTO.getUniqueId(), text, Objects.isNull(collectionElement) ? "" : collectionElement.getUrl(),
mode, category, generateThroughImageTextDTO.getGender(), version);
jsonString = JSON.toJSONString(generateToPythonDTO, SerializerFeature.WriteMapNullValue);
} else {
path = CommonConstant.GENERATE_PATH_FLUX2_KLEIN;
// 构建object_name: {userId}/{category}/{uuid}.png
String objectName = generateThroughImageTextDTO.getUserId() + "/" + category + "/" + UUID.randomUUID() + ".png";
ImageProcessRequest imageProcessRequest = ImageProcessRequest.builder()
.object_name(objectName)
.bucket_name(userBucket)
.prompt(text).build();
jsonString = JSON.toJSONString(imageProcessRequest);
}
}
Boolean requestResult = pythonService.generateSketchOrPrint(jsonString, port, path);
Boolean requestResult = pythonService.generateSketchOrPrint(jsonString, port, path, generateThroughImageTextDTO.getUniqueId());
// 4、将请求信息落库,将本次generate的请求信息添加到t_generate表中
save(generate);
// 5、将本次请求存入redis
String key = generateResultKey + ":" + generateThroughImageTextDTO.getUniqueId();
@@ -266,6 +288,40 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
}
public void saveGenerateImmediately(Generate generate) {
save(generate);
// 使用 TransactionSynchronizationManager 在事务真正提交后再设锁
// 否则 save() 完成后事务尚未 commitMQ 消费者立即读到 null
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
String lockKey = "generate:lock:" + generate.getUniqueId();
redisUtil.addToString(lockKey, "1", 60L);
log.debug("Save lock set after commit for uniqueId: {}", generate.getUniqueId());
}
});
}
private void waitForSaveLock(String uniqueId) {
String lockKey = "generate:lock:" + uniqueId;
int maxRetries = 30;
int retryIntervalMs = 200;
for (int i = 0; i < maxRetries; i++) {
if (Boolean.TRUE.equals(redisUtil.hasKey(lockKey))) {
log.debug("Save lock acquired for uniqueId: {} after {} retries", uniqueId, i);
return;
}
try {
Thread.sleep(retryIntervalMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("Interrupted while waiting for save lock: {}", uniqueId);
return;
}
}
log.warn("Save lock timeout for uniqueId: {}, proceeding anyway", uniqueId);
}
public GenerateModeEnum getMode(GenerateThroughImageTextDTO generateThroughImageTextDTO) {
if (!StringUtil.isNullOrEmpty(generateThroughImageTextDTO.getText())) {
if (Objects.nonNull(generateThroughImageTextDTO.getCollectionElementId())) {
@@ -284,11 +340,16 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
@Override
@Transactional(rollbackFor = Exception.class)
public void processGenerateResult(String taskId, String url, String category) {
log.info("============ProcessGenerateResult listening==========");
log.debug("taskId: " + taskId);
String status = null;
// 1、处理模型返回的数据
GenerateDetail generateDetail = new GenerateDetail();
GenerateCollectionItemVO generateCollectionItemVO = new GenerateCollectionItemVO();
Generate generate;
try {
// 等待 HTTP 线程写入完成后再查库
waitForSaveLock(taskId);
generate = selectByUniqueId(taskId);
} catch (MybatisPlusException e) {
log.error(e.getMessage());
@@ -311,14 +372,15 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
generateDetail.setUrl(url);
generateDetail.setGenerateId(generate.getId());
generateDetail.setCreateDate(LocalDateTime.now());
generateDetail.setMd5(md5);
generateDetail.setMd5("");
// 将相应的url保存到数据库
generateDetailMapper.insert(generateDetail);
log.debug("generateDetail: " + generateDetail.toString());
// String uuid = taskId.substring(0, taskId.substring(0, taskId.lastIndexOf("-")).lastIndexOf("-"));
String key = generateResultKey + ":" + taskId;
String imageName = url.substring(url.lastIndexOf("/") + 1);
String status = imageName.equals("white_image.jpg") ? "Invalid" : "Success";
status = imageName.equals("white_image.jpg") ? "Invalid" : "Success";
if (StringUtil.isNullOrEmpty(category)) {
Generate generateRecord = selectByUniqueId(taskId);
category = generateRecord.getLevel2Type();
@@ -326,6 +388,8 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
GenerateResultVO generateResultVO = new GenerateResultVO(taskId, generateDetail.getId(), url, status, category);
// 更新redis
redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
log.debug("generateResultVO: " + generateResultVO.toString());
// 执行积分扣除
// ** 注:如果生成的图片都是空白 则不扣积分
@@ -785,8 +849,9 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
long requestEndTime = System.currentTimeMillis();
log.info("HTTP请求完成 - 响应状态: {}, 耗时: {}ms, taskId: {}",
response.code(), (requestEndTime - requestStartTime), taskId);
String result = response.body().string();
if (!response.isSuccessful()) {
log.warn("Google API响应失败状态码: {} for taskId: {}", response.code(), taskId);
log.warn("Google API响应失败状态码: {} for taskId: {},结果:{}", response.code(), taskId, result);
if (attempt < maxRetries) {
Thread.sleep(retryDelay * attempt); // 递增延迟
continue;
@@ -795,7 +860,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
}
}
String result = response.body().string();
// log.info("Google 响应结果:{}", result);
com.alibaba.fastjson.JSONObject jsonResponse = JSON.parseObject(result);
@@ -1065,6 +1130,12 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
String result = response.body().string();
if (response.code() != 200) {
log.error("Google API 请求失败 - taskId: {}, 尝试: {}, URL: {}, 状态码: {}, 响应结果: {}",
taskId, attempt, endpoint, response.code(), result);
throw new BusinessException("system.error");
}
// log.info("Google 响应结果:{}", result);
com.alibaba.fastjson.JSONObject jsonResponse = JSON.parseObject(result);
@@ -1203,7 +1274,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
* @param modelName advanced high normal
*/
private HashMap<String, String> chooseModelAndPrompt(GenerateThroughImageTextDTO generateDTO, String modelName) {
if (StringUtil.isNullOrEmpty(modelName)){
if (StringUtil.isNullOrEmpty(modelName)) {
throw new BusinessException("system error");
}
HashMap<String, String> modelAndPromptMap = new HashMap<>();
@@ -1221,7 +1292,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
String style = generateDTO.getText().substring(0, firstCommaIndex).trim();
String prompt = generateDTO.getText().substring(firstCommaIndex + 1).trim();
prompt = getPrintboardPrompt(style, prompt,modelName);
prompt = getPrintboardPrompt(style, prompt, modelName, isUseImage);
modelAndPromptMap.put(ModelConstants.PROMPT, prompt);
@@ -1260,8 +1331,31 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
modelAndPromptMap.put(ModelConstants.USE_MODEL, ModelConstants.LOCAL_MODEL);
}
} else if (ModelConstants.SKETCHBOARD.equals(generateDTO.getLevel1Type())) {
String prompt = generateDTO.getText() + "rules:front view sketch only,plain white background, single garment only, orthographic, centered on white background, borderless canvas, thin monochrome black line art.\n" +
String style = "";
String userPrompt = "";
// 找到第一个逗号的位置
int firstCommaIndex = generateDTO.getText().indexOf(",");
if (firstCommaIndex != -1) {
// 截取第一个逗号前的内容作为style
style = generateDTO.getText().substring(0, firstCommaIndex).trim();
// 截取第一个逗号后的所有内容作为userPrompt去除首尾空格
userPrompt = generateDTO.getText().substring(firstCommaIndex + 1).trim();
if ("Lolita".equals(style)) {
style = "洛丽塔";
}
} else {
// 兼容无逗号的情况style为空全部内容作为userPrompt
userPrompt = generateDTO.getText().trim();
}
String prompt = userPrompt + "rules:front view sketch only,plain white background, single garment only, orthographic, centered on white background, borderless canvas, thin monochrome black line art.\n" +
" No clothes hanger, no fake clothes hanger, no human-related lines, no color fill, no words, no text, no black background, no boundary or frame.";
if (!style.trim().isEmpty() && !"all".equalsIgnoreCase(style)) {
prompt += ".sketch style:" + style.trim();
}
modelAndPromptMap.put(ModelConstants.PROMPT, prompt);
if (isUseImage) {
if (ModelConstants.ADVANCED.equals(modelName)) {
@@ -1459,6 +1553,13 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
if (imagePath != null) {
requestBuilder.image(finalImagePath1);
}
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)) {
GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions();
optimizePromptOptions.setMode("fast");
requestBuilder.optimizePromptOptions(optimizePromptOptions);
//由于PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致为了区别积分扣除PRINTBOARD_HIGH_I2I加入了-fast但传入模型时需要去掉-fast用PRINTBOARD_ADVANCED_I2I的常量做替代
requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I);
}
// 保存生成记录到数据库
Generate generate = new Generate(
@@ -1570,7 +1671,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
}
private String getPrintboardPrompt(String style, String userInput, String modelName) {
private String getPrintboardPrompt(String style, String userInput, String modelName, boolean isUseImage) {
String systemPrompt = null;
String prompt;
@@ -1596,12 +1697,16 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
"Flat textile pattern printed directly on fabric surface, no three-dimensional objects, no items placed on cloth. \n" +
"Real style: fabric print, realistic woven/printed pattern, detailed surface pattern only";
}
}else {
throw new BusinessException("style error:"+ style);
} else {
throw new BusinessException("style error:" + style);
}
if (userInput == null || userInput.trim().isEmpty()) {
throw new BusinessException("prompt null");
if (isUseImage) {
prompt = "Theme: Image content" + "\nRequirement: " + systemPrompt;
} else {
throw new BusinessException("prompt null");
}
} else {
prompt = "Theme: " + userInput.trim() + "\nRequirement: " + systemPrompt;
}
@@ -2001,7 +2106,9 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
public Generate selectByUniqueId(String uniqueId) {
QueryWrapper<Generate> qw = new QueryWrapper<>();
qw.eq("unique_id", uniqueId);
log.debug("selectByUniqueId: " + uniqueId);
Generate one = getOne(qw);
log.debug("Generate: " + one);
return getOne(qw);
}
@@ -4172,11 +4279,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
// 处理不同状态
switch (statusEnum) {
case TASK_NOT_FOUND:
// 审核没过
// 审核没过
case REQUEST_MODERATED:
// 审核没过
// 审核没过
case CONTENT_MODERATED:
// 出错
// 出错
case ERROR:
return "Fail";
case PENDING_F:
@@ -4295,7 +4402,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
MotionModeEnum motionModeEnum = MotionModeEnum.of(poseTransformDTO.getMode());
switch (motionModeEnum) {
case POSE_TO_VIDEO:
params.put("pose_id", poseTransformDTO.getPoseId());
params.put("pose_id", poseTransformDTO.getPoseId().toString());
params.put("image_url", poseTransformDTO.getProductImage());
break;
case PROMPT_TO_VIDEO:

View File

@@ -22,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
@@ -29,6 +30,20 @@ import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.FileOutputStream;
import java.time.format.DateTimeFormatter;
@Service
@Slf4j
@@ -46,7 +61,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
private final RedisUtil redisUtil;
@Value("${file.upload.dir:uploads}")
@Value("${file.upload.temp.dir}")
private String uploadDir;
private static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy/MM");
@@ -128,6 +143,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> saveContestant(ContestantDTO request) {
Map<String,Object> resp = new HashMap<>();
if (request.getEmail() == null) {
@@ -142,26 +158,59 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
LocalDateTime now = LocalDateTime.now();
if (existing == null) {
Contestant toInsert = Contestant.builder()
.email(request.getEmail())
.firstName(request.getFirstName())
.lastName(request.getLastName())
.gender(request.getGender())
.occupation(request.getOccupation())
.age(request.getAge())
.countryRegionCity(request.getCountryRegionCity())
.phoneNumber(request.getPhoneNumber())
.designTitle(request.getDesignTitle())
.designDescription(request.getDesignDescription())
.pdfPath(request.getPdfPath())
.videoPath(request.getVideoPath())
.createdAt(now)
.updatedAt(now)
.build();
contestantMapper.insert(toInsert);
resp.put("success", true);
sendSiteMsg(toInsert.getId(), toInsert.getEmail());
return resp;
// 通过行锁 + 重试机制保证 contestant_number 在并发下自增分配
final int maxAttempts = 5;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
// 获取当前最大 contestant_number 并加行锁LIMIT 1 FOR UPDATE
QueryWrapper<Contestant> qMax = new QueryWrapper<>();
qMax.isNotNull("contestant_number");
qMax.orderByDesc("contestant_number");
qMax.last("LIMIT 1 FOR UPDATE");
Contestant last = contestantMapper.selectOne(qMax);
Integer nextNumber = (last == null || last.getContestantNumber() == null) ? 10000 : last.getContestantNumber() + 1;
Contestant toInsert = Contestant.builder()
.email(request.getEmail())
.firstName(request.getFirstName())
.lastName(request.getLastName())
.gender(request.getGender())
.occupation(request.getOccupation())
.age(request.getAge())
.countryRegionCity(request.getCountryRegionCity())
.phoneNumber(request.getPhoneNumber())
.designTitle(request.getDesignTitle())
.designDescription(request.getDesignDescription())
.pdfPath(request.getPdfPath())
.videoPath(request.getVideoPath())
.videoDuration(request.getVideoDuration())
.videoSize(request.getVideoSize())
.pdfSize(request.getPdfSize())
.contestantNumber(nextNumber)
.createdAt(now)
.updatedAt(now)
.build();
contestantMapper.insert(toInsert);
resp.put("success", true);
sendSiteMsg(toInsert.getId(), toInsert.getEmail());
return resp;
} catch (Exception e) {
log.warn("Attempt {} to assign contestant_number failed", attempt, e);
String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase();
if ((msg.contains("duplicate") || msg.contains("uniq_contestant_number") || msg.contains("contestant_number")) && attempt < maxAttempts) {
try {
Thread.sleep(100L);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
continue;
}
throw e;
}
}
throw new BusinessException("Failed to assign contestant number after retries.");
} else {
// update existing contestant
existing.setFirstName(request.getFirstName());
@@ -175,6 +224,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
existing.setDesignDescription(request.getDesignDescription());
existing.setPdfPath(request.getPdfPath());
existing.setVideoPath(request.getVideoPath());
existing.setVideoDuration(request.getVideoDuration());
existing.setVideoSize(request.getVideoSize());
existing.setPdfSize(request.getPdfSize());
existing.setUpdatedAt(now);
contestantMapper.updateById(existing);
resp.put("success", true);
@@ -182,6 +234,134 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
}
}
@Override
public byte[] exportContestants() throws Exception {
List<Contestant> list = contestantMapper.selectList(new QueryWrapper<>());
try (XSSFWorkbook workbook = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
Sheet sheet = workbook.createSheet("contestants");
int rowIdx = 0;
Row header = sheet.createRow(rowIdx++);
String[] headers = new String[] {
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
};
for (int i = 0; i < headers.length; i++) {
Cell c = header.createCell(i);
c.setCellValue(headers[i]);
}
for (Contestant cst : list) {
Row r = sheet.createRow(rowIdx++);
int ci = 0;
r.createCell(ci++).setCellValue(cst.getContestantNumber() == null ? "" : cst.getContestantNumber().toString());
r.createCell(ci++).setCellValue(cst.getEmail() == null ? "" : cst.getEmail());
r.createCell(ci++).setCellValue(cst.getFirstName() == null ? "" : cst.getFirstName());
r.createCell(ci++).setCellValue(cst.getLastName() == null ? "" : cst.getLastName());
r.createCell(ci++).setCellValue(cst.getGender() == null ? "" : cst.getGender());
r.createCell(ci++).setCellValue(cst.getOccupation() == null ? "" : cst.getOccupation());
r.createCell(ci++).setCellValue(cst.getAge() == null ? "" : cst.getAge().toString());
r.createCell(ci++).setCellValue(cst.getCountryRegionCity() == null ? "" : cst.getCountryRegionCity());
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
// 视频时长(秒)
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
if (cst.getVideoSize() == null) {
r.createCell(ci++).setCellValue("");
} else {
double vMb = cst.getVideoSize() / 1024.0 / 1024.0;
r.createCell(ci++).setCellValue(String.format("%.2f", vMb));
}
if (cst.getPdfSize() == null) {
r.createCell(ci++).setCellValue("");
} else {
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
}
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
}
workbook.write(out);
out.flush();
return out.toByteArray();
} catch (IOException e) {
log.error("export contestants failed", e);
throw e;
}
}
@Override
public void saveContestantsToLocal() throws Exception {
List<Contestant> list = contestantMapper.selectList(new QueryWrapper<>());
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
String ts = LocalDateTime.now().format(fmt);
Path exportDir = Paths.get(uploadDir == null ? "uploads" : uploadDir, "exports");
Files.createDirectories(exportDir);
Path outPath = exportDir.resolve("contestants_" + ts + ".xlsx");
try (XSSFWorkbook workbook = new XSSFWorkbook(); FileOutputStream fos = new FileOutputStream(outPath.toFile())) {
Sheet sheet = workbook.createSheet("contestants");
int rowIdx = 0;
Row header = sheet.createRow(rowIdx++);
String[] headers = new String[] {
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
};
for (int i = 0; i < headers.length; i++) {
Cell c = header.createCell(i);
c.setCellValue(headers[i]);
}
for (Contestant cst : list) {
Row r = sheet.createRow(rowIdx++);
int ci = 0;
r.createCell(ci++).setCellValue(cst.getContestantNumber() == null ? "" : cst.getContestantNumber().toString());
r.createCell(ci++).setCellValue(cst.getEmail() == null ? "" : cst.getEmail());
r.createCell(ci++).setCellValue(cst.getFirstName() == null ? "" : cst.getFirstName());
r.createCell(ci++).setCellValue(cst.getLastName() == null ? "" : cst.getLastName());
r.createCell(ci++).setCellValue(cst.getGender() == null ? "" : cst.getGender());
r.createCell(ci++).setCellValue(cst.getOccupation() == null ? "" : cst.getOccupation());
r.createCell(ci++).setCellValue(cst.getAge() == null ? "" : cst.getAge().toString());
r.createCell(ci++).setCellValue(cst.getCountryRegionCity() == null ? "" : cst.getCountryRegionCity());
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
// 视频时长(秒)
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
if (cst.getVideoSize() == null) {
r.createCell(ci++).setCellValue("");
} else {
double vMb = cst.getVideoSize() / 1024.0 / 1024.0;
r.createCell(ci++).setCellValue(String.format("%.2f", vMb));
}
if (cst.getPdfSize() == null) {
r.createCell(ci++).setCellValue("");
} else {
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
}
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
}
workbook.write(fos);
fos.flush();
log.info("Exported contestants to local file: {}", outPath.toString());
} catch (IOException e) {
log.error("save contestants to local failed", e);
throw e;
}
}
@Override
public ContestantDTO getContestantByID(String id) {
if (id == null) {
@@ -204,6 +384,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
dto.setDesignDescription(existing.getDesignDescription());
dto.setPdfPath(existing.getPdfPath());
dto.setVideoPath(existing.getVideoPath());
dto.setVideoDuration(existing.getVideoDuration());
dto.setPdfSize(existing.getPdfSize());
dto.setVideoSize(existing.getVideoSize());
return dto;
}
@@ -295,6 +478,111 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
// 这里推送消息是在接受到视频生成结束后发生的所以UserContext中没有用户信息
messageCenterService.pushMessage("system", userId);
}
@Override
public int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
if (minContestantNumber == null || maxContestantNumber == null) {
throw new BusinessException("minContestantNumber and maxContestantNumber are required.");
}
if (minContestantNumber > maxContestantNumber) {
throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber.");
}
// 1. 根据contestantNumber范围查询参赛者
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.ge(Contestant::getContestantNumber, minContestantNumber)
.le(Contestant::getContestantNumber, maxContestantNumber)
.orderByAsc(Contestant::getContestantNumber);
List<Contestant> contestants = contestantMapper.selectList(queryWrapper);
if (contestants.isEmpty()) {
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
return 0;
}
// 2. 创建基础目录
String baseDir = uploadDir + "/contestants";
Path basePath = Paths.get(baseDir).toAbsolutePath();
Files.createDirectories(basePath);
log.info("Base directory created: {}", basePath);
int exportedCount = 0;
// 3. 遍历每个参赛者,下载文件
for (Contestant contestant : contestants) {
Integer contestantNumber = contestant.getContestantNumber();
if (contestantNumber == null) {
log.warn("Contestant {} has no contestantNumber, skipping", contestant.getId());
continue;
}
// 创建参赛者文件夹
String contestantDir = baseDir + "/" + contestantNumber;
Path contestantPath = Paths.get(contestantDir);
Files.createDirectories(contestantPath);
// 下载PDF文件
String pdfPath = contestant.getPdfPath();
if (StringUtils.isNotBlank(pdfPath)) {
try {
String fileName = pdfPath.contains("/") ?
pdfPath.substring(pdfPath.lastIndexOf("/") + 1) : "design.pdf";
downloadFileFromMinio(pdfPath, contestantPath.toString(), "design.pdf");
log.info("Downloaded PDF for contestant {}", fileName);
} catch (Exception e) {
log.error("Failed to download PDF for contestant {}: {}", contestantNumber, e.getMessage());
}
}
// 下载视频文件
String videoPath = contestant.getVideoPath();
if (StringUtils.isNotBlank(videoPath)) {
try {
// 根据路径判断视频格式
String fileName = videoPath.contains("/") ?
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
downloadFileFromMinio(videoPath, contestantPath.toString(), fileName);
log.info("Downloaded video for contestant {}", contestantNumber);
} catch (Exception e) {
log.error("Failed to download video for contestant {}: {}", contestantNumber, e.getMessage());
}
}
exportedCount++;
}
log.info("Exported {} contestants' files to {}", exportedCount, basePath);
return exportedCount;
}
/**
* 从MinIO下载文件到本地
* @param minioPath MinIO路径 (格式: bucketName/objectPath)
* @param localDir 本地目录
* @param fileName 本地文件名
*/
private void downloadFileFromMinio(String minioPath, String localDir, String fileName) {
if (StringUtils.isBlank(minioPath)) {
return;
}
// 从路径中提取bucket名称和对象名称
int index = minioPath.indexOf("/");
if (index == -1) {
log.warn("Invalid MinIO path: {}", minioPath);
return;
}
String bucketName = minioPath.substring(0, index);
String objectName = minioPath.substring(index + 1);
// 构建本地文件完整路径
Path localFilePath = Paths.get(localDir, fileName);
// 下载文件
minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath.toString());
}
}

View File

@@ -28,6 +28,7 @@ import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -53,7 +54,11 @@ public class LibraryModelPointServiceImpl extends ServiceImpl<LibraryModelPointM
private final PythonTAllInfoService pythonTAllInfoService;
@Override
@Transactional(rollbackFor = Exception.class)
public LibraryModelPointVO saveOrEditTemplatePoint(LibraryModelPointDTO libraryModelPointDTO) {
// 参数校验
validateInputParams(libraryModelPointDTO);
LibraryModelPointVO libraryModelPointVO = CopyUtil.copyObject(libraryModelPointDTO, LibraryModelPointVO.class);
// 不管是保存还是另存为都需要传模特的libraryId
@@ -71,7 +76,8 @@ public class LibraryModelPointServiceImpl extends ServiceImpl<LibraryModelPointM
// 更新模特图片
if (flag) {
libModel.setUrl(url);
libModel.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), false));
String preSignedUrl = minioUtil.getPreSignedUrl(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME);
libModel.setMd5(MD5Utils.encryptFile(preSignedUrl, false));
List<Integer> imagesWidthAndHeight = minioUtil.getImagesWidthAndHeight(url);
libModel.setWidth(imagesWidthAndHeight.get(0));
libModel.setHigh(imagesWidthAndHeight.get(1));
@@ -104,25 +110,10 @@ public class LibraryModelPointServiceImpl extends ServiceImpl<LibraryModelPointM
} else {
// 不覆盖,即另存为
// 新增模特library信息
Library saveAsModel = new Library();
saveAsModel.setAccountId(libModel.getAccountId());
saveAsModel.setLevel1Type(libModel.getLevel1Type());
saveAsModel.setLevel2Type(libModel.getLevel2Type());
String ageGroup = StringUtil.isNullOrEmpty(libModel.getLevel3Type()) ? "Adult" : libModel.getLevel3Type();
saveAsModel.setLevel3Type(ageGroup);
saveAsModel.setName(DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD));
saveAsModel.setUrl(url);
saveAsModel.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), false));
List<Integer> imagesWidthAndHeight = minioUtil.getImagesWidthAndHeight(url);
saveAsModel.setWidth(imagesWidthAndHeight.get(0));
saveAsModel.setHigh(imagesWidthAndHeight.get(1));
saveAsModel.setCreateDate(DateUtil.getByTimeZone(libraryModelPointDTO.getTimeZone()));
libraryService.save(saveAsModel);
// 更新新的模特在library中的id,用于后面新建模特点位信息用
libraryModelPointDTO.setLibraryId(saveAsModel.getId());
Library saveAsModel = createNewLibraryCopy(libModel, libraryModelPointDTO);
// 新增模特点位信息
libraryModelPointDTO.setLibraryId(saveAsModel.getId()); // 更新libraryId为新创建的模型ID
LibraryModelPoint libraryModelPoint = resolvePoint(libraryModelPointDTO);
libraryModelPoint.setModelType("Library");
libraryModelPoint.setCreateDate(DateUtil.getByTimeZone(libraryModelPointDTO.getTimeZone()));
@@ -130,22 +121,50 @@ public class LibraryModelPointServiceImpl extends ServiceImpl<LibraryModelPointM
libraryModelPointVO.setTemplateId(libraryModelPoint.getId());
libraryModelPointVO.setRelationId(libraryModelPoint.getRelationId());
}
//编辑
/*if (!StringUtils.isEmpty(libraryModelPointDTO.getModelSex())) {
Library byId = libraryService.getById(libraryModelPointDTO.getLibraryId());
if (!byId.getLevel2Type().equals(libraryModelPointDTO.getModelSex())) {
if (byId.getLevel2Type().equals(Sex.FEMALE.getValue())) {
libraryService.checkModel(Sex.FEMALE.getValue(), Collections.singletonList(byId.getId()), 1);
}else {
libraryService.checkModel(Sex.MALE.getValue(), Collections.singletonList(byId.getId()), 1);
}
byId.setLevel2Type(libraryModelPointDTO.getModelSex());
libraryService.updateById(byId);
}
}*/
return libraryModelPointVO;
}
/**
* 验证输入参数
*/
private void validateInputParams(LibraryModelPointDTO libraryModelPointDTO) {
if (libraryModelPointDTO == null) {
throw new BusinessException("libraryModelPointDTO cannot be null");
}
if (libraryModelPointDTO.getLibraryId() == null || libraryModelPointDTO.getLibraryId() <= 0) {
throw new BusinessException("libraryId is required");
}
if (StringUtils.isEmpty(libraryModelPointDTO.getModelPath())) {
throw new BusinessException("modelPath is required");
}
if (StringUtils.isEmpty(libraryModelPointDTO.getTimeZone())) {
throw new BusinessException("timeZone is required");
}
}
/**
* 创建新的库模型副本
*/
private Library createNewLibraryCopy(Library originalModel, LibraryModelPointDTO libraryModelPointDTO) {
// 新增模特library信息
Library saveAsModel = new Library();
saveAsModel.setAccountId(originalModel.getAccountId());
saveAsModel.setLevel1Type(originalModel.getLevel1Type());
saveAsModel.setLevel2Type(originalModel.getLevel2Type());
String ageGroup = StringUtil.isNullOrEmpty(originalModel.getLevel3Type()) ? "Adult" : originalModel.getLevel3Type();
saveAsModel.setLevel3Type(ageGroup);
saveAsModel.setName(DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD));
saveAsModel.setUrl(libraryModelPointDTO.getModelPath());
String preSignedUrl = minioUtil.getPreSignedUrl(libraryModelPointDTO.getModelPath(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME);
saveAsModel.setMd5(MD5Utils.encryptFile(preSignedUrl, false));
List<Integer> imagesWidthAndHeight = minioUtil.getImagesWidthAndHeight(libraryModelPointDTO.getModelPath());
saveAsModel.setWidth(imagesWidthAndHeight.get(0));
saveAsModel.setHigh(imagesWidthAndHeight.get(1));
saveAsModel.setCreateDate(DateUtil.getByTimeZone(libraryModelPointDTO.getTimeZone()));
libraryService.save(saveAsModel);
return saveAsModel;
}
@Override
public LibraryModelPointVO saveOrEditTemplatePointOld(LibraryModelPointDTO libraryModelPointDTO) {
// Library library = libraryService.getById(libraryModelPointDTO.getLibraryId());

View File

@@ -31,6 +31,11 @@ public class RabbitMQServiceImpl implements RabbitMQService {
mqPublisher.sendGenerateMessage(message);
}
@Override
public void publishMessageToGenerateResult(String message) {
mqPublisher.sendGenerateResultMessage(message);
}
@Override
public void publishMessageToSR(String message) {
mqPublisher.sendSRMessage(message);

View File

@@ -1060,11 +1060,12 @@ public class StripeServiceImpl implements StripeService {
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
.eq(PaymentInfo::getTradeState, "paid")
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
.orderByDesc(PaymentInfo::getId);
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
if (paymentInfos.isEmpty()) {
log.info("不发送邮件原因【根据order_no:{},查询到的paymentInfos为空】", orderNo);
log.info("不发送邮件原因【根据order_no:{},查询到的成功的paymentInfos为空】", orderNo);
return false;
}
PaymentInfo paymentInfo = paymentInfos.get(0);

View File

@@ -905,15 +905,15 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
}
}
// 将构建好的结果对象添加到返回列表
results.add(magicToolResultVO);
// results.add(magicToolResultVO);
} else if (Objects.isNull(magicToolResultVO)) {
// 如果Redis中没有结果对象创建执行中状态的结果对象
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
results.add(magicToolResultVO);
} else {
// results.add(magicToolResultVO);
}/* else {
// 如果Redis中有结果对象但URL为空直接添加到返回列表
results.add(magicToolResultVO);
}
}*/
// 收集任务状态用于统计
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
@@ -1461,12 +1461,16 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
if (StringUtil.isNullOrEmpty(fluxResult)) {
toProductImageResult.setStatus("Fail");
toProductImageResultMapper.updateById(toProductImageResult);
sortRank(toProductImageResult);
if (toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
sortRank(toProductImageResult);
}
results.add(new MagicToolResultVO(taskId, "Fail"));
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
toProductImageResult.setStatus(fluxResult);
toProductImageResultMapper.updateById(toProductImageResult);
sortRank(toProductImageResult);
if (fluxResult.equals("Fail") && toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
sortRank(toProductImageResult);
}
results.add(new MagicToolResultVO(taskId, fluxResult));
} else {
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
@@ -2203,10 +2207,14 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
List<AllCollectionVO> childList = new ArrayList<>();
// 收集需要删除的失败记录ID用于后续统一清理并重新排序
List<Long> failedSortIds = new ArrayList<>();
for (CollectionSort userLikeSort : childSortList) {
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
failedSortIds.add(userLikeSort.getId());
log.info("【获取内容】TO_PRODUCT_IMAGE结果失败relationId={}即将从collection_sort中删除", userLikeSort.getRelationId());
continue;
}
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
@@ -2238,6 +2246,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
failedSortIds.add(userLikeSort.getId());
log.info("【获取内容】RELIGHT结果失败relationId={}即将从collection_sort中删除", userLikeSort.getRelationId());
continue;
}
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
@@ -2269,6 +2279,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
failedSortIds.add(userLikeSort.getId());
log.info("【获取内容】POSE_TRANSFORM结果失败relationId={}即将从collection_sort中删除", userLikeSort.getRelationId());
continue;
}
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
@@ -2293,6 +2305,114 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
childList.add(poseTransformationVO);
}
}
// 统一处理失败的记录从collection_sort表中删除失败的记录并重新排序
if (CollectionUtil.isNotEmpty(failedSortIds)) {
Long parentId = collectionSort.getId();
Long projectId = projectDTO.getId();
log.info("【获取内容】检测到{}条失败记录需要清理parentId={}, projectId={}", failedSortIds.size(), parentId, projectId);
for (Long failedSortId : failedSortIds) {
CollectionSort failedRecord = collectionSortMapper.selectById(failedSortId);
if (failedRecord != null) {
String relationType = failedRecord.getRelationType();
Long relationId = failedRecord.getRelationId();
collectionSortService.deleteCollectionSort(relationId, relationType, projectId, parentId);
log.info("【获取内容】已删除失败记录relationId={}, relationType={}", relationId, relationType);
}
}
// 重新查询子列表,获取更新后的排序
childSortList = collectionSortMapper.selectList(childCollectionQw);
// 重新构建childList使用更新后的sort值
childList = new ArrayList<>();
for (CollectionSort userLikeSort : childSortList) {
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
continue;
}
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
if (Objects.isNull(toProductImageRecord)) {
continue;
}
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
} else {
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
}
toProductImageResultVO.setCollectionType(CollectionType.TO_PRODUCT_IMAGE.getValue());
toProductImageResultVO.setSort(userLikeSort.getSort());
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
toProductImageResultVO.setParentId(userLikeSort.getParentId());
childList.add(toProductImageResultVO);
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
continue;
}
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
if (Objects.isNull(toProductImageRecord)) {
continue;
}
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
} else {
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
}
toProductImageResultVO.setCollectionType(CollectionType.RELIGHT.getValue());
toProductImageResultVO.setSort(userLikeSort.getSort());
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
toProductImageResultVO.setParentId(userLikeSort.getParentId());
childList.add(toProductImageResultVO);
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
continue;
}
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
poseTransformationVO.setId(item.getId());
poseTransformationVO.setTaskId(item.getUniqueId());
poseTransformationVO.setProductImage(getMinioUrl(item.getProductImage()));
poseTransformationVO.setLastFrameProductImage(getMinioUrl(item.getLastFrameProductImage()));
poseTransformationVO.setPrompt(item.getPrompt());
poseTransformationVO.setGifUrl(getMinioUrl(item.getGifUrl()));
poseTransformationVO.setVideoUrl(getMinioUrl(item.getVideoUrl()));
poseTransformationVO.setFirstFrameUrl(getMinioUrl(item.getFirstFrameUrl()));
poseTransformationVO.setIsLiked(item.getIsLiked());
poseTransformationVO.setCollectionType(CollectionType.POSE_TRANSFORM.getValue());
poseTransformationVO.setSort(userLikeSort.getSort());
poseTransformationVO.setUserLikeSortId(userLikeSort.getId());
poseTransformationVO.setRelationType(userLikeSort.getRelationType());
poseTransformationVO.setResultType(CollectionType.POSE_TRANSFORM.getValue());
poseTransformationVO.setParentId(userLikeSort.getParentId());
poseTransformationVO.setModelName(item.getModelName());
poseTransformationVO.setPoseId(item.getPoseId());
poseTransformationVO.setStatus(item.getTaskStatus());
childList.add(poseTransformationVO);
}
}
log.info("【获取内容】失败记录清理完成重新排序后childList.size={}", childList.size());
}
o.setChildList(childList);
list.add(o);

View File

@@ -125,9 +125,9 @@ orderList.link=https://develop.aida.com.hk/home/homePage?order=
# 0 不发送邮件通知 1 发送邮件通知
stripe.webhook.fail.reminder=0
# kim test
stripe.paymentMethodConfiguration=pmc_1LywTWH7nPZ8bkrN6FvdCUWG
#stripe.paymentMethodConfiguration=pmc_1LywTWH7nPZ8bkrN6FvdCUWG
# developer test
#stripe.paymentMethodConfiguration=pmc_1QIKyq02n1TEydyNKVEYvhW7
stripe.paymentMethodConfiguration=pmc_1QIKyq02n1TEydyNKVEYvhW7
#thymelea模板配置
#控制 Thymeleaf 是否启用模板缓存 生产环境用true,以提高性能
spring.thymeleaf.cache=false
@@ -181,4 +181,4 @@ file.upload.max.size.video=104857600
# 上传任务过期时间(小时)
file.upload.task.expiry.hours=24
global.award.link=https://develop.aida.com.hk/award/contestants?id=
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=

View File

@@ -179,4 +179,4 @@ file.upload.max.size.video=104857600
# 上传任务过期时间(小时)
file.upload.task.expiry.hours=24
global.award.link=https://www.aida.com.hk/award/contestants?id=
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=

View File

@@ -61,10 +61,10 @@
</if>
<!-- 添加时间区间查询条件 -->
<if test="startTime != null and startTime != ''">
AND cd.create_time &gt;= #{startTime}
AND create_time &gt;= #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND cd.create_time &lt;= #{endTime}
AND create_time &lt;= #{endTime}
</if>
GROUP BY
account_id

View File

@@ -52,8 +52,10 @@
AND b.create_date between #{startTime} and #{endTime}
</if>
</where>
and b.create_date not like '%:01'
and b.create_date not like '%:02'
<if test="filterBySecond">
and b.create_date not like '%:01'
and b.create_date not like '%:02'
</if>
<if test="ids != null and ids.size() > 0">
and a.id in
<foreach item="id" collection="ids" open="(" separator="," close=")">

View File

@@ -17,3 +17,5 @@
</mapper>