Files
smartDriveEE/src/main/java/com/rj/service/impl/VideoSynthesisServiceImpl.java
2025-10-12 09:37:43 +08:00

230 lines
9.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.rj.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rj.dto.VideoSynthesisRequestDto;
import com.rj.entity.VideoSynthesisLog;
import com.rj.mapper.VideoSynthesisLogMapper;
import com.rj.service.IVideoSynthesisService;
import com.rj.utils.MinIOUrlGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 视频合成服务实现类
*
* @author rj
* @date 2025-01-02
*/
@Slf4j
@Service
public class VideoSynthesisServiceImpl implements IVideoSynthesisService {
@Autowired
private VideoSynthesisLogMapper videoSynthesisLogMapper;
@Autowired
private RestTemplate restTemplate;
@Autowired
MinIOUrlGenerator minIOUrlGenerator ;
@Value("${dashscope.api.key}")
private String apiKey;
private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis/";
@Override
public VideoSynthesisLog synthesizeVideoAndSave(VideoSynthesisRequestDto request) {
LocalDateTime startTime = LocalDateTime.now();
String requestId = UUID.randomUUID().toString();
VideoSynthesisLog synthesisLog = new VideoSynthesisLog();
synthesisLog.setRequestId(requestId);
synthesisLog.setRequestTime(startTime);
synthesisLog.setSuccess(false);
// 使用BeanUtils复制相同名称的属性
BeanUtils.copyProperties(request, synthesisLog);
// 设置视频名称(如果请求中有提供)
if (request.getVideoName() != null && !request.getVideoName().trim().isEmpty()) {
synthesisLog.setVideoName(request.getVideoName());
log.info("设置视频名称: {}", request.getVideoName());
} else {
// 如果没有提供视频名称,使用默认名称
synthesisLog.setVideoName("视频合成_" + requestId.substring(0, 8));
log.info("使用默认视频名称: {}", synthesisLog.getVideoName());
}
// 设置图像区域坐标(如果请求中有提供)
if (request.getFaceBbox() != null && !request.getFaceBbox().trim().isEmpty()) {
synthesisLog.setFaceBbox(request.getFaceBbox());
log.info("设置图像区域坐标: {}", request.getFaceBbox());
}
// 设置动态区域坐标(如果请求中有提供)
if (request.getExtBbox() != null && !request.getExtBbox().trim().isEmpty()) {
synthesisLog.setExtBbox(request.getExtBbox());
log.info("设置动态区域坐标: {}", request.getExtBbox());
}
try {
log.info("开始视频合成请求ID: {}, 图片URL: {}, 音频URL: {}",
requestId, request.getImageUrl(), request.getAudioUrl());
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("X-DashScope-Async", "enable");
headers.set("Authorization", "Bearer " + apiKey);
request.buildParam();
// 构建请求体
HttpEntity<VideoSynthesisRequestDto> entity = new HttpEntity<>(request, headers);
log.info("开始视频合成entity : {} ",entity);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(API_URL, entity, String.class);
LocalDateTime endTime = LocalDateTime.now();
synthesisLog.setResponseTime(endTime);
synthesisLog.setProcessingTimeMs(java.time.Duration.between(startTime, endTime).toMillis());
// 解析响应
if (response.getStatusCode() == HttpStatus.OK) {
// 直接解析JSON响应
String responseBody = response.getBody();
log.info("API响应: {}", responseBody);
// 解析JSON响应
if (responseBody != null && !responseBody.trim().isEmpty()) {
try {
// 使用fastjson解析JSON响应
JSONObject responseJson = JSON.parseObject(responseBody);
// 提取task_id
if (responseJson.containsKey("output")) {
JSONObject output = responseJson.getJSONObject("output");
if (output != null && output.containsKey("task_id")) {
String taskId = output.getString("task_id");
synthesisLog.setTaskId(taskId);
log.info("提取到任务ID: {}", taskId);
}
}
// 设置基本状态
synthesisLog.setTaskStatus("PENDING");
synthesisLog.setSuccess(true);
// 生成临时访问URL7天有效期
try {
log.info("即将用音频名称: {} 生成临时访问URL", synthesisLog.getVideoName());
String tempUrl = generateTempVideoUrl(synthesisLog.getVideoName(), requestId);
synthesisLog.setVideoTempUrl(tempUrl);
log.info("生成临时访问URL: {}", tempUrl);
} catch (Exception e) {
log.warn("生成临时访问URL失败: {}", e.getMessage());
// 临时URL生成失败不影响主流程
}
} catch (Exception e) {
log.error("解析API响应JSON失败: {}", e.getMessage(), e);
synthesisLog.setErrorMessage("解析API响应失败: " + e.getMessage());
synthesisLog.setSuccess(false);
}
} else {
synthesisLog.setErrorMessage("API响应为空");
synthesisLog.setSuccess(false);
}
log.info("视频合成请求成功任务ID: {}, 状态: {}",
synthesisLog.getTaskId(), synthesisLog.getTaskStatus());
} else {
synthesisLog.setErrorMessage("HTTP请求失败状态码: " + response.getStatusCode());
log.error("视频合成请求失败,状态码: {}, 响应: {}", response.getStatusCode(), response.getBody());
}
} catch (Exception e) {
LocalDateTime endTime = LocalDateTime.now();
synthesisLog.setResponseTime(endTime);
synthesisLog.setProcessingTimeMs(java.time.Duration.between(startTime, endTime).toMillis());
synthesisLog.setErrorMessage("视频合成异常: " + e.getMessage());
log.error("视频合成失败: {}", e.getMessage(), e);
}
// 保存日志
saveVideoSynthesisLog(synthesisLog);
return synthesisLog;
}
@Override
public boolean saveVideoSynthesisLog(VideoSynthesisLog synthesisLog) {
try {
synthesisLog.setCreatedAt(LocalDateTime.now());
synthesisLog.setUpdatedAt(LocalDateTime.now());
int result = videoSynthesisLogMapper.insert(synthesisLog);
log.info("视频合成日志保存{}: 请求ID={}, 任务ID={}, 成功={}",
result > 0 ? "成功" : "失败", synthesisLog.getRequestId(), synthesisLog.getTaskId(), synthesisLog.getSuccess());
return result > 0;
} catch (Exception e) {
log.error("保存视频合成日志失败: {}", e.getMessage(), e);
return false;
}
}
@Override
public VideoSynthesisLog getVideoSynthesisLogByRequestId(String requestId) {
try {
return videoSynthesisLogMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<VideoSynthesisLog>()
.eq("request_id", requestId)
);
} catch (Exception e) {
log.error("根据请求ID查询视频合成日志失败: {}", e.getMessage(), e);
return null;
}
}
@Override
public VideoSynthesisLog getVideoSynthesisLogByTaskId(String taskId) {
try {
return videoSynthesisLogMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<VideoSynthesisLog>()
.eq("task_id", taskId)
);
} catch (Exception e) {
log.error("根据任务ID查询视频合成日志失败: {}", e.getMessage(), e);
return null;
}
}
/**
* 生成临时视频访问URL
*
* @param videoName 视频名称
* @param requestId 请求ID
* @return 临时访问URL
*/
private String generateTempVideoUrl(String videoName, String requestId) {
try {
return minIOUrlGenerator.generateTempUrl(videoName, 7, TimeUnit.DAYS).getUrl();
} catch (Exception e) {
log.error("生成临时视频URL失败: {}", e.getMessage(), e);
return null;
}
}
}