Compare commits
28 Commits
23716984cc
...
dev/3.1_re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
921d2d956e | ||
|
|
d700f94f9d | ||
|
|
b277479e73 | ||
|
|
83cbd57dea | ||
|
|
4d3b22de82 | ||
|
|
6b5c2cfec0 | ||
|
|
b676de054a | ||
|
|
4c169ef67e | ||
|
|
f2bce066b6 | ||
|
|
6af442eb15 | ||
|
|
768df55309 | ||
|
|
f351277b73 | ||
|
|
a799162ea4 | ||
|
|
c035eb9d7d | ||
|
|
906a54b3c8 | ||
|
|
643799546b | ||
|
|
f582464cd3 | ||
|
|
b864b393bc | ||
|
|
c03a8762e7 | ||
|
|
cb87ad1099 | ||
|
|
fb229764f8 | ||
|
|
8bec1f842d | ||
|
|
b54bd04cff | ||
|
|
b4ccad6242 | ||
|
|
6068bf7d7d | ||
|
|
d36baf747f | ||
| 7c8f1bee6a | |||
|
|
62bd145e2c |
111
.gitea/workflows/develop_3.1_MS_build_manual.yaml
Normal file
111
.gitea/workflows/develop_3.1_MS_build_manual.yaml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
name: 手动 AiDA back-java 开发分支构建部署
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_deploy:
|
||||||
|
runs-on: java21
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
build_status: ${{ job.status }}
|
||||||
|
build_url: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/DevelopVersion/develop-MS-version-aida-back
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 0.记录开始时间
|
||||||
|
id: build_start_time
|
||||||
|
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 1.检出代码
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: dev/3.1_release_merge_MS
|
||||||
|
|
||||||
|
|
||||||
|
- name: 3.缓存 Maven 依赖
|
||||||
|
uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
path: ~/.m2/repository
|
||||||
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-maven-
|
||||||
|
|
||||||
|
- name: 4.构建项目
|
||||||
|
run: |
|
||||||
|
java -version
|
||||||
|
mvn -v
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
|
||||||
|
- name: 5.生成Dockerfile
|
||||||
|
run: |
|
||||||
|
echo "===== 生成Dockerfile ====="
|
||||||
|
cat > Dockerfile << 'EOF'
|
||||||
|
FROM openjdk:21-ea-21-jdk-slim
|
||||||
|
VOLUME /tmp
|
||||||
|
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||||
|
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||||
|
ADD ./target/aida-0.0.1-SNAPSHOT.jar /app.jar
|
||||||
|
ENTRYPOINT ["java","-jar","/app.jar"]
|
||||||
|
EOF
|
||||||
|
echo "Dockerfile内容:"
|
||||||
|
cat Dockerfile
|
||||||
|
|
||||||
|
- name: 6.生成docker-compose.yml
|
||||||
|
run: |
|
||||||
|
echo "===== 生成docker-compose.yml ====="
|
||||||
|
cat > docker-compose.yml << 'EOF'
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
aida_back:
|
||||||
|
container_name: develop-aida-ms
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
# 数据挂载
|
||||||
|
- ./log:/log
|
||||||
|
- ./temp:/temp
|
||||||
|
- ./uploads:/temp/uploads
|
||||||
|
ports:
|
||||||
|
- '10092:10092'
|
||||||
|
restart: always
|
||||||
|
EOF
|
||||||
|
# 验证docker-compose.yml生成
|
||||||
|
echo "docker-compose.yml内容:"
|
||||||
|
cat docker-compose.yml
|
||||||
|
|
||||||
|
- name: 7.上传jar到远程服务器
|
||||||
|
uses: appleboy/scp-action@master
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
|
port: 22
|
||||||
|
username: ${{ secrets.SERVER_USER }}
|
||||||
|
key: ${{ secrets.SSH_KEY }}
|
||||||
|
source: "target/*.jar,Dockerfile,docker-compose.yml"
|
||||||
|
target: ${{ env.REMOTE_DEPLOY_PATH }}
|
||||||
|
preserve_host_directory_structure: false
|
||||||
|
|
||||||
|
- name: 8. 重启 Docker 服务
|
||||||
|
uses: appleboy/ssh-action@master # 👈 专门执行命令的 action
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
|
username: ${{ secrets.SERVER_USER }}
|
||||||
|
key: ${{ secrets.SSH_KEY }}
|
||||||
|
key_base64: true
|
||||||
|
script: |
|
||||||
|
echo "========= 进入部署目录 ========="
|
||||||
|
cd ${{ env.REMOTE_DEPLOY_PATH }}
|
||||||
|
ls -l
|
||||||
|
|
||||||
|
echo "========= 停止旧服务 ========="
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
echo "========= 启动新服务 ========="
|
||||||
|
docker compose up -d --build
|
||||||
|
|
||||||
|
echo "========= 查看运行状态 ========="
|
||||||
|
docker compose ps
|
||||||
@@ -103,7 +103,13 @@ jobs:
|
|||||||
- ./uploads:/temp/uploads
|
- ./uploads:/temp/uploads
|
||||||
ports:
|
ports:
|
||||||
- '10090:5567'
|
- '10090:5567'
|
||||||
|
networks:
|
||||||
|
- aida_java_net
|
||||||
restart: always
|
restart: always
|
||||||
|
networks:
|
||||||
|
aida_java_net:
|
||||||
|
external: true
|
||||||
|
name: aida_java_net
|
||||||
EOF
|
EOF
|
||||||
# 验证docker-compose.yml生成
|
# 验证docker-compose.yml生成
|
||||||
echo "docker-compose.yml内容:"
|
echo "docker-compose.yml内容:"
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@@ -263,6 +263,12 @@
|
|||||||
<version>2.15.1</version>
|
<version>2.15.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.stripe</groupId>
|
<groupId>com.stripe</groupId>
|
||||||
<artifactId>stripe-java</artifactId>
|
<artifactId>stripe-java</artifactId>
|
||||||
|
|||||||
@@ -559,83 +559,83 @@ public class GenerateConsumer {
|
|||||||
log.info("============ProcessPoseTransformResult End listening==========");
|
log.info("============ProcessPoseTransformResult End listening==========");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer1(Message msg, Channel channel) {
|
// public void generateConsumer1(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 1");
|
// generate(msg, channel, "consumer 1");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer2(Message msg, Channel channel) {
|
// public void generateConsumer2(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 2");
|
// generate(msg, channel, "consumer 2");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer3(Message msg, Channel channel) {
|
// public void generateConsumer3(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 3");
|
// generate(msg, channel, "consumer 3");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer4(Message msg, Channel channel) {
|
// public void generateConsumer4(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 4");
|
// generate(msg, channel, "consumer 4");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer5(Message msg, Channel channel) {
|
// public void generateConsumer5(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 5");
|
// generate(msg, channel, "consumer 5");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer6(Message msg, Channel channel) {
|
// public void generateConsumer6(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 6");
|
// generate(msg, channel, "consumer 6");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer7(Message msg, Channel channel) {
|
// public void generateConsumer7(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 7");
|
// generate(msg, channel, "consumer 7");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer8(Message msg, Channel channel) {
|
// public void generateConsumer8(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 8");
|
// generate(msg, channel, "consumer 8");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void generateConsumer9(Message msg, Channel channel) {
|
// public void generateConsumer9(Message msg, Channel channel) {
|
||||||
generate(msg, channel, "consumer 9");
|
// generate(msg, channel, "consumer 9");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.generateResult}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generateResult}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void getGenerateResult(Message msg, Channel channel) {
|
// public void getGenerateResult(Message msg, Channel channel) {
|
||||||
processGenerateResult(msg, channel);
|
// processGenerateResult(msg, channel);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageResult}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageResult}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void getToProductImageResult(Message msg, Channel channel) {
|
// public void getToProductImageResult(Message msg, Channel channel) {
|
||||||
processToProductImageResult(msg, channel);
|
// processToProductImageResult(msg, channel);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.relightResult}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.relightResult}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void getRelightResult(Message msg, Channel channel) {
|
// public void getRelightResult(Message msg, Channel channel) {
|
||||||
processRelightResult(msg, channel);
|
// processRelightResult(msg, channel);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void getPoseTransformationResult(Message msg, Channel channel) {
|
// public void getPoseTransformationResult(Message msg, Channel channel) {
|
||||||
processPoseTransformResult(msg, channel);
|
// processPoseTransformResult(msg, channel);
|
||||||
}
|
// }
|
||||||
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
|
||||||
// @RabbitHandler
|
// @RabbitHandler
|
||||||
// public void getDesignBatchResult(Message msg, Channel channel) {
|
// public void getDesignBatchResult(Message msg, Channel channel) {
|
||||||
|
|||||||
@@ -222,16 +222,16 @@ public class SRConsumer {
|
|||||||
taskListService.updateTaskStatusOrOutputRedis(uniqueId, "fail", null);
|
taskListService.updateTaskStatusOrOutputRedis(uniqueId, "fail", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.sr}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.sr}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void SRConsumer1(Message msg, Channel channel) {
|
// public void SRConsumer1(Message msg, Channel channel) {
|
||||||
superResolution(msg, channel, "consumer 1");
|
// superResolution(msg, channel, "consumer 1");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@RabbitListener(queues = "#{rabbitMQProperties.queues.srResult}")
|
// @RabbitListener(queues = "#{rabbitMQProperties.queues.srResult}")
|
||||||
@RabbitHandler
|
// @RabbitHandler
|
||||||
public void SRResultConsumer1(Message msg, Channel channel) {
|
// public void SRResultConsumer1(Message msg, Channel channel) {
|
||||||
getSRResult(msg, channel, "consumer 1");
|
// getSRResult(msg, channel, "consumer 1");
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import com.ai.da.common.response.Response;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.ai.da.common.response.ResultEnum;
|
import com.ai.da.common.response.ResultEnum;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: dangweijian
|
* @author: dangweijian
|
||||||
@@ -36,6 +38,14 @@ public class ExceptionCatch {
|
|||||||
return Response.error(e.getCode(), e.getMsg());
|
return Response.error(e.getCode(), e.getMsg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
|
@ExceptionHandler(UnauthorizedException.class)
|
||||||
|
public Response<String> unauthorizedExceptionCatch(UnauthorizedException e) {
|
||||||
|
log.error("Unauthorized: {}", e.getMessage());
|
||||||
|
return Response.error(401, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public Response<String> exceptionCatch(Exception e) {
|
public Response<String> exceptionCatch(Exception e) {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.ai.da.common.config.exception;
|
||||||
|
|
||||||
|
public class UnauthorizedException extends RuntimeException {
|
||||||
|
|
||||||
|
public UnauthorizedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException() {
|
||||||
|
super("Gateway token verification failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ public class CommonConstant {
|
|||||||
// 单位 秒 两天过期
|
// 单位 秒 两天过期
|
||||||
public static final Long CREDITS_EXPIRE_TIME = 2 * 24 * 60 * 60L;
|
public static final Long CREDITS_EXPIRE_TIME = 2 * 24 * 60 * 60L;
|
||||||
// 单位 分钟
|
// 单位 分钟
|
||||||
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
|
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60 * 7;
|
||||||
// 单位 秒 一天过期 in redis
|
// 单位 秒 一天过期 in redis
|
||||||
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
|
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
|
||||||
// 单位 秒 7天过期
|
// 单位 秒 7天过期
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ public class ModelConstants {
|
|||||||
|
|
||||||
// 模型名称常量
|
// 模型名称常量
|
||||||
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
|
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 MOODBOARD_ADVANCED = "doubao-seedream-4-5-251128";
|
||||||
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
|
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_HIGH_I2I = "doubao-seedream-4-0-250828-fast";
|
||||||
public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
|
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 IMAGEN_MODEL = "imagen-4.0-generate-001";
|
||||||
|
|||||||
@@ -3,17 +3,39 @@ package com.ai.da.common.context;
|
|||||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||||
|
|
||||||
public class UserContext {
|
public class UserContext {
|
||||||
private static ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<AuthPrincipalVo>();
|
private static final ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
|
||||||
|
userHolder.set(authPrincipalVo);
|
||||||
|
}
|
||||||
|
|
||||||
public static AuthPrincipalVo getUserHolder() {
|
public static AuthPrincipalVo getUserHolder() {
|
||||||
return userHolder.get();
|
AuthPrincipalVo holder = userHolder.get();
|
||||||
|
if (holder == null) {
|
||||||
|
throw new RuntimeException("User not authenticated");
|
||||||
|
}
|
||||||
|
if (!"AIDA".equals(holder.getSource())) {
|
||||||
|
throw new RuntimeException("Access denied: source must be AIDA");
|
||||||
|
}
|
||||||
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void delete() {
|
public static void delete() {
|
||||||
userHolder.remove();
|
userHolder.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
|
public static Long getUserId() {
|
||||||
userHolder.set(authPrincipalVo);
|
return getUserHolder().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getBuyerId() {
|
||||||
|
AuthPrincipalVo holder = userHolder.get();
|
||||||
|
if (holder == null) {
|
||||||
|
throw new RuntimeException("User not authenticated");
|
||||||
|
}
|
||||||
|
if (!"BUYER".equals(holder.getSource())) {
|
||||||
|
throw new RuntimeException("Access denied: source must be BUYER");
|
||||||
|
}
|
||||||
|
return holder.getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class AccountTask {
|
|||||||
* 每个月月初只刷新教育子账号的积分
|
* 每个月月初只刷新教育子账号的积分
|
||||||
*/
|
*/
|
||||||
// @Scheduled(cron = "0 25 14 * * ?")
|
// @Scheduled(cron = "0 25 14 * * ?")
|
||||||
@Scheduled(cron = "0 0 0 1 * ?")
|
// @Scheduled(cron = "0 0 0 1 * ?")
|
||||||
public void refreshCreditsMonthly() {
|
public void refreshCreditsMonthly() {
|
||||||
log.info("每月1号0点 重置教育版子账号为默认积分");
|
log.info("每月1号0点 重置教育版子账号为默认积分");
|
||||||
accountService.refreshCreditsMonthly();
|
accountService.refreshCreditsMonthly();
|
||||||
@@ -54,7 +54,7 @@ public class AccountTask {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// 每天检测正式用户到期情况,每天凌晨0点执行
|
// 每天检测正式用户到期情况,每天凌晨0点执行
|
||||||
@Scheduled(cron = "0 0 0 * * ?")
|
// @Scheduled(cron = "0 0 0 * * ?")
|
||||||
public void paidUserToVisitor() {
|
public void paidUserToVisitor() {
|
||||||
// 1、查询当前已过期正式用户或试用用户
|
// 1、查询当前已过期正式用户或试用用户
|
||||||
List<Account> accountList = accountService.getExpiredUserBySystemUser(1);
|
List<Account> accountList = accountService.getExpiredUserBySystemUser(1);
|
||||||
@@ -77,7 +77,7 @@ public class AccountTask {
|
|||||||
accountService.registerUserToVisitor();
|
accountService.registerUserToVisitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 0 0 1 * ?")
|
// @Scheduled(cron = "0 0 0 1 * ?")
|
||||||
// 每月初刷新所有用户用户名剩余修改次数
|
// 每月初刷新所有用户用户名剩余修改次数
|
||||||
public void resetUsernameModifyTimes(){
|
public void resetUsernameModifyTimes(){
|
||||||
log.info("重置所有用户的用户名修改次数");
|
log.info("重置所有用户的用户名修改次数");
|
||||||
@@ -85,17 +85,17 @@ public class AccountTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 35 14 * * ?")
|
// @Scheduled(cron = "0 35 14 * * ?")
|
||||||
@Scheduled(cron = "0 5 0 * * ?")
|
// @Scheduled(cron = "0 5 0 * * ?")
|
||||||
public void checkEduAdminExpireStatus() {
|
public void checkEduAdminExpireStatus() {
|
||||||
accountService.checkEduAdminExpireStatus();
|
accountService.checkEduAdminExpireStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 5 0 * * ?")
|
// @Scheduled(cron = "0 5 0 * * ?")
|
||||||
public void activeSubscriptionPlan() {
|
public void activeSubscriptionPlan() {
|
||||||
subscriptionPlanService.activeSubscriptionPlan(null);
|
subscriptionPlanService.activeSubscriptionPlan(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||||
public void expireSubscription() {
|
public void expireSubscription() {
|
||||||
subscriptionPlanService.expireSubscription();
|
subscriptionPlanService.expireSubscription();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class GenerateTask {
|
|||||||
* 故这里通过定时任务做补偿
|
* 故这里通过定时任务做补偿
|
||||||
* flux五分钟查询一次,万相1小时查询一次
|
* flux五分钟查询一次,万相1小时查询一次
|
||||||
*/
|
*/
|
||||||
@Scheduled(cron = "0 */4 * * * ?")
|
// @Scheduled(cron = "0 */4 * * * ?")
|
||||||
public void fluxCompensationMechanism(){
|
public void fluxCompensationMechanism(){
|
||||||
// 1、查所有 任务还没成功、还没失败,正在等待或者执行中的任务id有哪些
|
// 1、查所有 任务还没成功、还没失败,正在等待或者执行中的任务id有哪些
|
||||||
// (由于获取结果的polling_url在redis中只存一天,大部分结果超过一天之后就无法再找到任务,小部分可以通过公共路径查到结果)
|
// (由于获取结果的polling_url在redis中只存一天,大部分结果超过一天之后就无法再找到任务,小部分可以通过公共路径查到结果)
|
||||||
@@ -98,7 +98,7 @@ public class GenerateTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 万相 -> pose transformation 补偿 当前任务执行完后,5分钟再执行一次(不会出现任务重叠的情况)
|
// 万相 -> pose transformation 补偿 当前任务执行完后,5分钟再执行一次(不会出现任务重叠的情况)
|
||||||
@Scheduled(fixedDelay = 5 * 60 * 1000)
|
// @Scheduled(fixedDelay = 5 * 60 * 1000)
|
||||||
public void wxCompensationMechanism(){
|
public void wxCompensationMechanism(){
|
||||||
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("wx");
|
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("wx");
|
||||||
if (apiGenerates != null && !apiGenerates.isEmpty()){
|
if (apiGenerates != null && !apiGenerates.isEmpty()){
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class PaymentTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 定时同步(每分钟一次)
|
// 定时同步(每分钟一次)
|
||||||
@Scheduled(fixedRate = 60000)
|
// @Scheduled(fixedRate = 60000)
|
||||||
public void syncLinkViewCountToDB(){
|
public void syncLinkViewCountToDB(){
|
||||||
affiliateService.syncLinkViewCountToDB();
|
affiliateService.syncLinkViewCountToDB();
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ public class PaymentTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||||
public void calcCouponsCommission(){
|
public void calcCouponsCommission(){
|
||||||
// log.info("优惠券佣金计算定时器");
|
// log.info("优惠券佣金计算定时器");
|
||||||
affiliateService.calcCouponsCommission();
|
affiliateService.calcCouponsCommission();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import io.netty.util.internal.StringUtil;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -41,6 +42,9 @@ public class MinioUtil {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MinioClient minioClient;
|
private MinioClient minioClient;
|
||||||
|
|
||||||
|
@Value("${minio.endpoint}")
|
||||||
|
private String endpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取MinIO客户端实例
|
* 获取MinIO客户端实例
|
||||||
*/
|
*/
|
||||||
@@ -48,6 +52,18 @@ public class MinioUtil {
|
|||||||
return minioClient;
|
return minioClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis缓存key前缀,用于Minio签名URL缓存
|
||||||
|
*/
|
||||||
|
private static final String REDIS_MINIO_URL_PREFIX = "minio:url:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名URL缓存过期时间(秒),默认1天
|
||||||
|
*/
|
||||||
|
private static final long URL_CACHE_EXPIRE_SECONDS = 24 * 60 * 60;
|
||||||
/**
|
/**
|
||||||
* description: 判断bucket是否存在,不存在则创建
|
* description: 判断bucket是否存在,不存在则创建
|
||||||
*
|
*
|
||||||
@@ -388,6 +404,11 @@ public class MinioUtil {
|
|||||||
* @return 文件的临时URL,如果出现异常则返回null
|
* @return 文件的临时URL,如果出现异常则返回null
|
||||||
*/
|
*/
|
||||||
public String getPreSignedUrl(String bucketName, String fileName, int expiry) {
|
public String getPreSignedUrl(String bucketName, String fileName, int expiry) {
|
||||||
|
String cacheKey = REDIS_MINIO_URL_PREFIX + bucketName + "/" + fileName;
|
||||||
|
Object cachedUrl = redisUtil.getFromString(cacheKey);
|
||||||
|
if (cachedUrl != null) {
|
||||||
|
return cachedUrl.toString();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String lowerName = fileName.toLowerCase();
|
String lowerName = fileName.toLowerCase();
|
||||||
@@ -415,8 +436,9 @@ public class MinioUtil {
|
|||||||
|
|
||||||
builder.extraQueryParams(queryParams);
|
builder.extraQueryParams(queryParams);
|
||||||
}
|
}
|
||||||
|
String presignedObjectUrl = minioClient.getPresignedObjectUrl(builder.build());
|
||||||
return minioClient.getPresignedObjectUrl(builder.build());
|
redisUtil.addToString(cacheKey, presignedObjectUrl, URL_CACHE_EXPIRE_SECONDS);
|
||||||
|
return presignedObjectUrl;
|
||||||
} catch (MinioException | InvalidKeyException
|
} catch (MinioException | InvalidKeyException
|
||||||
| IOException | NoSuchAlgorithmException | IllegalArgumentException e) {
|
| IOException | NoSuchAlgorithmException | IllegalArgumentException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -958,6 +980,166 @@ public class MinioUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测字符串是否为预签名URL
|
||||||
|
* 通过检查URL中是否包含minio endpoint来判断
|
||||||
|
*
|
||||||
|
* @param str 待检测的字符串
|
||||||
|
* @return true表示是预签名URL,false表示不是
|
||||||
|
*/
|
||||||
|
public boolean isPresignedUrl(String str) {
|
||||||
|
if (str == null || str.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 检查字符串是否是一个有效的URL
|
||||||
|
URL url = new URL(str);
|
||||||
|
String host = url.getHost();
|
||||||
|
// 获取endpoint中的主机部分(去掉http://或https://)
|
||||||
|
String endpointHost = endpoint;
|
||||||
|
if (endpointHost.startsWith("http://")) {
|
||||||
|
endpointHost = endpointHost.substring(7);
|
||||||
|
} else if (endpointHost.startsWith("https://")) {
|
||||||
|
endpointHost = endpointHost.substring(8);
|
||||||
|
}
|
||||||
|
// 去掉端口号
|
||||||
|
if (endpointHost.contains(":")) {
|
||||||
|
endpointHost = endpointHost.substring(0, endpointHost.indexOf(":"));
|
||||||
|
}
|
||||||
|
// 检查URL的host是否与endpoint的host匹配
|
||||||
|
return host.equals(endpointHost);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 不是有效的URL
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测字符串是否为MinIO逻辑路径(bucketName/objectName格式)
|
||||||
|
* 逻辑路径特点:
|
||||||
|
* 1. 包含 "/"(桶名和对象名之间的分隔符)
|
||||||
|
* 2. 不是完整的URL(不以http://或https://开头)
|
||||||
|
* 3. 路径中没有查询参数
|
||||||
|
*
|
||||||
|
* @param str 待检测的字符串
|
||||||
|
* @return true表示是MinIO逻辑路径,false表示不是
|
||||||
|
*/
|
||||||
|
public boolean isMinioLogicalPath(String str) {
|
||||||
|
if (str == null || str.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 必须是字符串
|
||||||
|
if (!(str instanceof String)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String trimStr = str.trim();
|
||||||
|
// 不应该以http://或https://开头
|
||||||
|
if (trimStr.startsWith("http://") || trimStr.startsWith("https://")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 应该包含 "/"(bucket/object格式)
|
||||||
|
if (!trimStr.contains("/")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 不应该包含空格或特殊字符
|
||||||
|
if (trimStr.contains(" ") || trimStr.contains("\n") || trimStr.contains("\t")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将预签名URL转换为逻辑路径
|
||||||
|
*
|
||||||
|
* @param presignedUrl 预签名URL
|
||||||
|
* @return 逻辑路径(格式:bucketName/objectName)
|
||||||
|
*/
|
||||||
|
public String getLogicalPathFromPresignedUrl(String presignedUrl) {
|
||||||
|
try {
|
||||||
|
// 解析URL
|
||||||
|
URL url = new URL(presignedUrl);
|
||||||
|
|
||||||
|
// 获取路径部分(去掉开头的/)
|
||||||
|
String path = url.getPath();
|
||||||
|
if (path.startsWith("/")) {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路径格式为 bucketName/objectName
|
||||||
|
// Minio路径中可能包含多个/,需要正确分割
|
||||||
|
int firstSlashIndex = path.indexOf("/");
|
||||||
|
if (firstSlashIndex <= 0) {
|
||||||
|
throw new MinioException("预签名URL路径格式无效,应包含桶名和对象名: " + presignedUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
String bucketName = path.substring(0, firstSlashIndex);
|
||||||
|
String objectName = path.substring(firstSlashIndex + 1);
|
||||||
|
|
||||||
|
// log.info("预签名URL转换成功,桶名: {}, 对象名: {}", bucketName, objectName);
|
||||||
|
return bucketName + "/" + objectName;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("预签名URL解析失败: {}", e.getMessage(), e);
|
||||||
|
throw new BusinessException("system.error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理MinIO资源(预签名URL或逻辑路径),统一生成预签名URL
|
||||||
|
*
|
||||||
|
* @param resource 预签名URL或逻辑路径
|
||||||
|
* @param expires 过期时间(秒)
|
||||||
|
* @return 新的预签名URL
|
||||||
|
*/
|
||||||
|
public String processMinioResource(String resource, int expires) {
|
||||||
|
try {
|
||||||
|
String logicalPath;
|
||||||
|
if (isPresignedUrl(resource)) {
|
||||||
|
// 是预签名URL,解析为逻辑路径
|
||||||
|
logicalPath = getLogicalPathFromPresignedUrl(resource);
|
||||||
|
} else if (isMinioLogicalPath(resource)) {
|
||||||
|
// 本身就是逻辑路径
|
||||||
|
logicalPath = resource.trim();
|
||||||
|
} else {
|
||||||
|
// 不认识的内容,直接返回原始值
|
||||||
|
log.warn("未识别的MinIO资源格式: {}", resource);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一生成预签名URL
|
||||||
|
return getPreSignedUrl(logicalPath, expires);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理MinIO资源失败: {}, error: {}", resource, e.getMessage(), e);
|
||||||
|
// 如果失败,返回原始内容
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将任意MinIO URL转换为逻辑路径
|
||||||
|
* 检测URL类型并转换为逻辑路径返回
|
||||||
|
*
|
||||||
|
* @param url 预签名URL或逻辑路径
|
||||||
|
* @return 逻辑路径(格式:bucketName/objectName)
|
||||||
|
* @throws MinioException 如果不是有效的MinIO资源
|
||||||
|
*/
|
||||||
|
public String convertToLogicalPath(String url) {
|
||||||
|
if (url == null || url.isEmpty()) {
|
||||||
|
throw new BusinessException("url.cannot.be.empty");
|
||||||
|
}
|
||||||
|
if (isMinioLogicalPath(url)) {
|
||||||
|
// 本身就是逻辑路径,直接返回
|
||||||
|
return url.trim();
|
||||||
|
} else if (isPresignedUrl(url)) {
|
||||||
|
// 是预签名URL,转换为逻辑路径
|
||||||
|
return getLogicalPathFromPresignedUrl(url);
|
||||||
|
} else {
|
||||||
|
// 不认识的内容,抛出异常
|
||||||
|
throw new BusinessException("无法识别的MinIO资源格式: " + url + ",请提供有效的预签名URL或逻辑路径");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class PythonService {
|
|||||||
@Value("${access.python.generate_sr_port}")
|
@Value("${access.python.generate_sr_port}")
|
||||||
private String srServicePort;
|
private String srServicePort;
|
||||||
|
|
||||||
@Value("${design.callback.url}")
|
@Value("${design.callback.url.aida}")
|
||||||
private String callbackUrl;
|
private String callbackUrl;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
|||||||
37
src/main/java/com/ai/da/seller/DesignUrlsDTO.java
Normal file
37
src/main/java/com/ai/da/seller/DesignUrlsDTO.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package com.ai.da.seller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设计URLs DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "设计URLs数据传输对象")
|
||||||
|
public class DesignUrlsDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设计项ID
|
||||||
|
*/
|
||||||
|
@Schema(description = "设计项ID", example = "1")
|
||||||
|
private Long designItemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TO_PRODUCT_IMAGE类型的URL列表
|
||||||
|
*/
|
||||||
|
@Schema(description = "TO_PRODUCT_IMAGE类型的URL列表")
|
||||||
|
private List<String> toProductImageUrls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DesignItemDetail的path列表
|
||||||
|
*/
|
||||||
|
@Schema(description = "DesignItemDetail的path列表")
|
||||||
|
private List<String> clothes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 姿势转换视频信息列表
|
||||||
|
*/
|
||||||
|
@Schema(description = "姿势转换视频信息列表")
|
||||||
|
private List<PoseTransformationVideoDTO> videos;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ai.da.seller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 姿势转换视频信息DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "姿势转换视频信息数据传输对象")
|
||||||
|
public class PoseTransformationVideoDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GIF第一帧截图URL
|
||||||
|
*/
|
||||||
|
@Schema(description = "GIF第一帧截图URL")
|
||||||
|
private String firstFrameUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GIF视频URL
|
||||||
|
*/
|
||||||
|
@Schema(description = "GIF视频URL")
|
||||||
|
private String gifUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频URL
|
||||||
|
*/
|
||||||
|
@Schema(description = "视频URL")
|
||||||
|
private String videoUrl;
|
||||||
|
}
|
||||||
44
src/main/java/com/ai/da/seller/SellerController.java
Normal file
44
src/main/java/com/ai/da/seller/SellerController.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package com.ai.da.seller;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.Response;
|
||||||
|
import com.ai.da.service.UserLikeGroupService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seller Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/seller")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "Seller", description = "Seller相关接口")
|
||||||
|
public class SellerController {
|
||||||
|
|
||||||
|
private final UserLikeGroupService userLikeGroupService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据designItemId列表获取设计相关的URL列表
|
||||||
|
* @param designItemIds designItemId列表
|
||||||
|
* @return 设计URLs DTO列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/sketchDetail")
|
||||||
|
@Operation(summary = "获取设计相关URL列表", description = "根据designItemId列表获取设计相关的URL列表,包括TO_PRODUCT_IMAGE类型的URL和DesignItemDetail的path列表")
|
||||||
|
public Response<List<DesignUrlsDTO>> getDesignUrlsByDesignItemIds(
|
||||||
|
@Parameter(description = "设计项ID列表", required = true, example = "1,2,3")
|
||||||
|
@RequestParam List<Long> designItemIds) {
|
||||||
|
List<DesignUrlsDTO> designUrlsDTOList = new ArrayList<>();
|
||||||
|
for (Long designItemId : designItemIds) {
|
||||||
|
DesignUrlsDTO designUrlsDTO = userLikeGroupService.getToProductImageUrlsByDesignItemId(designItemId);
|
||||||
|
designUrlsDTOList.add(designUrlsDTO);
|
||||||
|
}
|
||||||
|
return Response.success(designUrlsDTOList);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.ai.da.common.response.PageBaseResponse;
|
|||||||
import com.ai.da.mapper.primary.entity.*;
|
import com.ai.da.mapper.primary.entity.*;
|
||||||
import com.ai.da.model.dto.*;
|
import com.ai.da.model.dto.*;
|
||||||
import com.ai.da.model.vo.*;
|
import com.ai.da.model.vo.*;
|
||||||
|
import com.ai.da.seller.DesignUrlsDTO;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
@@ -121,4 +122,11 @@ public interface UserLikeGroupService extends IService<UserLikeGroup> {
|
|||||||
Boolean toProductImageElementDelete(Long id);
|
Boolean toProductImageElementDelete(Long id);
|
||||||
|
|
||||||
ToProductElementVO convertRelightElement(Long id);
|
ToProductElementVO convertRelightElement(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据designItemId获取TO_PRODUCT_IMAGE类型的URL列表和DesignItemDetail的path列表
|
||||||
|
* @param designItemId designItemId
|
||||||
|
* @return 包含TO_PRODUCT_IMAGE类型的URL列表和DesignItemDetail的path列表的对象
|
||||||
|
*/
|
||||||
|
DesignUrlsDTO getToProductImageUrlsByDesignItemId(Long designItemId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
principal.setUsername(account.getUserName());
|
principal.setUsername(account.getUserName());
|
||||||
principal.setLanguage(account.getLanguage());
|
principal.setLanguage(account.getLanguage());
|
||||||
principal.setCountry(account.getCountry());
|
principal.setCountry(account.getCountry());
|
||||||
|
//区分买家端登录
|
||||||
|
principal.setSource("AIDA");
|
||||||
String token2 = tokenGenerateUtils.createToken(principal);
|
String token2 = tokenGenerateUtils.createToken(principal);
|
||||||
// 本地 JVM 缓存(适配旧逻辑)
|
// 本地 JVM 缓存(适配旧逻辑)
|
||||||
LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
|
LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
|
||||||
|
|||||||
@@ -1553,11 +1553,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
|||||||
if (imagePath != null) {
|
if (imagePath != null) {
|
||||||
requestBuilder.image(finalImagePath1);
|
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();
|
GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions();
|
||||||
optimizePromptOptions.setMode("fast");
|
optimizePromptOptions.setMode("fast");
|
||||||
requestBuilder.optimizePromptOptions(optimizePromptOptions);
|
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);
|
requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4225,8 +4225,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送POST请求到Flux API
|
// 发送POST请求到Flux API
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
String resp = sendRequestUtil.sendFluxPost(fluxRequestUrl, requestBody.toString());
|
String resp = sendRequestUtil.sendFluxPost(fluxRequestUrl, requestBody.toString());
|
||||||
JSONObject respObj = JSONUtil.parseObj(resp);
|
JSONObject respObj = JSONUtil.parseObj(resp);
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
log.info("flux 耗时:{}ms", end - start);
|
||||||
log.info("flux 发起生成请求返回结果: {}", respObj);
|
log.info("flux 发起生成请求返回结果: {}", respObj);
|
||||||
|
|
||||||
// 从响应中提取任务ID
|
// 从响应中提取任务ID
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import com.ai.da.model.enums.Module;
|
|||||||
import com.ai.da.model.vo.*;
|
import com.ai.da.model.vo.*;
|
||||||
import com.ai.da.python.PythonService;
|
import com.ai.da.python.PythonService;
|
||||||
import com.ai.da.service.*;
|
import com.ai.da.service.*;
|
||||||
|
import com.ai.da.seller.DesignUrlsDTO;
|
||||||
|
import com.ai.da.seller.PoseTransformationVideoDTO;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
@@ -31,6 +33,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
@@ -61,6 +64,8 @@ import java.time.ZoneId;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.ai.da.common.enums.LayersPriorityEnum.BODY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务实现类
|
* 服务实现类
|
||||||
*
|
*
|
||||||
@@ -71,6 +76,89 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, UserLikeGroup> implements UserLikeGroupService {
|
public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, UserLikeGroup> implements UserLikeGroupService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据CollectionSort ID查询子记录,将TO_PRODUCT_IMAGE类型的URL和姿势转换视频信息写入DesignUrlsDTO
|
||||||
|
* @param collectionSortId CollectionSort ID
|
||||||
|
* @param designUrlsDTO DesignUrlsDTO,用于收集图片URL和视频信息
|
||||||
|
*/
|
||||||
|
private void getToProductImageUrlsByCollectionSortId(Long collectionSortId, DesignUrlsDTO designUrlsDTO) {
|
||||||
|
// 查询子记录中的TO_PRODUCT_IMAGE类型
|
||||||
|
QueryWrapper<CollectionSort> childCollectionQw = new QueryWrapper<>();
|
||||||
|
childCollectionQw.lambda().eq(CollectionSort::getParentId, collectionSortId);
|
||||||
|
childCollectionQw.lambda().in(CollectionSort::getRelationType, CollectionType.TO_PRODUCT_IMAGE.getValue(), CollectionType.RELIGHT.getValue(), CollectionType.POSE_TRANSFORM.getValue());
|
||||||
|
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
||||||
|
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||||
|
|
||||||
|
for (CollectionSort userLikeSort : childSortList) {
|
||||||
|
if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())){
|
||||||
|
PoseTransformation poseTransformation = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
||||||
|
if (poseTransformation != null) {
|
||||||
|
PoseTransformationVideoDTO videoDTO = new PoseTransformationVideoDTO();
|
||||||
|
videoDTO.setFirstFrameUrl(minioUtil.processMinioResource(poseTransformation.getFirstFrameUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
|
||||||
|
videoDTO.setGifUrl(minioUtil.processMinioResource(poseTransformation.getGifUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
|
||||||
|
videoDTO.setVideoUrl(minioUtil.processMinioResource(poseTransformation.getVideoUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
|
||||||
|
designUrlsDTO.getVideos().add(videoDTO);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
|
if (toProductImageResult != null && !isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
String url = toProductImageResult.getUrl();
|
||||||
|
designUrlsDTO.getToProductImageUrls().add(minioUtil.processMinioResource(url, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据designItemId获取TO_PRODUCT_IMAGE类型的URL列表和DesignItemDetail的path列表
|
||||||
|
* @param designItemId designItemId
|
||||||
|
* @return 包含TO_PRODUCT_IMAGE类型的URL列表和DesignItemDetail的path列表的对象
|
||||||
|
*/
|
||||||
|
public DesignUrlsDTO getToProductImageUrlsByDesignItemId(Long designItemId) {
|
||||||
|
DesignUrlsDTO designUrlsDTO = new DesignUrlsDTO();
|
||||||
|
designUrlsDTO.setDesignItemId(designItemId);
|
||||||
|
designUrlsDTO.setVideos(new ArrayList<>());
|
||||||
|
designUrlsDTO.setToProductImageUrls(new ArrayList<>());
|
||||||
|
designUrlsDTO.setClothes(new ArrayList<>());
|
||||||
|
|
||||||
|
// 根据designItemId查询UserLike
|
||||||
|
QueryWrapper<UserLike> userLikeQueryWrapper = new QueryWrapper<>();
|
||||||
|
userLikeQueryWrapper.lambda().eq(UserLike::getDesignItemId, designItemId);
|
||||||
|
UserLike userLike = userLikeMapper.selectOne(userLikeQueryWrapper);
|
||||||
|
|
||||||
|
if (userLike != null) {
|
||||||
|
// 根据UserLike的ID查询CollectionSort
|
||||||
|
QueryWrapper<CollectionSort> collectionSortQueryWrapper = new QueryWrapper<>();
|
||||||
|
collectionSortQueryWrapper.lambda().eq(CollectionSort::getRelationId, userLike.getId());
|
||||||
|
collectionSortQueryWrapper.lambda().eq(CollectionSort::getRelationType, CollectionType.DESIGN.getValue());
|
||||||
|
CollectionSort collectionSort = collectionSortMapper.selectOne(collectionSortQueryWrapper);
|
||||||
|
|
||||||
|
if (collectionSort != null) {
|
||||||
|
// 获取TO_PRODUCT_IMAGE类型的URL列表
|
||||||
|
getToProductImageUrlsByCollectionSortId(collectionSort.getId(), designUrlsDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询DesignItemDetail表,排除type为"Body"的数据
|
||||||
|
QueryWrapper<DesignItemDetail> designItemDetailQueryWrapper = new QueryWrapper<>();
|
||||||
|
designItemDetailQueryWrapper.lambda().eq(DesignItemDetail::getDesignItemId, designItemId);
|
||||||
|
designItemDetailQueryWrapper.lambda().ne(DesignItemDetail::getType, BODY.getType());
|
||||||
|
List<DesignItemDetail> designItemDetails = designItemDetailMapper.selectList(designItemDetailQueryWrapper);
|
||||||
|
|
||||||
|
for (DesignItemDetail designItemDetail : designItemDetails) {
|
||||||
|
// 判断当前用户是否是DesignItemDetail的创建者
|
||||||
|
if (!Objects.equals(designItemDetail.getAccountId(), UserContext.getUserHolder().getId())){
|
||||||
|
throw new BusinessException("unknown.authentication.operation.type");
|
||||||
|
}
|
||||||
|
if (designItemDetail.getPath() != null) {
|
||||||
|
designUrlsDTO.getClothes().add(minioUtil.processMinioResource(designItemDetail.getPath(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return designUrlsDTO;
|
||||||
|
}
|
||||||
|
|
||||||
private final UserLikeGroupMapper userLikeGroupMapper;
|
private final UserLikeGroupMapper userLikeGroupMapper;
|
||||||
private final AccountMapper accountMapper;
|
private final AccountMapper accountMapper;
|
||||||
private final CollectionService collectionService;
|
private final CollectionService collectionService;
|
||||||
@@ -87,6 +175,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
private final PortfolioMapper portfolioMapper;
|
private final PortfolioMapper portfolioMapper;
|
||||||
private final TagsMapper tagsMapper;
|
private final TagsMapper tagsMapper;
|
||||||
private final DesignItemDetailService designItemDetailService;
|
private final DesignItemDetailService designItemDetailService;
|
||||||
|
private final DesignItemDetailMapper designItemDetailMapper;
|
||||||
private final CollectionElementMapper collectionElementMapper;
|
private final CollectionElementMapper collectionElementMapper;
|
||||||
private final AttributeRetrievalMapper attributeRetrievalMapper;
|
private final AttributeRetrievalMapper attributeRetrievalMapper;
|
||||||
private final ProductImageAttributeMapper productImageAttributeMapper;
|
private final ProductImageAttributeMapper productImageAttributeMapper;
|
||||||
|
|||||||
@@ -547,7 +547,7 @@ public class UploadServiceImpl implements UploadService {
|
|||||||
/**
|
/**
|
||||||
* 清理过期上传任务(每小时执行一次)
|
* 清理过期上传任务(每小时执行一次)
|
||||||
*/
|
*/
|
||||||
@Scheduled(fixedDelay = 3600000) // 1小时
|
// @Scheduled(fixedDelay = 3600000) // 1小时
|
||||||
public void cleanupExpiredUploads() {
|
public void cleanupExpiredUploads() {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
uploadTasks.entrySet().removeIf(entry -> {
|
uploadTasks.entrySet().removeIf(entry -> {
|
||||||
|
|||||||
@@ -5,28 +5,12 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
server:
|
server:
|
||||||
port: 5567
|
port: 10092
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: aida-back
|
name: aida-back
|
||||||
|
|
||||||
# ---------- 副数据源(back 私有,由 Nacos 统一管理) ----------
|
|
||||||
|
|
||||||
# ---------- Token 生成参数(由 TokenGenerateUtils 使用) ----------
|
|
||||||
security:
|
|
||||||
jwtSecret: JWTSECRET
|
|
||||||
jwtTokenHeader: Authorization
|
|
||||||
jwtTokenPrefix: Bearer-
|
|
||||||
jwtExpiration: 8640000000
|
|
||||||
|
|
||||||
# ---------- Python 服务 ----------
|
|
||||||
access:
|
|
||||||
python:
|
|
||||||
ip: http://18.167.251.121
|
|
||||||
port: 9994
|
|
||||||
generate_sr_port: 9994
|
|
||||||
address: http://18.167.251.121:9994
|
|
||||||
|
|
||||||
# ---------- MinIO Buckets ----------
|
# ---------- MinIO Buckets ----------
|
||||||
minio:
|
minio:
|
||||||
@@ -101,10 +85,6 @@ google:
|
|||||||
redirect:
|
redirect:
|
||||||
uri: https://develop.api.aida.com.hk/api/third/party/auth/google_callback
|
uri: https://develop.api.aida.com.hk/api/third/party/auth/google_callback
|
||||||
|
|
||||||
design:
|
|
||||||
callback:
|
|
||||||
url: https://darkish-copied-sprinkler.ngrok-free.dev/api/third/party/receiveDesignResults
|
|
||||||
|
|
||||||
redirect:
|
redirect:
|
||||||
url: http://18.167.251.121:7788
|
url: http://18.167.251.121:7788
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,31 @@
|
|||||||
# 示例:docker run -e NACOS_NAMESPACE=prod ...
|
# 示例:docker run -e NACOS_NAMESPACE=prod ...
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
nacos:
|
||||||
|
namespace: dev
|
||||||
|
host: 18.167.251.121:28848
|
||||||
|
username: nacos
|
||||||
|
password: Aidlab123123!
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: aida-back
|
name: aida-back
|
||||||
config:
|
config:
|
||||||
import: optional:nacos:aida-public-${NACOS_NAMESPACE:test}.yml
|
import: optional:nacos:aida-public-${nacos.namespace}.yml
|
||||||
cloud:
|
cloud:
|
||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
server-addr: ${nacos.host}
|
||||||
namespace: ${NACOS_NAMESPACE:test}
|
namespace: ${nacos.namespace}
|
||||||
|
username: ${nacos.username}
|
||||||
|
password: ${nacos.password}
|
||||||
|
# ip: 18.167.251.121
|
||||||
|
port: 10092
|
||||||
|
# ip-type: ipv4
|
||||||
|
# prefer-ip-address: true
|
||||||
config:
|
config:
|
||||||
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
server-addr: ${nacos.host}
|
||||||
namespace: ${NACOS_NAMESPACE:test}
|
namespace: ${nacos.namespace}
|
||||||
group: ${NACOS_GROUP:DEFAULT_GROUP}
|
|
||||||
file-extension: yaml
|
file-extension: yaml
|
||||||
|
username: ${nacos.username}
|
||||||
|
password: ${nacos.password}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ waistbandRight.cannot.be.empty=waistbandRight cannot be empty.
|
|||||||
handLeft.cannot.be.empty=handLeft cannot be empty.
|
handLeft.cannot.be.empty=handLeft cannot be empty.
|
||||||
handRight.cannot.be.empty=handRight cannot be empty.
|
handRight.cannot.be.empty=handRight cannot be empty.
|
||||||
id.cannot.be.empty=id cannot be empty.
|
id.cannot.be.empty=id cannot be empty.
|
||||||
|
url.cannot.be.empty=url cannot be empty.
|
||||||
type.cannot.be.empty=type cannot be empty.
|
type.cannot.be.empty=type cannot be empty.
|
||||||
color.cannot.be.empty=color cannot be empty.
|
color.cannot.be.empty=color cannot be empty.
|
||||||
generateDetailId.cannot.be.empty=generateDetailId cannot be empty.
|
generateDetailId.cannot.be.empty=generateDetailId cannot be empty.
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ waistbandRight.cannot.be.empty=waistbandRight不能为空。
|
|||||||
handLeft.cannot.be.empty=handLeft不能为空。
|
handLeft.cannot.be.empty=handLeft不能为空。
|
||||||
handRight.cannot.be.empty=handRight不能为空。
|
handRight.cannot.be.empty=handRight不能为空。
|
||||||
id.cannot.be.empty=id不能为空。
|
id.cannot.be.empty=id不能为空。
|
||||||
|
url.cannot.be.empty=url不能为空。
|
||||||
type.cannot.be.empty=type不能为空。
|
type.cannot.be.empty=type不能为空。
|
||||||
color.cannot.be.empty=color不能为空。
|
color.cannot.be.empty=color不能为空。
|
||||||
generateDetailId.cannot.be.empty=generateDetailId不能为空。
|
generateDetailId.cannot.be.empty=generateDetailId不能为空。
|
||||||
|
|||||||
Reference in New Issue
Block a user