7 Commits

9 changed files with 150 additions and 64 deletions

View File

@@ -13,8 +13,9 @@ public class CommonConstant {
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
// 单位 秒 一天过期 in redis
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
// 单位 秒 7天过期
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
// 单位 秒 7天过期 todo 测试状态下 3小时过期
// public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
public static final Long REDIS_SET_EXPIRE_TIME = 3 * 60 * 60L;
public static class Numbers{
public static final Integer NUMBER_10 = 10;

View File

@@ -18,8 +18,8 @@ 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 MOODBOARD_ADVANCED = "doubao-seedream-4-5-251128";
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-4-0-250828-high";
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";

View File

@@ -5,6 +5,7 @@ import com.ai.da.model.dto.*;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.model.vo.CheckOTPVO;
import com.ai.da.model.vo.ContestantCountVO;
import com.ai.da.model.vo.PageVisitCountVO;
import com.ai.da.service.GlobalAwardService;
import com.ai.da.service.upload.UploadService;
import com.ai.da.service.upload.UploadTask;
@@ -198,6 +199,19 @@ public class GlobalAwardController {
return Response.success(globalAwardService.getContestantCount());
}
@PostMapping("/page/visit")
@ApiOperation(value = "记录比赛页面访问量", notes = "记录比赛页面的访问量,包含两种统计方式:每次访问/刷新计一次以及5秒内刷新只计一次")
public Response<Void> recordPageVisit(@ApiParam(value = "会话ID用于5秒内去重判断", required = false) @RequestParam(value = "sessionId", required = false) String sessionId) {
globalAwardService.recordPageVisit(sessionId);
return Response.success();
}
@GetMapping("/page/visit/count")
@ApiOperation(value = "获取比赛页面访问量", notes = "获取比赛页面的两种访问量rawVisitCount每次访问/刷新计一次)和 uniqueVisitCount5秒内刷新只计一次")
public Response<PageVisitCountVO> getPageVisitCount() {
return Response.success(globalAwardService.getPageVisitCount());
}
}

View File

@@ -0,0 +1,23 @@
package com.ai.da.model.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageVisitCountVO {
/**
* 每次访问或刷新都计一次(不去重)
*/
private Long rawVisitCount;
/**
* 5秒内刷新只算一次去重后的真实访客数
*/
private Long uniqueVisitCount;
}

View File

@@ -2912,72 +2912,71 @@ public class PythonService {
private PrintToPython resolveDesignSinglePrint(List<DesignSinglePrint> printObject, String partialDesign) {
PrintToPython printToPython = new PrintToPython();
// DesignPythonItemPrint printSingle = new DesignPythonItemPrint();
DesignPythonItemPrint printOverall = new DesignPythonItemPrint();
// printToPython.setSingle(printSingle);
printToPython.setOverall(printOverall);
printToPython.setPartial(StringUtil.isNullOrEmpty(partialDesign) ? null : partialDesign);
if (Objects.isNull(printObject) || printObject.isEmpty()) {
return printToPython;
}
// 没有印花时的参数设置
// if (printObject.getIfSingle().equals(Boolean.FALSE) && CollectionUtil.isEmpty(printObject.getPrints())) {
// return new DesignPythonItemPrint(new ArrayList<>(), false);
// }
// DesignPythonItemPrint print = CopyUtil.copyObject(printObject, DesignPythonItemPrint.class);
// 1. 先对 printObject 按 priority 排序(升序)
List<DesignSinglePrint> sortedPrints = printObject.stream()
.sorted(Comparator.comparingInt(DesignSinglePrint::getPriority))
.toList();
int size = printObject.size();
// 占位符填充数组
List<List<Float>> locationS = new ArrayList<>(Collections.nCopies(size, null));
List<List<Float>> scaleS = new ArrayList<>(Collections.nCopies(size, null));
List<Double> angleS = new ArrayList<>(Collections.nCopies(size, null));
ArrayList<String> pathsS = new ArrayList<>(Collections.nCopies(size, null));
// 2. 分别收集单印和非单印的数据
List<DesignSinglePrint> singlePrints = sortedPrints.stream()
.filter(DesignSinglePrint::getIfSingle)
.toList();
List<List<Float>> locationO = new ArrayList<>(Collections.nCopies(size, null));
List<List<Float>> scaleO = new ArrayList<>(Collections.nCopies(size, null));
List<Double> angleO = new ArrayList<>(Collections.nCopies(size, null));
ArrayList<String> pathsO = new ArrayList<>(Collections.nCopies(size, null));
List<DesignSinglePrint> overallPrints = sortedPrints.stream()
.filter(p -> !p.getIfSingle())
.toList();
// 设置印花的位置、大小、旋转角度
// 优先级越大越靠近顶层在传输给python的数组中越靠前
// List<DesignSinglePrint> prints = printObject.getPrints();
printObject.forEach(p -> {
p.getLocation().set(0, p.getLocation().get(0));
p.getLocation().set(1, p.getLocation().get(1));
Integer priority = p.getPriority();
setUriToMinioPath(p);
// todo 下标越界问题
if (p.getIfSingle()) {
locationS.set(priority - 1, p.getLocation());
scaleS.set(priority - 1, p.getScale());
angleS.set(priority - 1, p.getAngle());
pathsS.set(priority - 1, p.getMinIOPath());
} else {
locationO.set(priority - 1, p.getLocation());
scaleO.set(priority - 1, p.getScale());
angleO.set(priority - 1, p.getAngle());
pathsO.set(priority - 1, p.getMinIOPath());
// 3. 处理单印数据
if (!singlePrints.isEmpty()) {
List<List<Float>> locationS = new ArrayList<>();
List<List<Float>> scaleS = new ArrayList<>();
List<Double> angleS = new ArrayList<>();
List<String> pathsS = new ArrayList<>();
for (DesignSinglePrint p : singlePrints) {
setUriToMinioPath(p);
locationS.add(p.getLocation());
scaleS.add(p.getScale());
angleS.add(p.getAngle());
pathsS.add(p.getMinIOPath());
}
// log.info("本次print打点locations###{}###fileVO{}", p.getLocation(), JSON.toJSONString(fileVO));
});
/*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);*/
locationO.removeAll(Collections.singleton(null));
scaleO.removeAll(Collections.singleton(null));
angleO.removeAll(Collections.singleton(null));
pathsO.removeAll(Collections.singleton(null));
printOverall.setLocation(locationO);
printOverall.setPrint_scale_list(scaleO);
printOverall.setPrint_angle_list(angleO);
printOverall.setPrint_path_list(pathsO);
// 注意:如果 printOverall 中需要设置单印数据,请在这里添加相应的 setter
// 根据您的原始代码,似乎只设置了 overall非单印的数据
// 如果需要设置单印,请取消下面的注释并添加对应的字段
// printOverall.setSingleLocation(locationS);
// printOverall.setSingleScale(scaleS);
// printOverall.setSingleAngle(angleS);
// printOverall.setSinglePath(pathsS);
}
// 4. 处理非单印数据(整体印花)
if (!overallPrints.isEmpty()) {
List<List<Float>> locationO = new ArrayList<>();
List<List<Float>> scaleO = new ArrayList<>();
List<Double> angleO = new ArrayList<>();
List<String> pathsO = new ArrayList<>();
for (DesignSinglePrint p : overallPrints) {
setUriToMinioPath(p);
locationO.add(p.getLocation());
scaleO.add(p.getScale());
angleO.add(p.getAngle());
pathsO.add(p.getMinIOPath());
}
printOverall.setLocation(locationO);
printOverall.setPrint_scale_list(scaleO);
printOverall.setPrint_angle_list(angleO);
printOverall.setPrint_path_list(pathsO);
}
return printToPython;
}

View File

@@ -3,6 +3,7 @@ package com.ai.da.service;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.model.vo.CheckOTPVO;
import com.ai.da.model.vo.ContestantCountVO;
import com.ai.da.model.vo.PageVisitCountVO;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@@ -46,6 +47,22 @@ public interface GlobalAwardService {
* @return 参赛者数量和最大参赛者编号
*/
ContestantCountVO getContestantCount();
/**
* 记录比赛页面的访问量
* <ul>
* <li>rawVisitCount: 每次访问或刷新都计一次(不去重)</li>
* <li>uniqueVisitCount: 5秒内刷新只算一次基于会话去重</li>
* </ul>
* @param sessionId 会话ID用于5秒去重判断
*/
void recordPageVisit(String sessionId);
/**
* 获取比赛页面的两种访问量
* @return 原始访问量和去重访问量
*/
PageVisitCountVO getPageVisitCount();
}

View File

@@ -1553,11 +1553,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
if (imagePath != null) {
requestBuilder.image(finalImagePath1);
}
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)) {
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)|| useModel.equals(ModelConstants.PRINTBOARD_HIGH_T2I)) {
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的常量做替代
//由于PRINTBOARD_HIGH_T2I,PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致为了区别积分扣除PRINTBOARD_HIGH_I2I加入了-fast或者-high,但传入模型时需要去掉-fast或者-high用PRINTBOARD_ADVANCED_I2I的常量做替代
requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I);
}

View File

@@ -13,6 +13,7 @@ import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.model.dto.PublishSysNotificationDTO;
import com.ai.da.model.vo.CheckOTPVO;
import com.ai.da.model.vo.ContestantCountVO;
import com.ai.da.model.vo.PageVisitCountVO;
import com.ai.da.service.GlobalAwardService;
import com.ai.da.service.MessageCenterService;
import com.alibaba.fastjson.JSON;
@@ -619,6 +620,37 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
private String nullSafe(String value) {
return value != null ? value : "N/A";
}
private static final String RAW_VISIT_COUNT_KEY = "GLOBAL_AWARD:visit:raw";
private static final String UNIQUE_VISIT_SET_KEY = "GLOBAL_AWARD:visit:unique";
private static final String SESSION_VISIT_KEY_PREFIX = "GLOBAL_AWARD:visit:session:";
private static final long SESSION_DEDUP_SECONDS = 5L;
@Override
public void recordPageVisit(String sessionId) {
redisUtil.increaseCount(RAW_VISIT_COUNT_KEY);
if (StringUtils.isNotBlank(sessionId)) {
String sessionKey = SESSION_VISIT_KEY_PREFIX + sessionId;
if (!redisUtil.hasKey(sessionKey)) {
redisUtil.increaseCount(UNIQUE_VISIT_SET_KEY);
redisUtil.addToString(sessionKey, "1", SESSION_DEDUP_SECONDS);
}
} else {
redisUtil.increaseCount(UNIQUE_VISIT_SET_KEY);
}
}
@Override
public PageVisitCountVO getPageVisitCount() {
Long raw = redisUtil.getIncrementCount(RAW_VISIT_COUNT_KEY);
Long unique = redisUtil.getIncrementCount(UNIQUE_VISIT_SET_KEY);
return PageVisitCountVO.builder()
.rawVisitCount(raw != null ? raw : 0L)
.uniqueVisitCount(unique != null ? unique : 0L)
.build();
}
}

View File

@@ -137,9 +137,7 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
long now = Instant.now().getEpochSecond();
boolean inPeriod = now > passedInfo.getCurrentPeriodStart() && now < passedInfo.getCurrentPeriodEnd();
// 续订失败的场景可能订单状态已被更新为past_due
boolean validStatus = "fail_renewal".equals(type)
? ("past_due".equals(passedInfo.getStatus()) || "active".equals(passedInfo.getStatus()))
: "active".equals(passedInfo.getStatus());
boolean validStatus = "past_due".equals(passedInfo.getStatus()) || "active".equals(passedInfo.getStatus());
if (inPeriod && validStatus) {
return passedInfo;
}
@@ -357,7 +355,9 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
params.setEmail(account.getUserEmail());
params.setCountry(paymentInfo.getCountry());
params.setOrderId(paymentInfo.getId().toString());
params.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
// params.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
params.setOrderRef("\"" + paymentInfo.getHostedInvoiceUrl() + "\"");
params.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " "));
params.setQuantity("1");
params.setTotalFee(paymentInfo.getPayerTotal() != null ? paymentInfo.getPayerTotal().toString() : "0");