fix: 生成视频、任务回调 - 检查代码并修改相关逻辑问题
This commit is contained in:
parent
80c136ad18
commit
f53f849ec8
|
|
@ -12,6 +12,7 @@ import com.ruoyi.common.core.response.video.GetVideoGenerationTaskResponse;
|
|||
import com.ruoyi.common.enums.AiOrderStatusType;
|
||||
import com.ruoyi.common.enums.VideoTaskStatusType;
|
||||
import com.ruoyi.common.utils.RandomStringUtil;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.TencentCosUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
|
|
@ -43,19 +44,17 @@ public class ByteApiController extends BaseController {
|
|||
// 锁参数
|
||||
private static final int LOCK_WAIT_SECONDS = 10;
|
||||
private static final int LOCK_LEASE_SECONDS = 20;
|
||||
// 任务成功时流水表备注
|
||||
private static final String TASK_SUCCESS_BALANCE_REMARK = "order.number.generation.successes";
|
||||
|
||||
private final IByteService byteService;
|
||||
private final TencentCosUtil tencentCosUtil;
|
||||
private final IAiOrderService aiOrderService;
|
||||
private final IAiManagerService managerService;
|
||||
private final IAiTagService aiTagService;
|
||||
private final IAiUserService aiUserService;
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
@Value("${volcengine.ark.callbackUrl}")
|
||||
private String volcCallbackUrl;
|
||||
private final IByteDeptApiKeyService byteDeptApiKeyService;
|
||||
|
||||
@PostMapping("/promptToImg")
|
||||
@ApiOperation("文生图")
|
||||
|
|
@ -346,16 +345,25 @@ public class ByteApiController extends BaseController {
|
|||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// 2、从官方获取任务数据
|
||||
String apiKey = byteService.resolveCurrentAiUserApiKey();
|
||||
// 2、查询订单
|
||||
String taskId = request.getId();
|
||||
AiOrder order = aiOrderService.selectOneByThirdPartyOrderNum(taskId);
|
||||
if (order == null) {
|
||||
// 可能是其他环境生成的但回调地址配置成正式的
|
||||
logger.warn("volcCallback aiorder is not exist! third party order num = {}", taskId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
// 3、从官方获取任务数据
|
||||
// 根据订单用户ID查询使用的Key
|
||||
// 严格来讲,按逻辑这块是应放在锁内,但这是调外部接口,如果接口超时整个服务可能会当机,所以不放锁内,即不做强一致
|
||||
String apiKey = byteDeptApiKeyService.resolveVolcApiKey(order.getUserId());
|
||||
GetVideoGenerationTaskResponse taskResp = byteService.getVideoGenerationTasks(request.getId(), apiKey);
|
||||
// 3、官方数据校验
|
||||
// 4、官方数据校验
|
||||
result = volcCallbackByteCheck(request, taskResp);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// 4、查询订单(同 taskId 串行:Redisson 分布式锁;步骤 1~3 已在锁外)
|
||||
String taskId = request.getId();
|
||||
// 5、查询订单(同 taskId 串行:Redisson 分布式锁;步骤 1~3 已在锁外)
|
||||
String lockKey = VOLC_CALLBACK_LOCK_KEY_PREFIX + taskId;
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
boolean locked = false;
|
||||
|
|
@ -365,30 +373,32 @@ public class ByteApiController extends BaseController {
|
|||
logger.warn("volcCallback skip: concurrent handling for same task, third party order num = {}", taskId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
AiOrder order = aiOrderService.selectOneByThirdPartyOrderNum(taskId);
|
||||
// 锁内二次查询,防止并发时状态变更
|
||||
order = aiOrderService.selectOneByThirdPartyOrderNum(taskId);
|
||||
if (order == null) {
|
||||
// 可能是其他环境生成的但回调地址配置成正式的
|
||||
logger.warn("volcCallback aiorder is not exist! third party order num = {}", taskId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
// 5、状态为队列中、执行中,只更新任务状态
|
||||
// 6、状态为队列中、执行中,只更新任务状态
|
||||
result = volcCallbackRunningTaskProcess(taskResp, order);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// 6、订单数据校验
|
||||
// 7、订单数据校验
|
||||
result = volcCallbackOrderCheck(taskResp, order);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// 7、根据状态做不同的处理(加事务)
|
||||
String status = taskResp.getStatus();
|
||||
// 8、根据状态做不同的处理(加事务)
|
||||
String status = taskResp.getStatus().toLowerCase();
|
||||
if (VideoTaskStatusType.SUCCEEDED.getName().equals(status)) {
|
||||
// 成功,预扣
|
||||
return volcCallbackSuccessProcess(request, taskResp, order);
|
||||
return aiOrderService.volcCallbackSuccessProcess(request, taskResp, order);
|
||||
} else {
|
||||
// 前面已判断过status的合法性,并处理了三种非失败的状态,所以可以确定是取消、失败、超时
|
||||
return volcCallbackFailProcess(taskResp, order);
|
||||
aiOrderService.orderFailure(order);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
|
@ -405,55 +415,6 @@ public class ByteApiController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
private AjaxResult volcCallbackFailProcess(GetVideoGenerationTaskResponse taskResp, AiOrder order) {
|
||||
aiOrderService.orderFailure(order);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
private AjaxResult volcCallbackSuccessProcess(VideoTaskCallBackRequest request, GetVideoGenerationTaskResponse taskResp, AiOrder order) {
|
||||
// 用量是否一致
|
||||
Integer requestTotalTokens = request.getUsage() == null || request.getUsage().getTotalTokens() == null
|
||||
? 0 : request.getUsage().getTotalTokens();
|
||||
Integer officialTotalTokens = taskResp.getUsage() == null || taskResp.getUsage().getTotalTokens() == null
|
||||
? 0 : taskResp.getUsage().getTotalTokens();
|
||||
if (requestTotalTokens.equals(officialTotalTokens)) {
|
||||
logger.error("volcCallback request's total tokens != official tokens! third party order num = {}, request's tokens = {}, official tokens = {}",
|
||||
request.getId(), requestTotalTokens, officialTotalTokens);
|
||||
return AjaxResult.error();
|
||||
}
|
||||
if (officialTotalTokens <= 0) {
|
||||
// 异常情况,应该不会出现,以防万一
|
||||
logger.error("volcCallback official tokens <= 0! third party order num = {}, request's tokens = {}, official tokens = {}",
|
||||
request.getId(), requestTotalTokens, officialTotalTokens);
|
||||
return AjaxResult.error();
|
||||
}
|
||||
BigDecimal realAmount = new BigDecimal(officialTotalTokens);
|
||||
// 用量回补、多退少补 = 预扣量 - 实际用量
|
||||
// 有预扣值才回补,没有的是历史单,不处理
|
||||
if (order.getPreDeductAmount() != null
|
||||
&& order.getPreDeductAmount().compareTo(new BigDecimal(0)) > 0) {
|
||||
BigDecimal addAmount = order.getPreDeductAmount().subtract(realAmount);
|
||||
if (addAmount.compareTo(new BigDecimal(0)) != 0) {
|
||||
// 回补
|
||||
aiUserService.addUserBalance(order.getOrderNum(), order.getUserId(), addAmount,
|
||||
BalanceChangerConstants.REFUND, TASK_SUCCESS_BALANCE_REMARK);
|
||||
}
|
||||
}
|
||||
// 设置视频地址与状态
|
||||
if (taskResp.getContent() != null && StringUtils.isNotEmpty(taskResp.getContent().getVideoUrl())) {
|
||||
order.setResult(taskResp.getContent().getVideoUrl());
|
||||
}
|
||||
// 设置用量
|
||||
order.setAmount(realAmount);
|
||||
// 订单状态
|
||||
order.setStatus(AiOrderStatusType.FINISH.ordinal());
|
||||
order.setIsBackfilled(1);
|
||||
aiOrderService.orderSuccess(order);
|
||||
return AjaxResult.success("callback success");
|
||||
}
|
||||
|
||||
private AjaxResult volcCallbackOrderCheck(GetVideoGenerationTaskResponse taskResp, AiOrder order) {
|
||||
// 订单状态如果不为执行中则不做处理
|
||||
if (order.getStatus() != null && order.getStatus() != AiOrderStatusType.RUNNING.ordinal()) {
|
||||
|
|
@ -471,7 +432,7 @@ public class ByteApiController extends BaseController {
|
|||
}
|
||||
|
||||
private AjaxResult volcCallbackByteCheck(VideoTaskCallBackRequest request, GetVideoGenerationTaskResponse taskResp) {
|
||||
String status = taskResp.getStatus();
|
||||
String status = request.getStatus().toLowerCase();
|
||||
// 请求的状态与字节的状态是否一致
|
||||
if (!status.equals(taskResp.getStatus().toLowerCase())) {
|
||||
logger.error("volcCallback request's status != official status! order third party order num = {}, request's status = {}, official status = {}",
|
||||
|
|
@ -501,7 +462,7 @@ public class ByteApiController extends BaseController {
|
|||
private AjaxResult volcCallbackRunningTaskProcess(GetVideoGenerationTaskResponse taskResp, AiOrder order) {
|
||||
// 执行中状态 ,更新到ext_status字段
|
||||
Integer extStatus = null;
|
||||
String status = taskResp.getStatus();
|
||||
String status = taskResp.getStatus().toLowerCase();
|
||||
if (VideoTaskStatusType.QUEUED.getName().equals(status)) {
|
||||
extStatus = 0;
|
||||
} else if (VideoTaskStatusType.RUNNING.getName().equals(status)) {
|
||||
|
|
@ -534,33 +495,33 @@ public class ByteApiController extends BaseController {
|
|||
// logger.warn("volcCallback code 非 200,已清空 result 并 status=2, orderId={}, {}", order.getId(), reason);
|
||||
// }
|
||||
|
||||
private AiOrder findAiOrderByVolcTaskId(String taskId) {
|
||||
AiOrder order = aiOrderService.getAiOrderByPortalVideoTask(taskId);
|
||||
if (order != null) {
|
||||
return order;
|
||||
}
|
||||
return aiOrderService.getAiOrderByResult(taskId);
|
||||
}
|
||||
// private AiOrder findAiOrderByVolcTaskId(String taskId) {
|
||||
// AiOrder order = aiOrderService.getAiOrderByPortalVideoTask(taskId);
|
||||
// if (order != null) {
|
||||
// return order;
|
||||
// }
|
||||
// return aiOrderService.getAiOrderByResult(taskId);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 回调判定任务失败:订单仍持有火山任务 id、且非已失败时,标记失败并退余额(orderFailure)。
|
||||
*/
|
||||
private void handleVolcCallbackFailure(String taskId, String reason) {
|
||||
AiOrder order = aiOrderService.getAiOrderByResult(taskId);
|
||||
if (order == null) {
|
||||
logger.warn("volcCallback 失败:未找到 result={} 的订单, {}", taskId, reason);
|
||||
return;
|
||||
}
|
||||
if (!taskId.equals(order.getResult())) {
|
||||
logger.info("volcCallback 失败处理跳过:订单结果已更新, taskId={}, {}", taskId, reason);
|
||||
return;
|
||||
}
|
||||
if (Integer.valueOf(2).equals(order.getStatus())) {
|
||||
return;
|
||||
}
|
||||
aiOrderService.orderFailure(order);
|
||||
logger.warn("volcCallback 任务失败,已标记订单失败并退款, taskId={}, reason={}", taskId, reason);
|
||||
}
|
||||
// private void handleVolcCallbackFailure(String taskId, String reason) {
|
||||
// AiOrder order = aiOrderService.getAiOrderByResult(taskId);
|
||||
// if (order == null) {
|
||||
// logger.warn("volcCallback 失败:未找到 result={} 的订单, {}", taskId, reason);
|
||||
// return;
|
||||
// }
|
||||
// if (!taskId.equals(order.getResult())) {
|
||||
// logger.info("volcCallback 失败处理跳过:订单结果已更新, taskId={}, {}", taskId, reason);
|
||||
// return;
|
||||
// }
|
||||
// if (Integer.valueOf(2).equals(order.getStatus())) {
|
||||
// return;
|
||||
// }
|
||||
// aiOrderService.orderFailure(order);
|
||||
// logger.warn("volcCallback 任务失败,已标记订单失败并退款, taskId={}, reason={}", taskId, reason);
|
||||
// }
|
||||
|
||||
// @PostMapping(value = "/{id}/cancel")
|
||||
// @ApiOperation("取消视频生成任务")
|
||||
|
|
|
|||
|
|
@ -272,19 +272,20 @@ public class PortalVideoController extends BaseController {
|
|||
|
||||
String key = apiKey();
|
||||
ByteBodyRes byteBodyRes = byteService.imgToVideo(byteBodyReq, key);
|
||||
String id = byteBodyRes.getId();
|
||||
if (id == null) {
|
||||
String thirdPartyOrderNumId = byteBodyRes.getId();
|
||||
if (thirdPartyOrderNumId == null) {
|
||||
aiOrderService.orderFailure(aiOrder);
|
||||
return AjaxResult.error(-2, "generation failed, balance has been refunded");
|
||||
}
|
||||
mergeVolcTaskIdIntoVideoParams(aiOrder, id);
|
||||
aiOrder.setResult(id);
|
||||
mergeVolcTaskIdIntoVideoParams(aiOrder, thirdPartyOrderNumId);
|
||||
aiOrder.setResult(thirdPartyOrderNumId);
|
||||
// 字节订单号与请求ID
|
||||
aiOrder.setThirdPartyOrderNum(id);
|
||||
aiOrder.setThirdPartyOrderNum(thirdPartyOrderNumId);
|
||||
aiOrder.setVideoGenRequestId(byteBodyRes.getRequestId());
|
||||
aiOrderService.orderSuccess(aiOrder);
|
||||
// aiOrderService.orderSuccess(aiOrder);
|
||||
aiOrderService.updateAiOrder(aiOrder);
|
||||
// 查询任务详情,按字节返回的预扣数量扣减
|
||||
GetVideoGenerationTaskResponse task = byteService.getVideoGenerationTasks(id, key);
|
||||
GetVideoGenerationTaskResponse task = byteService.getVideoGenerationTasks(thirdPartyOrderNumId, key);
|
||||
if (task == null || task.getUsage() == null || task.getUsage().getTotalTokens() == null) {
|
||||
return AjaxResult.error(-2, "generation failed, byte task's usage is null");
|
||||
}
|
||||
|
|
@ -292,16 +293,21 @@ public class PortalVideoController extends BaseController {
|
|||
return AjaxResult.error(-2, "generation failed, byte task's totalTokens <= 0");
|
||||
}
|
||||
BigDecimal totalTokens = new BigDecimal(task.getUsage().getTotalTokens());
|
||||
// 扣减余额
|
||||
aiUserService.addUserBalance(aiOrder.getOrderNum(), SecurityUtils.getAiUserId()
|
||||
, NumberUtil.mul(-1, totalTokens), aiOrderService.getChangerType(functionType));
|
||||
// 同步设置aiOrder,以防在抛异常时数值没变
|
||||
aiOrder.setPreDeductAmount(totalTokens);
|
||||
aiOrder.setAmount(totalTokens);
|
||||
|
||||
// 设置订单信息
|
||||
AiOrder updAiOrder = new AiOrder();
|
||||
updAiOrder.setId(aiOrder.getId());
|
||||
updAiOrder.setOrderNum(aiOrder.getOrderNum());
|
||||
updAiOrder.setPreDeductAmount(totalTokens);
|
||||
// 先设置成预扣数量,等收到回调再改过来,这样后续报表会比较准确
|
||||
updAiOrder.setAmount(totalTokens);
|
||||
aiOrderService.updateAiOrder(updAiOrder);
|
||||
// 扣减余额
|
||||
aiUserService.addUserBalance(aiOrder.getOrderNum(), SecurityUtils.getAiUserId()
|
||||
, NumberUtil.mul(-1, totalTokens), aiOrderService.getChangerType(functionType));
|
||||
return AjaxResult.success(byteBodyRes);
|
||||
} catch (Exception e) {
|
||||
aiOrderService.orderFailure(aiOrder);
|
||||
|
|
@ -626,19 +632,19 @@ public class PortalVideoController extends BaseController {
|
|||
return AjaxResult.success(byteBodyRes);
|
||||
}
|
||||
|
||||
@DeleteMapping("/tasks/{taskId}")
|
||||
@ApiOperation("删除或取消视频生成任务")
|
||||
public AjaxResult deleteOrCancelTask(@PathVariable String taskId) throws Exception {
|
||||
Long uid = SecurityUtils.getAiUserId();
|
||||
AiOrder owned = aiOrderService.getAiOrderByPortalVideoTask(taskId);
|
||||
if (owned == null || !uid.equals(owned.getUserId())) {
|
||||
return AjaxResult.error("无权操作该任务");
|
||||
}
|
||||
String key = apiKey();
|
||||
AjaxResult cancelRes = byteService.cancelVideoTask(taskId, key);
|
||||
if (cancelRes.isSuccess() && owned.getStatus() != null && owned.getStatus() == 0) {
|
||||
aiOrderService.orderFailure(owned);
|
||||
}
|
||||
return cancelRes;
|
||||
}
|
||||
// @DeleteMapping("/tasks/{taskId}")
|
||||
// @ApiOperation("删除或取消视频生成任务")
|
||||
// public AjaxResult deleteOrCancelTask(@PathVariable String taskId) throws Exception {
|
||||
// Long uid = SecurityUtils.getAiUserId();
|
||||
// AiOrder owned = aiOrderService.getAiOrderByPortalVideoTask(taskId);
|
||||
// if (owned == null || !uid.equals(owned.getUserId())) {
|
||||
// return AjaxResult.error("无权操作该任务");
|
||||
// }
|
||||
// String key = apiKey();
|
||||
// AjaxResult cancelRes = byteService.cancelVideoTask(taskId, key);
|
||||
// if (cancelRes.isSuccess() && owned.getStatus() != null && owned.getStatus() == 0) {
|
||||
// aiOrderService.orderFailure(owned);
|
||||
// }
|
||||
// return cancelRes;
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,8 +281,8 @@ portal:
|
|||
- 14
|
||||
- 15
|
||||
resolutions:
|
||||
- "480p"
|
||||
- "720p"
|
||||
- "1080p"
|
||||
|
||||
jinsha:
|
||||
url: https://api.jinshapay.xyz
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import java.util.List;
|
|||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.request.video.dto.VideoTaskCallBackRequest;
|
||||
import com.ruoyi.common.core.response.video.GetVideoGenerationTaskResponse;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
|
|
@ -92,4 +95,9 @@ public interface IAiOrderService {
|
|||
BigDecimal getSumAmountByUserId(String userId);
|
||||
|
||||
AiOrder selectOneByThirdPartyOrderNum(String id);
|
||||
|
||||
/**
|
||||
* 火山回调 - 任务成功时处理流程
|
||||
*/
|
||||
AjaxResult volcCallbackSuccessProcess(VideoTaskCallBackRequest request, GetVideoGenerationTaskResponse taskResp, AiOrder order);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.ByteBodyReq;
|
||||
import com.ruoyi.ai.domain.ByteBodyRes;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.request.video.dto.VideoTaskCallBackRequest;
|
||||
import com.ruoyi.common.core.response.video.GetVideoGenerationTaskResponse;
|
||||
|
||||
public interface IByteService {
|
||||
|
|
@ -55,5 +57,5 @@ public interface IByteService {
|
|||
/**
|
||||
* GET 查询视频生成任务(单个)
|
||||
*/
|
||||
GetVideoGenerationTaskResponse getVideoGenerationTasks(String id, String arkApiKey) throws Exception;
|
||||
GetVideoGenerationTaskResponse getVideoGenerationTasks(String thirdPartyOrderNumId, String arkApiKey) throws Exception;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,17 @@ import com.ruoyi.ai.service.IAiStatisticsService;
|
|||
import com.ruoyi.ai.service.IAiUserService;
|
||||
import com.ruoyi.common.constant.BalanceChangerConstants;
|
||||
import com.ruoyi.common.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||
import com.ruoyi.common.core.request.video.dto.VideoTaskCallBackRequest;
|
||||
import com.ruoyi.common.core.response.video.GetVideoGenerationTaskResponse;
|
||||
import com.ruoyi.common.enums.AiOrderStatusType;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -36,6 +42,7 @@ import java.util.UUID;
|
|||
* @author shi
|
||||
* @date 2025-11-13
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AiOrderServiceImpl implements IAiOrderService {
|
||||
|
||||
|
|
@ -51,6 +58,8 @@ public class AiOrderServiceImpl implements IAiOrderService {
|
|||
@Autowired
|
||||
private IAiStatisticsService aiStatisticsService;
|
||||
|
||||
// 任务成功时流水表备注
|
||||
private static final String TASK_SUCCESS_BALANCE_REMARK = "order.number.generation.successes";
|
||||
|
||||
/**
|
||||
* 查询订单管理
|
||||
|
|
@ -266,4 +275,53 @@ public class AiOrderServiceImpl implements IAiOrderService {
|
|||
public AiOrder selectOneByThirdPartyOrderNum(String id) {
|
||||
return aiOrderMapper.selectOneByThirdPartyOrderNum(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AjaxResult volcCallbackSuccessProcess(VideoTaskCallBackRequest request, GetVideoGenerationTaskResponse taskResp, AiOrder order) {
|
||||
// 用量是否一致
|
||||
Integer requestTotalTokens = request.getUsage() == null || request.getUsage().getTotalTokens() == null
|
||||
? 0 : request.getUsage().getTotalTokens();
|
||||
Integer officialTotalTokens = taskResp.getUsage() == null || taskResp.getUsage().getTotalTokens() == null
|
||||
? 0 : taskResp.getUsage().getTotalTokens();
|
||||
// !!!注意!!!
|
||||
// 以下检查不成立直接返回error,事务不会回退,所以不要在检查前面有存库操作
|
||||
// 这两个检查只是以防万一的,防止恶意回调,如果出现允许数据库中存在异常单,后续由程序通过日志检查问题
|
||||
if (!requestTotalTokens.equals(officialTotalTokens)) {
|
||||
log.error("volcCallback request's total tokens != official tokens! third party order num = {}, request's tokens = {}, official tokens = {}",
|
||||
request.getId(), requestTotalTokens, officialTotalTokens);
|
||||
return AjaxResult.error();
|
||||
}
|
||||
if (officialTotalTokens <= 0) {
|
||||
// 异常情况,应该不会出现,以防万一
|
||||
log.error("volcCallback official tokens <= 0! third party order num = {}, request's tokens = {}, official tokens = {}",
|
||||
request.getId(), requestTotalTokens, officialTotalTokens);
|
||||
return AjaxResult.error();
|
||||
}
|
||||
BigDecimal realAmount = new BigDecimal(officialTotalTokens);
|
||||
// 先存库再回补,防止订单保存时,会一直回补给用户
|
||||
// 设置视频地址与状态
|
||||
if (taskResp.getContent() != null && StringUtils.isNotEmpty(taskResp.getContent().getVideoUrl())) {
|
||||
order.setResult(taskResp.getContent().getVideoUrl());
|
||||
}
|
||||
// 设置用量
|
||||
order.setAmount(realAmount);
|
||||
// 订单状态
|
||||
order.setStatus(AiOrderStatusType.FINISH.ordinal());
|
||||
order.setIsBackfilled(1);
|
||||
orderSuccess(order);
|
||||
|
||||
// 用量回补、多退少补 = 预扣量 - 实际用量
|
||||
// 有预扣值才回补,没有的是历史单,不处理
|
||||
if (order.getPreDeductAmount() != null
|
||||
&& order.getPreDeductAmount().compareTo(new BigDecimal(0)) > 0) {
|
||||
BigDecimal addAmount = order.getPreDeductAmount().subtract(realAmount);
|
||||
if (addAmount.compareTo(new BigDecimal(0)) != 0) {
|
||||
// 回补
|
||||
aiUserService.addUserBalance(order.getOrderNum(), order.getUserId(), addAmount,
|
||||
BalanceChangerConstants.REFUND, TASK_SUCCESS_BALANCE_REMARK);
|
||||
}
|
||||
}
|
||||
return AjaxResult.success("callback success");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,17 @@ package com.ruoyi.ai.service.impl;
|
|||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.ByteBodyReq;
|
||||
import com.ruoyi.ai.domain.ByteBodyRes;
|
||||
import com.ruoyi.ai.service.IAiUserService;
|
||||
import com.ruoyi.ai.service.IByteDeptApiKeyService;
|
||||
import com.ruoyi.ai.service.IByteService;
|
||||
import com.ruoyi.common.constant.BalanceChangerConstants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.request.video.dto.VideoTaskCallBackRequest;
|
||||
import com.ruoyi.common.core.response.video.GetVideoGenerationTaskResponse;
|
||||
import com.ruoyi.common.enums.AiOrderStatusType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.http.OkHttpUtils;
|
||||
|
|
@ -18,6 +23,9 @@ import okhttp3.*;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
@ -241,15 +249,15 @@ public class ByteService implements IByteService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GetVideoGenerationTaskResponse getVideoGenerationTasks(String id, String arkApiKey) throws Exception {
|
||||
public GetVideoGenerationTaskResponse getVideoGenerationTasks(String thirdPartyOrderNumId, String arkApiKey) throws Exception {
|
||||
if (StringUtils.isBlank(arkApiKey)) {
|
||||
throw new Exception("getVideoGenerationTasks error:apiKey is null");
|
||||
}
|
||||
if (StringUtils.isBlank(id)) {
|
||||
throw new Exception("getVideoGenerationTasks error:id is null");
|
||||
if (StringUtils.isBlank(thirdPartyOrderNumId)) {
|
||||
throw new Exception("getVideoGenerationTasks error:thirdPartyOrderNumId is null");
|
||||
}
|
||||
|
||||
HttpUrl parsed = HttpUrl.parse(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id);
|
||||
HttpUrl parsed = HttpUrl.parse(volcBaseUrl + "/api/v3/contents/generations/tasks/" + thirdPartyOrderNumId);
|
||||
if (parsed == null) {
|
||||
throw new Exception("listVideoGenerationTasks error:invalid base url");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue