生成记录

This commit is contained in:
2025-11-23 13:24:19 +08:00
parent 98e244e60b
commit 5080ce3168
2 changed files with 146 additions and 15 deletions

View File

@@ -6,6 +6,8 @@ import cn.hutool.http.HttpResponse;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.tik.file.dal.dataobject.TikUserFileDO;
import cn.iocoder.yudao.module.tik.file.dal.mysql.TikUserFileMapper;
import cn.iocoder.yudao.module.tik.file.service.TikOssInitService;
import cn.iocoder.yudao.module.tik.voice.dal.dataobject.TikDigitalHumanTaskDO;
import cn.iocoder.yudao.module.tik.voice.dal.mysql.TikDigitalHumanTaskMapper;
@@ -42,6 +44,7 @@ public class LatentsyncPollingService {
private final RedissonClient redissonClient;
private final TikOssInitService ossInitService;
private final cn.iocoder.yudao.module.infra.api.file.FileApi fileApi;
private final TikUserFileMapper userFileMapper;
/**
* Redis键前缀
@@ -213,14 +216,14 @@ public class LatentsyncPollingService {
}
// 保存视频到OSS异步处理轻量化逻辑
String savedVideoUrl = videoUrl;
OssSaveResult saveResult = null;
try {
// 保存视频到OSS避免临时URL过期
savedVideoUrl = saveVideoToOss(task, videoUrl);
log.info("[handleTaskCompleted][任务({})视频已保存到OSS][url={}]", taskId, savedVideoUrl);
saveResult = saveVideoToOss(task, videoUrl);
log.info("[handleTaskCompleted][任务({})视频已保存到OSS][url={}]", taskId, saveResult.getUrl());
} catch (Exception e) {
log.warn("[handleTaskCompleted][任务({})保存视频失败使用原URL][error={}]", taskId, e.getMessage());
savedVideoUrl = videoUrl; // 降级处理
saveResult = new OssSaveResult(videoUrl, 0, null); // 降级处理
}
// 更新任务状态为成功
@@ -229,18 +232,21 @@ public class LatentsyncPollingService {
updateObj.setStatus("SUCCESS");
updateObj.setCurrentStep("finishing");
updateObj.setProgress(100);
updateObj.setResultVideoUrl(savedVideoUrl);
updateObj.setResultVideoUrl(saveResult.getUrl());
updateObj.setFinishTime(LocalDateTime.now());
taskMapper.updateById(updateObj);
// 缓存结果到Redis快速回显
try {
String resultKey = "digital_human:task:result:" + taskId;
stringRedisTemplate.opsForValue().set(resultKey, savedVideoUrl, Duration.ofHours(24));
stringRedisTemplate.opsForValue().set(resultKey, saveResult.getUrl(), Duration.ofHours(24));
} catch (Exception e) {
log.warn("[handleTaskCompleted][任务({})缓存结果失败]", taskId, e);
}
// 保存结果视频到用户文件表(这样用户可以在素材库中查看)
saveResultVideoToUserFiles(task, saveResult);
// 从轮询队列中移除
removeFromPollingQueue(taskId, requestId);
@@ -355,8 +361,9 @@ public class LatentsyncPollingService {
/**
* 保存视频到OSS - 流式处理优化内存
* 返回保存结果包含URL和文件大小
*/
private String saveVideoToOss(TikDigitalHumanTaskDO task, String remoteVideoUrl) throws Exception {
private OssSaveResult saveVideoToOss(TikDigitalHumanTaskDO task, String remoteVideoUrl) throws Exception {
log.info("[saveVideoToOss][任务({})开始下载并保存视频到OSS][remoteUrl={}]", task.getId(), remoteVideoUrl);
try {
@@ -382,14 +389,44 @@ public class LatentsyncPollingService {
// 6. 移除预签名URL中的签名参数获取基础URL
String cleanOssUrl = HttpUtils.removeUrlQuery(ossUrl);
// 7. 生成文件路径(用于后续删除)
String filePath = baseDirectory + "/" + fileName;
log.info("[saveVideoToOss][任务({})视频保存到OSS完成][directory={}, fileName={}, ossUrl={}]",
task.getId(), baseDirectory, fileName, cleanOssUrl);
return cleanOssUrl;
return new OssSaveResult(cleanOssUrl, videoBytes.length, filePath);
} catch (Exception e) {
log.error("[saveVideoToOss][任务({})保存视频到OSS失败][remoteUrl={}]", task.getId(), remoteVideoUrl, e);
// 如果保存失败返回原始URL降级处理
return remoteVideoUrl;
return new OssSaveResult(remoteVideoUrl, 0, null);
}
}
/**
* OSS保存结果
*/
private static class OssSaveResult {
private final String url;
private final int fileSize;
private final String filePath;
public OssSaveResult(String url, int fileSize, String filePath) {
this.url = url;
this.fileSize = fileSize;
this.filePath = filePath;
}
public String getUrl() {
return url;
}
public int getFileSize() {
return fileSize;
}
public String getFilePath() {
return filePath;
}
}
@@ -414,4 +451,48 @@ public class LatentsyncPollingService {
}
}
/**
* 保存结果视频到用户文件表
* 这样用户就可以在素材库中查看和管理生成的文件
*/
private void saveResultVideoToUserFiles(TikDigitalHumanTaskDO task, OssSaveResult saveResult) {
try {
Long userId = task.getUserId();
if (userId == null) {
log.warn("[saveResultVideoToUserFiles][任务({})用户ID为空无法保存文件]", task.getId());
return;
}
// 验证结果视频URL
String resultVideoUrl = saveResult.getUrl();
if (StrUtil.isBlank(resultVideoUrl)) {
log.warn("[saveResultVideoToUserFiles][任务({})结果视频URL为空无法保存文件]", task.getId());
return;
}
// 生成文件名使用任务ID和时间戳
String fileName = String.format("数字人视频_%d_%d.mp4", task.getId(), System.currentTimeMillis());
// 创建用户文件记录
TikUserFileDO userFile = new TikUserFileDO();
userFile.setUserId(userId);
userFile.setFileName(fileName);
userFile.setFileType("video/mp4");
userFile.setFileCategory("generate"); // 文件分类:生成文件
userFile.setFileUrl(resultVideoUrl);
userFile.setFilePath(saveResult.getFilePath()); // 设置文件路径(用于后续删除)
userFile.setFileSize((long) saveResult.getFileSize()); // 设置文件大小
userFile.setDescription("数字人生成结果视频任务ID" + task.getId());
// 插入到用户文件表
userFileMapper.insert(userFile);
log.info("[saveResultVideoToUserFiles][任务({})结果视频已保存到用户文件表,文件编号({})]",
task.getId(), userFile.getId());
} catch (Exception e) {
// 保存失败不影响主流程,只记录日志
log.error("[saveResultVideoToUserFiles][任务({})保存结果视频到用户文件表失败]", task.getId(), e);
}
}
}