Merge remote-tracking branch 'origin/dev/dev' into dev/dev

This commit is contained in:
shahaibo
2025-03-25 13:16:40 +08:00
31 changed files with 1863 additions and 20 deletions

View File

@@ -0,0 +1,138 @@
package com.ai.da.service;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.io.InputStreamSource;
import java.util.List;
public interface EmailService {
void loadSingleEmailTemplate(String templatePath);
void loadTemplatesFromResources(String resourcesPath);
/**
* 发邮件
*
* @param mailTo 收件人邮箱
* @param jsonObject 动态邮件模板参数
* @param templateName 邮件模板名(只有文件名且需要带文件后缀)
* @param title 邮件标题
* @param fileName 附件文件名。没有附件置为null
* @param inputStreamSource 附件文件数据。没有附件置为null
*/
void sendEmail(List<String> mailTo, JSONObject jsonObject, String templateName, String title, String fileName, InputStreamSource inputStreamSource);
/**
* 适用于 需要自定义发件人信息
*
* @param jsonObject 模板参数
* @param basicEmailParamDTO 包含发件人信息、邮件标题、收件人信息
* @param templateName 使用的模板文件名
* @param fileName 附件文件名
* @param inputStreamSource 附件文件信息
*/
void sendEmail(JSONObject jsonObject, BasicEmailParamDTO basicEmailParamDTO, String templateName, String fileName, InputStreamSource inputStreamSource);
// 登入模板id
String LOGIN_TEMPLATE_ID = "58020_login_aida_en.html";
// 修改密码模板id
String UPDATE_PWD_TEMPLATE_ID = "58022_update_password.html";
// 异常ip模板id
String EXCEPTION_ID_TEMPLATE_ID = "58021_exception_ip.html";
// 绑定邮箱模板id
String BIND_MAILBOX_TEMPLATE_ID = "132754_绑定邮箱.html";
// 更换绑定邮箱
String CHANGE_MAILBOX_TEMPLATE_ID = "128210_change_mailbox_en.html";
/**
* 发送登录相关的邮件
*
* @param receiverAddress 收件地址
* @param ip 请求ip
* @param templateId 模板ID名
* @param verifyCode 验证码
*/
Boolean send(String receiverAddress, String ip, String templateId, String verifyCode);
/**
* 发送试用订单相关的邮件
*
* @param receiverAddress 收件人邮箱地址
* @param trialOrder 试用订单相关参数
* @param emailType 邮件类型1 - 提交试用请求2 - 审批通过3 - 试用请求通过通知
* @param country 通过城市判断邮件模板的语言
* @param link
*/
void sendCustomEmail(String receiverAddress, TrialOrder trialOrder, int emailType, String country, Boolean link);
/**
* 发送昨日的试用订单用户数据
*
* @param receiverAddress 收件人地址
* @param fileName 附件文件名
* @param inputStreamSource 附件文件数据
*/
void sendExcelEmail(List<String> receiverAddress, String fileName, InputStreamSource inputStreamSource);
/**
* 发送昨日的试用订单用户数据--无试用订单情况
*
* @param receiverAddress 收件人地址
*/
void sendNoExcelEmail(List<String> receiverAddress);
/**
* 向账号快要到期的用户发送提醒邮件
*
* @param account 账号信息
*/
void sendWillBeExpiredEmail(Account account);
/**
* 发送系统升级通知邮件
*
* @param account 用户信息
* @param senderAddress 发件人邮件
* @param type 邮件类型
*/
void sendUpgradeNotification(Account account, String senderAddress, Integer type);
/**
* 通知在Code_Create上付费的用户AiDA账号的更新
*
* @param receiverAddress 收件人地址
* @param emailType 邮件类型
* @param country 国家(确定发送邮件的语言)
* @param userName 用户名
* @param date 账号到期时间
*/
void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date);
/**
* 广场用户注册通知邮件
*
* @param userEmail
* @param randomVerifyCode
* @return
*/
Boolean designWorksRegister(String userEmail, String randomVerifyCode);
void uploadTimeoutReminder(String userName, String time);
boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress);
void affiliateEmailReminder(List<String> receiverAddress, AffiliateEmailParamsDTO paramsDTO, String type);
void creditsPurchaseReminder(String username, String quantity, String amount);
void commonExceptionReminder(String functionName, List<String> destination);
}

View File

@@ -2,12 +2,10 @@ package com.ai.da.service;
import com.ai.da.mapper.primary.entity.Generate;
import com.ai.da.mapper.primary.entity.GenerateDetail;
import com.ai.da.model.dto.GenerateLikeDTO;
import com.ai.da.model.dto.GenerateModifyDTO;
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.dto.ImageToSketchDTO;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@@ -44,7 +42,21 @@ public interface GenerateService extends IService<Generate> {
List<Map<String, Object>> getCountByUserAndTime(String startTime, String endTime, List<Long> accountIdList);
GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO);
GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO, String collagePictureUrl, Long projectId);
GenerateResultVO modifySketch(GenerateModifyDTO generateModifyDTO);
String poseTransform(Long projectId, String productImage, int poseId);
void processPoseTransformResult(String taskId, String gifUrl, String videoUrl, String imageUrl);
PoseTransformationVO getPoseTransformationResult(String taskId);
String modifyModelProportion(ModifyModelProportionDTO proportionDTO);
GenerateResultVO sketchReconstructionGenerate(SketchReconstructionDTO sketchReconstructionDTO);
String sketchReconstructionSave(MultipartFile multipartFile, Long projectId);
SketchReconstructionVO getSketchReconstruction(Long projectId);
}

View File

@@ -0,0 +1,649 @@
package com.ai.da.service.impl;
import com.ai.da.common.utils.DateUtil;
import com.ai.da.common.utils.MailUtil;
import com.ai.da.mapper.primary.EmailLogMapper;
import com.ai.da.mapper.primary.EmailTemplateMapper;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Stream;
@Slf4j
@Service
public class EmailServiceImpl implements EmailService {
@Resource
private MailUtil mailUtil;
@Resource
private EmailTemplateMapper emailTemplateMapper;
@Resource
private EmailLogMapper emailLogMapper;
public void loadSingleEmailTemplate(String templatePath){
// 获取 ClassLoader
ClassLoader classLoader = this.getClass().getClassLoader();
// 获取文件的 URL
URL resourceUrl = classLoader.getResource(templatePath);
if (resourceUrl == null) {
System.out.println("File not found: " + templatePath);
return;
}
// 获取文件名
String fileName = templatePath.substring(templatePath.lastIndexOf("\\") + 1);
// 获取文件内容
try (InputStream inputStream = resourceUrl.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
// 调用方法将数据存入数据库
saveTemplateToDatabase(fileName, removePrefixAndFileExtension(templatePath), String.valueOf(content));
} catch (IOException e) {
e.printStackTrace();
}
}
public void loadTemplatesFromResources(String resourcesPath) {
try {
// 获取 ClassLoader
ClassLoader classLoader = this.getClass().getClassLoader();
// 获取 resources 文件夹的路径
Path path = Paths.get(classLoader.getResource(resourcesPath).toURI());
// 遍历文件夹
try (Stream<Path> paths = Files.walk(path)) {
paths.filter(Files::isRegularFile)
.forEach(file -> {
try {
// 读取文件内容
String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
// 获取文件名和路径
String fileName = file.getFileName().toString();
// 去除文件后缀
String filePath = removePrefixAndFileExtension(file.toString());
// 调用方法将数据存入数据库
saveTemplateToDatabase(fileName, filePath, content);
} catch (IOException e) {
e.printStackTrace();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 去掉文件路径的前缀和后缀
*
* @param filePath 文件路径(可以包含路径)
* @return 去掉后缀的文件名
*/
private static String removePrefixAndFileExtension(String filePath) {
String keyword = "templates\\";
int index = filePath.indexOf(keyword);
if (index == -1) {
return null; // 如果路径中不包含 templates/,返回空
}
int lastDotIndex = filePath.lastIndexOf('.');
if (lastDotIndex == -1) {
return filePath.substring(index + keyword.length()); // 没有后缀,直接返回
}
return filePath.substring(index+ keyword.length(), lastDotIndex);
}
public void saveTemplateToDatabase(String fileName, String filePath, String content) {
// 这里实现将数据存入数据库的逻辑
// 使用 JDBC 或 JPA 将 fileName、filePath 和 content 插入到 email_template 表
log.info("Saving to database: {}", fileName);
EmailTemplate emailTemplate = new EmailTemplate();
emailTemplate.setTemplateName(fileName);
emailTemplate.setTemplatePath(filePath);
emailTemplate.setContent(content);
emailTemplate.setVersion(1);
emailTemplate.setCreateTime(LocalDateTime.now());
if (fileName.endsWith("en.html")){
emailTemplate.setLanguage("EN");
}else {
emailTemplate.setLanguage("CN");
}
emailTemplateMapper.insert(emailTemplate);
}
/**
* 发邮件
* @param mailTo 收件人邮箱
* @param jsonObject 动态邮件模板【参数】
* @param templateName 邮件模板名(只有文件名且需要带文件后缀)
* @param title 邮件标题
* @param fileName 附件文件名
* @param inputStreamSource 附件
*/
public void sendEmail(List<String> mailTo, JSONObject jsonObject, String templateName, String title, String fileName, InputStreamSource inputStreamSource) {
EmailTemplate emailTemplate = getEmailTemplateByName(templateName);
if (Objects.isNull(emailTemplate)){
log.error("Email template: {}, dose not exist!", templateName);
return;
}
try {
BasicEmailParamDTO basicEmailParamDTO = mailUtil.setBasicEmailParams(mailTo, jsonObject, emailTemplate.getTemplatePath(), title);
int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
if (lastReturnCode == 250) {
log.info("邮件发送成功Subject : {}", basicEmailParamDTO.getSubject());
} else if (lastReturnCode == 450) {
log.info("目标邮箱 {} 暂时不可用,请稍后重试", mailTo);
} else if (lastReturnCode == 550) {
log.info("目标邮箱 {} 不可用,邮件发送失败", mailTo);
} else {
log.info("邮件发送失败Subject : {}, 状态码: {}", basicEmailParamDTO.getSubject(), lastReturnCode);
}
EmailLog emailLog = new EmailLog();
emailLog.setTemplateId(emailTemplate.getId());
if (Objects.nonNull(jsonObject)) emailLog.setParameter(jsonObject.toString());
emailLog.setSender("info@aida.com.hk");
emailLog.setRecipients(mailTo.toString());
emailLog.setSubject(title);
emailLog.setCreateTime(LocalDateTime.now());
switch (lastReturnCode) {
case 0:
break;
case 250:
emailLog.setStatus("delivered");
break;
case 450:
emailLog.setStatus("retrying");
break;
case 550:
emailLog.setStatus("failed");
break;
}
emailLogMapper.insert(emailLog);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
/**
* 适用于 需要自定义发件人信息
* @param jsonObject 模板参数
* @param basicEmailParamDTO 包含发件人信息、邮件标题、收件人信息
* @param templateName 使用的模板文件名
* @param fileName 附件文件名
* @param inputStreamSource 附件文件信息
*/
public void sendEmail(JSONObject jsonObject, BasicEmailParamDTO basicEmailParamDTO, String templateName, String fileName, InputStreamSource inputStreamSource) {
EmailTemplate emailTemplate = getEmailTemplateByName(templateName);
if (Objects.isNull(emailTemplate)){
log.error("Email template: {}, dose not exist!", templateName);
return;
}
try {
basicEmailParamDTO.setContent(mailUtil.setContent(jsonObject, emailTemplate.getTemplatePath()));
int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
EmailLog emailLog = new EmailLog();
emailLog.setTemplateId(emailTemplate.getId());
if (Objects.nonNull(jsonObject)) emailLog.setParameter(jsonObject.toString());
emailLog.setSender(basicEmailParamDTO.getSenderUser());
emailLog.setRecipients(basicEmailParamDTO.getMailTo().toString());
emailLog.setSubject(basicEmailParamDTO.getSubject());
emailLog.setCreateTime(LocalDateTime.now());
switch (lastReturnCode) {
case 0:
break;
case 250:
emailLog.setStatus("delivered");
break;
case 450:
emailLog.setStatus("retrying");
break;
case 550:
emailLog.setStatus("failed");
break;
}
emailLogMapper.insert(emailLog);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
public EmailTemplate getEmailTemplateByName(String templateName) {
QueryWrapper<EmailTemplate> qw = new QueryWrapper<>();
qw.eq("template_name", templateName).orderByDesc("id");
List<EmailTemplate> emailTemplates = emailTemplateMapper.selectList(qw);
if (emailTemplates.isEmpty()) {
return null;
}
return emailTemplates.get(0);
}
// 登入主题
public final String LOGIN_SUBJECT = "Log on";
// 忘记密码主题
public final String FORGET_PWD_SUBJECT = "Reset password";
// 异常ip
public final String EXCEPTION_ID_SUBJECT = "Exception ip";
// 绑定邮箱
public final String BIND_MAILBOX_SUBJECT = "绑定邮箱";
// 更换邮箱
public final String CHANGE_MAILBOX_SUBJECT = "Change Mailbox";
// 登入模板id
// public final String LOGIN_TEMPLATE_ID = "58020_login_aida_en.html";
// 修改密码模板id
// public final String UPDATE_PWD_TEMPLATE_ID = "58022_update_password.html";
// 异常ip模板id
// public final String EXCEPTION_ID_TEMPLATE_ID = "58021_exception_ip.html";
// 绑定邮箱模板id
// public final String BIND_MAILBOX_TEMPLATE_ID = "132754_绑定邮箱.html";
// 更换绑定邮箱
// public final String CHANGE_MAILBOX_TEMPLATE_ID = "128210_change_mailbox_en.html";
public Boolean send(String receiverAddress, String ip, String templateId, String verifyCode) {
String subject = Objects.equals(templateId, LOGIN_TEMPLATE_ID) ? LOGIN_SUBJECT :
Objects.equals(templateId, UPDATE_PWD_TEMPLATE_ID) ? FORGET_PWD_SUBJECT :
Objects.equals(templateId, EXCEPTION_ID_TEMPLATE_ID) ? EXCEPTION_ID_SUBJECT :
Objects.equals(templateId, CHANGE_MAILBOX_TEMPLATE_ID) ? CHANGE_MAILBOX_SUBJECT : BIND_MAILBOX_SUBJECT;
JSONObject jsonObject = contractTemplate(templateId, verifyCode, ip);
sendEmail(Collections.singletonList(receiverAddress), jsonObject, templateId, subject, null, null);
return Boolean.TRUE;
}
private static JSONObject contractTemplate(String templateId, String verifyCode, String ip) {
JSONObject jsonObject = new JSONObject();
if (templateId == EXCEPTION_ID_TEMPLATE_ID) {
jsonObject.put("exceptionIp", ip);
jsonObject.put("loginTime", DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD_HH_MM_SS));
} else {
jsonObject.put("code", verifyCode);
}
return jsonObject;
}
private final static String YOUR_TRIAL_TEMPLATE_ID = "117214_trailOrderTemplate.html";
private final static String APPROVAL_TEMPLATE_ID = "117215_trailOrderApprovalTemplate.html";
private final static String NOTIFICATION_TEMPLATE_ID = "117216_notificationTemplate.html";
private final static String NOTIFICATION_CHINESE_TEMPLATE_ID = "122229_notificationChineseTemplate.html";
/**
* 发送不同类型的邮件
*
* @param receiverAddress 收件人邮箱地址
* @param emailType 邮件类型1 - 提交试用请求2 - 审批通过3 - 试用请求通过通知
* @return 发送结果
*/
// 由于原本的参数【String senderAddress】在实际使用过程中都是空即使用默认发件地址故这里删除该参数
// todo 确认入参能否被删除
public void sendCustomEmail(String receiverAddress, TrialOrder trialOrder, int emailType, String country, Boolean link) {
// 根据邮件类型设置不同的主题和模板
String subject = "";
String templateId = "";
JSONObject jsonObject = new JSONObject();
switch (emailType) {
case 1:
subject = "试用订单请求";
templateId = YOUR_TRIAL_TEMPLATE_ID;
jsonObject = buildTrialOrderData(trialOrder, null);
break;
case 2:
subject = "试用订单审批通过";
templateId = APPROVAL_TEMPLATE_ID;
jsonObject = buildTrialOrderData(trialOrder, null);
break;
case 3:
subject = "Approval Confirmation for AiDA System Trial Access";
if (country.equals("China")) {
templateId = NOTIFICATION_CHINESE_TEMPLATE_ID;
} else {
templateId = NOTIFICATION_TEMPLATE_ID;
}
jsonObject = buildTrialOrderData(trialOrder, link);
break;
default:
break;
}
// 发送邮件
sendEmail(Collections.singletonList(receiverAddress), jsonObject, templateId, subject, null, null);
}
// 构建试用订单数据
private JSONObject buildTrialOrderData(TrialOrder trialOrder, Boolean link) {
JSONObject jsonObject = new JSONObject();
// 设置试用订单通过通知相关数据
jsonObject.put("title", trialOrder.getTitle());
jsonObject.put("surname", trialOrder.getSurname());
jsonObject.put("givenName", trialOrder.getGivenName());
jsonObject.put("userName", trialOrder.getUserName());
jsonObject.put("email", trialOrder.getEmail());
if (Objects.nonNull(link)) {
if (link) {
jsonObject.put("days", 14);
} else {
jsonObject.put("days", 5);
}
}
return jsonObject;
}
private final static String TRIAL_ORDER_LIST_ID = "122273_trailOrderData.html";
public void sendExcelEmail(List<String> receiverAddress, String fileName, InputStreamSource inputStreamSource) {
// 根据邮件类型设置不同的主题和模板
String subject = "昨日试用订单数据";
// 发送邮件
sendEmail(receiverAddress, null, TRIAL_ORDER_LIST_ID, subject, fileName, inputStreamSource);
}
private final static String NO_TRIAL_ORDER_LIST_ID = "122591_noTrailOrderTemplate.html";
public void sendNoExcelEmail(List<String> receiverAddress) {
// 根据邮件类型设置不同的主题和模板
String subject = "昨日试用订单数据";
// 发送邮件
sendEmail(receiverAddress, null, NO_TRIAL_ORDER_LIST_ID, subject, null, null);
}
private final static String WILLBEEXPIRED_TEMPLATE_ID = "118178_willBeExpiredNotification.html";
public void sendWillBeExpiredEmail(Account account) {
// 根据邮件类型设置不同的主题和模板
String subject = "Renewal notice";
// 发送邮件
sendEmail(Collections.singletonList(account.getUserEmail()), buildAccountData(account), WILLBEEXPIRED_TEMPLATE_ID, subject, null, null);
}
private static JSONObject buildAccountData(Account account) {
JSONObject jsonObject = new JSONObject();
// 设置试用订单相关数据
jsonObject.put("userName", account.getUserName());
// 用户到期时间戳
Long timestamp = account.getValidEndTime(); // 替换为你的时间戳
if (null != timestamp) {
// 获取当前时间戳
Long currentTimestamp = System.currentTimeMillis();
// 计算时间差(毫秒)
long timeDifference = currentTimestamp - timestamp;
// 向上取整计算天数
long days = (timeDifference + 24 * 60 * 60 * 1000 - 1) / (24 * 60 * 60 * 1000);
jsonObject.put("days", days);
}
return jsonObject;
}
private final static String UPGRADE_SUCCESS_NOTIFICATION_ID = "118856_AiDA发版完成通知英文版.html";
private final static String UPGRADE_SUCCESS_NOTIFICATION_ID_CHINESE = "122899_AiDA发版完成通知中文版.html";
// todo 将这里的发件人信息包装为枚举类,枚举类中包含发件邮箱的服务地址,密码,发件人邮箱
public void sendUpgradeNotification(Account account, String senderAddress, Integer type) {
try {
// 根据邮件类型设置不同的主题和模板
String subject = "";
String templateId = "";
if (type == 1) {
subject = "Successful System Upgrade and New Features in AiDA 3.0";
templateId = UPGRADE_SUCCESS_NOTIFICATION_ID;
}else {
subject = "系统升级成功和AiDA 3.0新功能";
templateId = UPGRADE_SUCCESS_NOTIFICATION_ID_CHINESE;
}
BasicEmailParamDTO basicEmailParamDTO = new BasicEmailParamDTO();
basicEmailParamDTO.setServiceAddress("mail.code-create.com.hk.");
basicEmailParamDTO.setSenderUserMail("info@code-create.com.hk");
basicEmailParamDTO.setSenderUser("info@code-create.com.hk");
basicEmailParamDTO.setPassword("???");
basicEmailParamDTO.setSubject(subject);
basicEmailParamDTO.setMailTo(mailUtil.getInternetAddressList(Collections.singletonList(account.getUserEmail())));
// 发送邮件
sendEmail(buildAccountData(account), basicEmailParamDTO, templateId, null, null);
} catch (AddressException e) {
throw new RuntimeException(e);
}
}
private final static String NEW_USER_PAYMENT_NOTIFICATION_EN = "124889_new_user_payment_notification_en.html";
private final static String NEW_USER_PAYMENT_NOTIFICATION_CN = "124888_new_user_payment_notification_cn.html";
private final static String RENEWAL_NOTIFICATION_FOR_OLD_USER_EN = "124892_renewal_notification_for_old_user_en.html";
private final static String RENEWAL_NOTIFICATION_FOR_OLD_USER_CN = "124891_renewal_notification_for_old_user_cn.html";
public void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date) {
// 根据邮件类型设置不同的主题和模板
String subject = "";
String templateId = "";
JSONObject parameter = new JSONObject();
switch (emailType) {
// 新用户
case 1:
subject = "Welcome to AiDA!";
if (country.equals("China")) {
templateId = NEW_USER_PAYMENT_NOTIFICATION_CN;
} else {
templateId = NEW_USER_PAYMENT_NOTIFICATION_EN;
}
parameter.put("userName", userName);
parameter.put("email", receiverAddress);
break;
// 续费用户
case 2:
subject = "Account renewal notification";
if (country.equals("China")) {
templateId = RENEWAL_NOTIFICATION_FOR_OLD_USER_CN;
} else {
templateId = RENEWAL_NOTIFICATION_FOR_OLD_USER_EN;
}
break;
default:
break;
}
parameter.put("userName", userName);
parameter.put("date", date);
// 发送邮件
sendEmail(Collections.singletonList(receiverAddress), parameter, templateId, subject, null, null);
}
private final static String PORTFOLIO_REGISTER_ID = "124847_portfolio-account-register.html";
public Boolean designWorksRegister(String userEmail, String randomVerifyCode) {
String subject = "Tourist registration";
sendEmail(Collections.singletonList(userEmail), contractTemplate(PORTFOLIO_REGISTER_ID, randomVerifyCode, null), PORTFOLIO_REGISTER_ID, subject, null, null);
return Boolean.TRUE;
}
private final static String UPLOAD_TIMEOUT_REMINDER = "128324_upload_timeout_reminder.html";
public void uploadTimeoutReminder(String userName, String time) {
String xp = "xupei3360@163.com";
String shb = "shahaibodd99@gmail.com";
String wxd = "X1627315083@163.com";
String pkc = "kaicpang.pang@connect.polyu.hk";
JSONObject param = new JSONObject();
param.put("username", userName);
param.put("time", time);
// 返回的resp是一个SendEmailResponse的实例与请求对象对应
sendEmail(Arrays.asList(shb, xp, wxd, pkc), param, UPLOAD_TIMEOUT_REMINDER, "上传图片超时提醒", null, null);
}
private final static String CANCEL_MERCHANT_EN = "130720_cancel-merchant-en.html";
private final static String NEW_MERCHANT_EN = "135190_new-merchant-en-updated01.html";
private final static String NEW_USER_EN = "135189_new-user-en-updated01.html";
private final static String NEW_USER_CN = "135186_new-user-cn-updated01.html";
private final static String RENEWAL_MERCHANT_EN = "130724_renewal-merchant-en.html";
private final static String RENEWAL_USER_EN = "130725_renewal-user-en.html";
private final static String RENEWAL_USER_CN = "130726_renewal-user-cn.html";
private final static String RENEWAL_REMINDER_USER_EN = "130727_renewal-reminder-user-en.html";
private final static String RENEWAL_REMINDER_USER_CN = "130728_renewal-reminder-user-cn.html";
private final static String PAYMENT_FAILED_NEW_MERCHANT_EN = "131230_payment_failed_new_merchant_en.html";
private final static String PAYMENT_FAILED_RENEWAL_MERCHANT_EN = "131225_payment_failed_renewal_merchant_en.html";
private final static String PAYMENT_FAILED_RENEWAL_USER_EN = "131563_payment_failed_renewal_user_en.html";
private final static String PAYMENT_FAILED_RENEWAL_USER_CN = "131564_payment_failed_renewal_user_cn.html";
public boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress) {
try {
String merchantEmail = "kimwong@code-create.com.hk";
String developer = "xupei3360@163.com";
List<String> merchantReceiver = Arrays.asList(/*merchantEmail, */developer);
String merchantSubject = null;
String merchantTemplate = null;
String userSubject = null;
String userTemplate = null;
switch (type) {
case "cancel":
merchantSubject = "[Code-Create] Subscription Cancelled";
merchantTemplate = CANCEL_MERCHANT_EN;
break;
case "fail_new":
merchantSubject = "[Code-Create] Payment Failed : New Order (" + subscriptionEmailParamsDTO.getOrderId() + ")";
merchantTemplate = PAYMENT_FAILED_NEW_MERCHANT_EN;
break;
case "fail_renewal":
merchantSubject = "[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")";
merchantTemplate = PAYMENT_FAILED_RENEWAL_MERCHANT_EN;
if (language.equals("ENGLISH")) {
userSubject = "[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")";
userTemplate = PAYMENT_FAILED_RENEWAL_USER_EN;
} else {
userSubject = "[Code-Create] 自动续费失败 (" + subscriptionEmailParamsDTO.getOrderId() + ")";
userTemplate = PAYMENT_FAILED_RENEWAL_USER_CN;
}
break;
case "new":
merchantSubject = "[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")";
merchantTemplate = NEW_MERCHANT_EN;
if (language.equals("ENGLISH")) {
userSubject = "[Code-Create] You have successfully subscribed to AiDA";
userTemplate = NEW_USER_EN;
} else {
userSubject = "[Code-Create] 您已成功订阅AiDA";
userTemplate = NEW_USER_CN;
}
break;
case "renewal":
merchantSubject = "[Code-Create] New subscription renewal order (" + subscriptionEmailParamsDTO.getOrderId() + ")";
merchantTemplate = RENEWAL_MERCHANT_EN;
if (language.equals("ENGLISH")) {
userSubject = "[Code-Create] AiDA Renewal Successful";
userTemplate = RENEWAL_USER_EN;
} else {
userSubject = "[Code-Create] AiDA续订成功";
userTemplate = RENEWAL_USER_CN;
}
break;
case "reminder":
if (language.equals("ENGLISH")) {
userSubject = "[Code-Create] AiDA Subscription Renewal Reminder";
userTemplate = RENEWAL_REMINDER_USER_EN;
} else {
userSubject = "[Code-Create] AiDA续订提醒";
userTemplate = RENEWAL_REMINDER_USER_CN;
}
break;
default:
log.error("unknown subscription email type");
return false;
}
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(subscriptionEmailParamsDTO));
// 排除不向用户发送邮件的情况
if (!type.equals("cancel") && !type.equals("fail_new")) {
sendEmail(Collections.singletonList(receiverAddress), jsonObject, userTemplate, userSubject, null, null);
}
// 排除不向商家发送邮件的情况
if (!type.equals("reminder")) {
sendEmail(merchantReceiver, jsonObject, merchantTemplate, merchantSubject, null, null);
}
return true;
} catch (Exception e) {
log.error("邮件发送失败,{}", e.getMessage());
return false;
}
}
private final static String NEW_REGISTRATION = "132123_affiliate_registration_en.html";
private final static String AFFILIATE_ACCEPTED = "132124_affiliate_accepted_en.html";
private final static String AFFILIATE_REFUSED = "132125_affiliate_refused_en.html";
private final static String AFFILIATE_MONTHLY_SUMMARY = "132126_affiliate_monthly_summary_en.html";
public void affiliateEmailReminder(List<String> receiverAddress, AffiliateEmailParamsDTO paramsDTO, String type) {
String subject = "";
String templateId = "";
switch (type) {
case "new":
subject = "New Affiliate Registration";
templateId = NEW_REGISTRATION;
break;
case "accepted":
subject = "Affiliate Application Accepted";
templateId = AFFILIATE_ACCEPTED;
break;
case "refused":
subject = "Affiliate Application Refused";
templateId = AFFILIATE_REFUSED;
break;
case "summary":
subject = "Your Monthly AffiliateWP Summary for AiDA";
templateId = AFFILIATE_MONTHLY_SUMMARY;
break;
}
// 将 DTO 转换为 JSONObject
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(paramsDTO);
sendEmail(receiverAddress, jsonObject, templateId, subject, null, null);
}
private final static String CREDITS_PURCHASE_MERCHANT = "133275_AiDA 积分购买通知-merchant.html";
public void creditsPurchaseReminder(String username, String quantity, String amount) {
String merchantEmail = "kimwong@code-create.com.hk";
String developerEmail = "xupei@code-create.com.hk";
JSONObject jsonObject = new JSONObject();
// 设置试用订单相关数据
jsonObject.put("username", username);
jsonObject.put("quantity", quantity);
jsonObject.put("totalFee", amount);
sendEmail(Arrays.asList(/*merchantEmail,*/developerEmail), jsonObject, CREDITS_PURCHASE_MERCHANT, "New Credit Purchase Order", null, null);
}
private final static String COMMON_EXCEPTION_REMINDER = "135279_common-exception-reminder.html";
public void commonExceptionReminder(String functionName, List<String> destination) {
// 邮件内容 {{function}}处理异常,请及时查看
JSONObject param = new JSONObject();
param.put("function", functionName);
sendEmail(destination, param, COMMON_EXCEPTION_REMINDER, "AiDA发生异常请及时处理", null, null);
}
}

View File

@@ -14,6 +14,8 @@ import com.ai.da.model.vo.*;
import com.ai.da.python.PythonService;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
@@ -26,14 +28,17 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import static com.ai.da.common.enums.CollectionLevel1TypeEnum.*;
import static com.ai.da.service.impl.UserLikeGroupServiceImpl.convert;
@Slf4j
@Service
@@ -59,6 +64,8 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
private RedisUtil redisUtil;
@Resource
private GenerateCancelMapper generateCancelMapper;
@Resource
private SketchReconstructionMapper sketchReconstructionMapper;
@Value("${redis.key.orderForGenerate}")
private String consumptionOrderKey;
@@ -715,6 +722,8 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
String path;
if (type.equals("Logo")) {
path = CommonConstant.GENERATE_LOGO_SINGLE_CANCEL;
} else if(type.equals("PoseTransformation")){
path =CommonConstant.POSE_TRANSFORMATION_CANCEL;
} else {
path = CommonConstant.GENERATE_CANCEL;
}
@@ -810,7 +819,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
@Override
@Transactional(rollbackFor = Exception.class)
public GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO) {
public GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO, String collagePictureUrl, Long projectId) {
String bucket = userBucket;
Long accountId = UserContext.getUserHolder().getId();
@@ -823,8 +832,13 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
throw new BusinessException("remaining.credits.insufficient", ResultEnum.PROMPT.getCode());
}
CollectionElement collectionElement = collectionElementService.getById(imageToSketchDTO.getElementId());
String imagePath = collectionElement.getUrl();
String imagePath;
if (StringUtil.isNullOrEmpty(collagePictureUrl)){
CollectionElement collectionElement = collectionElementService.getById(imageToSketchDTO.getElementId());
imagePath = collectionElement.getUrl();
}else {
imagePath = collagePictureUrl;
}
log.info(minioUtil.getPreSignedUrl(imagePath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
String imageName = UUID.randomUUID().toString();
@@ -852,7 +866,9 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
generate.setElementId(imageToSketchDTO.getElementId());
generate.setGenerateType("image");
generate.setSketchStyle(styleCode);
generate.setStyleImageElementId(imageToSketchDTO.getElementId());
generate.setStyleImageElementId(imageToSketchDTO.getStyleImageId());
generate.setProjectId(projectId);
generate.setInputImageUrl(collagePictureUrl);
generate.setCreateDate(new Date());
baseMapper.insert(generate);
@@ -920,4 +936,255 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
return new GenerateResultVO(generateDetailId, minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), "Success", category);
}
public String poseTransform(Long projectId, String productImage, int poseId){
Long accountId = UserContext.getUserHolder().getId();
// 1、判断用户当前积分是否够本次生成消耗
CreditsEventsEnum creditsEventsEnum = CreditsEventsEnum.POSE_TRANSFORMATION;
Boolean preDeduction = creditsService.creditsPreDeduction(creditsEventsEnum, 1);
if (!preDeduction) {
throw new BusinessException("remaining.credits.insufficient", ResultEnum.WARNING.getCode());
}
// 3、生成唯一id 使用uuid,由于uuid重复的几率很小故取消对uuid重复性的校验
String uuid = UUID.randomUUID().toString();
String taskId = uuid + "-" + accountId;
PoseTransformation poseTransformation = new PoseTransformation();
poseTransformation.setProjectId(projectId);
poseTransformation.setAccountId(accountId);
poseTransformation.setUniqueId(taskId);
poseTransformation.setProductImage(productImage);
poseTransformation.setPoseId(poseId);
poseTransformation.setCreateTime(LocalDateTime.now());
poseTransformationMapper.insert(poseTransformation);
Boolean b = pythonService.poseTransformation(productImage, poseId, taskId);
if (b){
// 6、添加预扣除积分到redis
creditsService.addRecordToCreditsDeduction(accountId, uuid, creditsEventsEnum);
// 6.1 添加积分扣除记录到db
creditsService.preInsert(accountId, creditsEventsEnum.getName(), uuid, Boolean.TRUE, null);
return taskId;
}
throw new BusinessException("pose transformation error", ResultEnum.ERROR.getCode());
}
@Resource
private PoseTransformationMapper poseTransformationMapper;
public void processPoseTransformResult(String taskId, String gifUrl, String videoUrl, String imageUrl){
// 1、存储模型返回的数据
PoseTransformation poseTransformation;
QueryWrapper<PoseTransformation> qw = new QueryWrapper<>();
qw.eq("unique_id", taskId);
List<PoseTransformation> poseTransformations = poseTransformationMapper.selectList(qw);
if (poseTransformations != null && poseTransformations.size() > 1){
log.warn("通过taskId {} 查询到的PoseTransformation的结果不止一条", taskId);
}else if (poseTransformations == null || poseTransformations.isEmpty()){
return ;
}
poseTransformation = poseTransformations.get(0);
poseTransformation.setGifUrl(gifUrl);
poseTransformation.setVideoUrl(videoUrl);
poseTransformation.setImageUrl(imageUrl);
poseTransformation.setUpdateTime(LocalDateTime.now());
poseTransformationMapper.updateById(poseTransformation);
String key = generateResultKey + ":" + taskId;
PoseTransformationVO poseTransformationVO = new PoseTransformationVO(
poseTransformation.getId(), taskId, gifUrl, videoUrl, imageUrl, (byte) 0, "Success");
// 2、更新redis
redisUtil.addToString(key, new Gson().toJson(poseTransformationVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 3、执行积分扣除
String accountId = taskId.substring(taskId.lastIndexOf("-") + 1);
String uuid = taskId.substring(0, taskId.lastIndexOf("-"));
Boolean flag = creditsService.taskCreditsDeduction(Long.parseLong(accountId), uuid);
if (flag) creditsService.updateChangedCredits(accountId, uuid);
}
public PoseTransformationVO getPoseTransformationResult(String taskId){
String key = generateResultKey + ":" + taskId;
String resultJson = redisUtil.getFromString(key);
if (!StringUtil.isNullOrEmpty(resultJson)){
PoseTransformationVO poseTransformationVO = new Gson().fromJson(redisUtil.getFromString(key), PoseTransformationVO.class);
if (poseTransformationVO.getStatus().equals("Success")){
poseTransformationVO.setGifUrl(minioUtil.getPreSignedUrl(poseTransformationVO.getGifUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
poseTransformationVO.setVideoUrl(minioUtil.getPreSignedUrl(poseTransformationVO.getVideoUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
poseTransformationVO.setImageUrl(minioUtil.getPreSignedUrl(poseTransformationVO.getImageUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
}
return poseTransformationVO;
}else {
return new PoseTransformationVO();
}
}
@Resource
private SysFileService sysFileService;
@Resource
private LibraryModelPointService libraryModelPointService;
public String modifyModelProportion(ModifyModelProportionDTO proportionDTO){
log.info("modifyModelProportion params: {}", proportionDTO);
String name;
String gender;
Library model = null;
Long accountId = UserContext.getUserHolder().getId();
String uuid = UUID.randomUUID().toString();
// 所有修改的图片都另存为,不覆盖原图
if (proportionDTO.getType().equals("Library")){
model = libraryService.getById(proportionDTO.getId());
String url = model.getUrl();
name = url.substring(url.indexOf("/") + 1, url.lastIndexOf("/")) + "/" + uuid;
gender = model.getLevel2Type();
}else {
SysFileVO sysModel = sysFileService.getById(proportionDTO.getId());
gender = sysModel.getLevel2Type();
name = accountId + "/models/" + gender.toLowerCase() + "/" + uuid;
}
// 只需要将结果存入library
String modifiedModel = pythonService.modifyModelProportion(proportionDTO.getModelPath(), proportionDTO.getStretch(), name, proportionDTO.getTop(), proportionDTO.getBottom());
List<Integer> imagesWidthAndHeight = minioUtil.getImagesWidthAndHeight(modifiedModel);
// 存储修改后的模特到个人library
model = new Library();
model.setAccountId(accountId);
model.setLevel1Type(LibraryLevel1TypeEnum.MODELS.getRealName());
model.setLevel2Type(gender);
model.setName(uuid);
model.setUrl(modifiedModel);
model.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(modifiedModel, 24 * 60),false));
model.setWidth(imagesWidthAndHeight.get(0));
model.setHigh(imagesWidthAndHeight.get(1));
model.setCreateDate(new Date());
libraryService.save(model);
// 新建模特点位信息
LibraryModelPoint libraryModelPoint = new LibraryModelPoint();
libraryModelPoint.setModelType("Library");
libraryModelPoint.setRelationId(model.getId());
libraryModelPoint.setShoulderLeft(Arrays.toString(proportionDTO.getShoulderLeft()));
libraryModelPoint.setShoulderRight(Arrays.toString(proportionDTO.getShoulderRight()));
libraryModelPoint.setWaistbandLeft(Arrays.toString(proportionDTO.getWaistbandLeft()));
libraryModelPoint.setWaistbandRight(Arrays.toString(proportionDTO.getWaistbandRight()));
libraryModelPoint.setHandLeft(Arrays.toString(proportionDTO.getHandLeft()));
libraryModelPoint.setHandRight(Arrays.toString(proportionDTO.getHandRight()));
libraryModelPoint.setCreateDate(new Date());
libraryModelPointService.save(libraryModelPoint);
return minioUtil.getPreSignedUrl(modifiedModel, CommonConstant.MINIO_IMAGE_EXPIRE_TIME);
}
/**
* String collagePicture(Base64)
* List<DTO(id, type)> elements
* File file
* @return
*/
@Transactional(rollbackFor = Exception.class)
public GenerateResultVO sketchReconstructionGenerate(SketchReconstructionDTO sketchReconstructionDTO){
Long accountId = UserContext.getUserHolder().getId();
// 1、线稿生成
String collagePictureBase64 = sketchReconstructionDTO.getCollagePicture();
String path = accountId + "/CollagePicture/" + UUID.randomUUID();
String minioPath = minioUtil.base64UploadToPath(collagePictureBase64, userBucket, path);
Long projectId = sketchReconstructionDTO.getProjectId();
GenerateResultVO generateResultVO = imageToSketch(new ImageToSketchDTO(null, "2", sketchReconstructionDTO.getGender()), minioPath, projectId);
QueryWrapper<SketchReconstruction> qw = new QueryWrapper<>();
qw.eq("project_id", projectId);
SketchReconstruction sketchReconstruction = sketchReconstructionMapper.selectOne(qw);
String url = generateResultVO.getUrl();
// 找到路径的起始位置(从"://"之后查找第一个"/"
int pathStartIndex = url.indexOf("/", url.indexOf("://") + 3);
// 找到查询参数的起始位置("?" 的位置)
int queryStartIndex = url.indexOf("?");
// 截取目标部分
String targetPath = url.substring(pathStartIndex + 1, queryStartIndex);
if (Objects.isNull(sketchReconstruction)){
sketchReconstruction = new SketchReconstruction();
sketchReconstruction.setProjectId(projectId);
sketchReconstruction.setCollageImgSketchUrl(targetPath);
sketchReconstruction.setGenerateDetailId(generateResultVO.getId());
sketchReconstruction.setCreateTime(LocalDateTime.now());
sketchReconstructionMapper.insert(sketchReconstruction);
}else {
sketchReconstruction.setCollageImgSketchUrl(targetPath);
sketchReconstruction.setGenerateDetailId(generateResultVO.getId());
sketchReconstructionMapper.updateById(sketchReconstruction);
}
return generateResultVO;
}
public String sketchReconstructionSave(MultipartFile multipartFile, Long projectId){
Long accountId = UserContext.getUserHolder().getId();
// 元素都在画布上,不用额外保存
String object = accountId + "/CollageSketchFile/" + projectId;
String canvasFilePath = minioUtil.upload("aida-users", object, multipartFile,null);
// 将画布文件上传到minio,地址保存到project表中
QueryWrapper<SketchReconstruction> qw = new QueryWrapper<>();
qw.eq("project_id", projectId).isNotNull("canvas_url").orderByDesc("id");
SketchReconstruction sketchReconstruction = sketchReconstructionMapper.selectOne(qw);
if (Objects.isNull(sketchReconstruction)){
sketchReconstruction = new SketchReconstruction();
sketchReconstruction.setProjectId(projectId);
sketchReconstruction.setCanvasUrl(canvasFilePath);
sketchReconstruction.setCreateTime(LocalDateTime.now());
sketchReconstructionMapper.insert(sketchReconstruction);
}else if (StringUtil.isNullOrEmpty(sketchReconstruction.getCanvasUrl())){
sketchReconstruction.setCanvasUrl(canvasFilePath);
sketchReconstructionMapper.updateById(sketchReconstruction);
}
// 需要返回哪些信息呢?
return null;
}
public SketchReconstructionVO getSketchReconstruction(Long projectId){
QueryWrapper<SketchReconstruction> qw = new QueryWrapper<>();
qw.eq("project_id", projectId);
SketchReconstruction sketchReconstruction = sketchReconstructionMapper.selectOne(qw);
if (Objects.isNull(sketchReconstruction) || StringUtil.isNullOrEmpty(sketchReconstruction.getCanvasUrl())){
return null;
}
try {
InputStream download = minioUtil.download(sketchReconstruction.getCanvasUrl());
String convert = convert(download);
JSONObject jsonObject = JSONObject.parseObject(convert);
JSONArray objects = jsonObject.getJSONArray("objects");
for (int i = 0; i < objects.size(); i++) {
JSONObject jsonObject1 = objects.getJSONObject(i);
String type = jsonObject1.getString("type");
if (type.equals("image")) {
String minioUrl = jsonObject1.getString("minioUrl");
jsonObject1.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
}
objects.set(i, jsonObject1);
}
jsonObject.put("objects", objects);
log.info(String.valueOf(jsonObject));
// 除返回jsonObject之外,还要返回最后一次生成的线稿图以及like状态
SketchReconstructionVO vo = new SketchReconstructionVO();
vo.setCanvasFile(jsonObject);
if (Objects.nonNull(sketchReconstruction.getGenerateDetailId())){
GenerateDetail generateDetail = generateDetailMapper.selectById(sketchReconstruction.getGenerateDetailId());
vo.setCollageSketchUrl(minioUtil.getPreSignedUrl(generateDetail.getUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
vo.setLiked(generateDetail.getIsLike().equals((byte)1));
}
return vo;
}catch (Exception e){
return null;
}
}
}