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

437 lines
19 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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.DetectVideoTemplate;
import com.rj.mapper.DetectVideoTemplateMapper;
import com.rj.service.IDetectVideoTemplateService;
import com.rj.service.MinIOService;
import com.rj.utils.MinIOUrlGenerator;
import lombok.extern.slf4j.Slf4j;
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 org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 检测视频模板日志服务实现
*/
@Slf4j
@Service
public class DetectVideoTemplateServiceImpl extends ServiceImpl<DetectVideoTemplateMapper, DetectVideoTemplate> implements IDetectVideoTemplateService {
private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/aa-template-generation";
@Value("${dashscope.api.key:}")
private String apiKey;
@Autowired
private MinIOService minioService;
@Autowired
private MinIOUrlGenerator urlGenerator;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
public DetectVideoTemplateServiceImpl() {
this.restTemplate = new RestTemplate();
this.objectMapper = new ObjectMapper();
}
@Override
public boolean saveDetectVideoTemplateLog(DetectVideoTemplate detectVideoTemplate) {
try {
return save(detectVideoTemplate);
} catch (Exception e) {
log.error("保存检测视频模板日志失败: {}", e.getMessage(), e);
return false;
}
}
/**
* 执行视频模板检测并保存日志
*/
public DetectVideoTemplate detectVideoTemplateAndSave(String videoUrl, String ownerName, String ownerPhone, String templateName, String model) {
if (apiKey == null || apiKey.trim().isEmpty()) {
log.error("DASHSCOPE_API_KEY未配置");
return createErrorLog(videoUrl, "DASHSCOPE_API_KEY未配置", ownerName, ownerPhone, templateName);
}
// 创建日志记录
DetectVideoTemplate detectVideoTemplate = new DetectVideoTemplate();
String requestId = UUID.randomUUID().toString();
LocalDateTime requestTime = LocalDateTime.now();
detectVideoTemplate.setRequestId(requestId);
// 设置模型名称,如果未提供则使用默认值
String modelName = (model != null && !model.trim().isEmpty()) ? model : "animate-anyone-template-gen2";
detectVideoTemplate.setModel(modelName);
log.info("使用模型: {}", modelName);
detectVideoTemplate.setVideoUrl(videoUrl);
detectVideoTemplate.setOwnerName(ownerName);
detectVideoTemplate.setOwnerPhone(ownerPhone);
detectVideoTemplate.setTemplateName(templateName);
detectVideoTemplate.setRequestTime(requestTime);
long startTime = System.currentTimeMillis();
try {
// 创建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", modelName);
Map<String, String> input = new HashMap<>();
input.put("video_url", videoUrl);
requestBody.put("input", input);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(apiKey);
// 添加异步调用请求头
headers.set("X-DashScope-Async", "enable");
log.info("发送视频模板检测请求requestBody : {}, 请求参数headers: {}", requestBody , headers);
// 创建请求实体
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(API_URL, requestEntity, String.class);
log.info("发送视频模板检测请求response: {}, 视频URL: {}", response, videoUrl);
// 计算处理时间
long endTime = System.currentTimeMillis();
long processingTime = endTime - startTime;
// 更新日志记录
detectVideoTemplate.setResponseTime(LocalDateTime.now());
detectVideoTemplate.setStatusCode(response.getStatusCode().value());
detectVideoTemplate.setProcessingTimeMs(processingTime);
detectVideoTemplate.setResponseData(response.getBody());
// 处理响应
log.info("视频模板检测响应,状态码: {}, 处理时间: {}ms", response.getStatusCode(), processingTime);
// 解析JSON响应
if (response.getStatusCode() == HttpStatus.OK) {
JsonNode jsonResponse = objectMapper.readTree(response.getBody());
// 解析响应数据
if (jsonResponse.has("output")) {
JsonNode output = jsonResponse.get("output");
// 解析任务ID
if (output.has("task_id")) {
String taskId = output.get("task_id").asText();
detectVideoTemplate.setTaskId(taskId);
log.info("任务ID: {}", taskId);
}
// 解析任务状态
if (output.has("task_status")) {
String taskStatus = output.get("task_status").asText();
detectVideoTemplate.setTaskStatus(taskStatus);
log.info("任务状态: {}", taskStatus);
// 根据任务状态判断是否成功
boolean isSuccess = "SUCCESS".equalsIgnoreCase(taskStatus) || "COMPLETED".equalsIgnoreCase(taskStatus);
detectVideoTemplate.setSuccess(isSuccess);
}
}
// 记录message信息
if (jsonResponse.has("request_id")) {
String request_id = jsonResponse.get("request_id").asText();
detectVideoTemplate.setRequestId(request_id);
}
} else {
// HTTP状态码不是200直接标记为失败
detectVideoTemplate.setSuccess(false);
}
// 保存到数据库
boolean saved = saveDetectVideoTemplateLog(detectVideoTemplate);
if (saved) {
log.info("视频模板检测日志已保存请求ID: {}", requestId);
} else {
log.error("保存视频模板检测日志失败请求ID: {}", requestId);
}
return detectVideoTemplate;
} catch (HttpClientErrorException e) {
return handleError(detectVideoTemplate, e, "客户端错误 (4xx): " + e.getStatusCode(), startTime);
} catch (HttpServerErrorException e) {
return handleError(detectVideoTemplate, e, "服务器错误 (5xx): " + e.getStatusCode(), startTime);
} catch (Exception e) {
return handleError(detectVideoTemplate, e, "视频模板检测请求失败: " + e.getMessage(), startTime);
}
}
/**
* 处理错误并保存到数据库
*/
private DetectVideoTemplate handleError(DetectVideoTemplate detectVideoTemplate, Exception e, String errorMessage, long startTime) {
long endTime = System.currentTimeMillis();
long processingTime = endTime - startTime;
detectVideoTemplate.setResponseTime(LocalDateTime.now());
detectVideoTemplate.setSuccess(false);
detectVideoTemplate.setProcessingTimeMs(processingTime);
detectVideoTemplate.setErrorMessage(errorMessage);
if (e instanceof HttpClientErrorException) {
detectVideoTemplate.setStatusCode(((HttpClientErrorException) e).getStatusCode().value());
detectVideoTemplate.setResponseData(((HttpClientErrorException) e).getResponseBodyAsString());
} else if (e instanceof HttpServerErrorException) {
detectVideoTemplate.setStatusCode(((HttpServerErrorException) e).getStatusCode().value());
detectVideoTemplate.setResponseData(((HttpServerErrorException) e).getResponseBodyAsString());
}
log.error("视频模板检测失败: {}", errorMessage);
log.error("错误详情: {}", e.getMessage());
// 保存错误日志到数据库
try {
saveDetectVideoTemplateLog(detectVideoTemplate);
log.info("错误日志已保存请求ID: {}", detectVideoTemplate.getRequestId());
} catch (Exception saveException) {
log.error("保存错误日志失败: {}", saveException.getMessage());
}
return detectVideoTemplate;
}
/**
* 创建错误日志
*/
private DetectVideoTemplate createErrorLog(String videoUrl, String errorMessage, String ownerName, String ownerPhone, String templateName) {
DetectVideoTemplate detectVideoTemplate = new DetectVideoTemplate();
detectVideoTemplate.setRequestId(UUID.randomUUID().toString());
detectVideoTemplate.setModel("video-template-detect");
detectVideoTemplate.setVideoUrl(videoUrl);
detectVideoTemplate.setOwnerName(ownerName);
detectVideoTemplate.setOwnerPhone(ownerPhone);
detectVideoTemplate.setTemplateName(templateName);
detectVideoTemplate.setRequestTime(LocalDateTime.now());
detectVideoTemplate.setResponseTime(LocalDateTime.now());
detectVideoTemplate.setSuccess(false);
detectVideoTemplate.setErrorMessage(errorMessage);
try {
saveDetectVideoTemplateLog(detectVideoTemplate);
} catch (Exception e) {
log.error("保存错误日志失败: {}", e.getMessage());
}
return detectVideoTemplate;
}
/**
* 分页查询检测视频模板日志
*/
@Override
public com.baomidou.mybatisplus.extension.plugins.pagination.Page<DetectVideoTemplate> getPageList(
Integer current, Integer size, Boolean success, String startTime, String endTime,
String ownerName, String ownerPhone, String templateName) {
com.baomidou.mybatisplus.extension.plugins.pagination.Page<DetectVideoTemplate> page =
new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(current, size);
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DetectVideoTemplate> queryWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 添加查询条件
if (success != null) {
queryWrapper.eq(DetectVideoTemplate::getSuccess, success);
}
if (startTime != null && !startTime.trim().isEmpty()) {
queryWrapper.ge(DetectVideoTemplate::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
queryWrapper.le(DetectVideoTemplate::getRequestTime, endTime);
}
if (ownerName != null && !ownerName.trim().isEmpty()) {
queryWrapper.like(DetectVideoTemplate::getOwnerName, ownerName);
}
if (ownerPhone != null && !ownerPhone.trim().isEmpty()) {
queryWrapper.like(DetectVideoTemplate::getOwnerPhone, ownerPhone);
}
if (templateName != null && !templateName.trim().isEmpty()) {
queryWrapper.like(DetectVideoTemplate::getTemplateName, templateName);
}
// 按请求时间倒序排列
queryWrapper.orderByDesc(DetectVideoTemplate::getRequestTime);
return page(page, queryWrapper);
}
/**
* 获取统计信息
*/
@Override
public Map<String, Object> getStatistics(String startTime, String endTime) {
Map<String, Object> statistics = new HashMap<>();
// 构建查询条件
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DetectVideoTemplate> queryWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 时间范围筛选
if (startTime != null && !startTime.trim().isEmpty()) {
queryWrapper.ge(DetectVideoTemplate::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
queryWrapper.le(DetectVideoTemplate::getRequestTime, endTime);
}
// 查询总数
long totalCount = count(queryWrapper);
// 查询成功数
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DetectVideoTemplate> successWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 时间范围筛选
if (startTime != null && !startTime.trim().isEmpty()) {
successWrapper.ge(DetectVideoTemplate::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
successWrapper.le(DetectVideoTemplate::getRequestTime, endTime);
}
successWrapper.eq(DetectVideoTemplate::getSuccess, true);
long successCount = count(successWrapper);
// 查询失败数
long failureCount = totalCount - successCount;
// 计算成功率
double successRate = totalCount > 0 ? (double) successCount / totalCount * 100 : 0;
// 查询平均处理时间
java.util.List<DetectVideoTemplate> logs = list(queryWrapper);
double avgProcessingTime = logs.stream()
.filter(log -> log.getProcessingTimeMs() != null)
.mapToLong(DetectVideoTemplate::getProcessingTimeMs)
.average()
.orElse(0.0);
// 构建统计结果
statistics.put("totalCount", totalCount);
statistics.put("successCount", successCount);
statistics.put("failureCount", failureCount);
statistics.put("successRate", Math.round(successRate * 100.0) / 100.0);
statistics.put("avgProcessingTimeMs", Math.round(avgProcessingTime));
log.info("统计信息查询完成,总数: {}, 成功数: {}, 失败数: {}, 成功率: {}%",
totalCount, successCount, failureCount, successRate);
return statistics;
}
/**
* 上传视频模板文件并进行检测
*/
@Override
public DetectVideoTemplate uploadAndDetectVideoTemplate(MultipartFile file, String userId, String ownerName,
String ownerPhone, String templateName, String model, int expiresInSeconds) {
try {
log.info("开始处理视频模板上传,文件名: {}, 大小: {} bytes, 用户ID: {}",
file.getOriginalFilename(), file.getSize(), userId);
// 1. 验证文件
if (file.isEmpty()) {
return createErrorLog("", "文件不能为空", ownerName, ownerPhone, templateName);
}
// 验证文件类型
String contentType = file.getContentType();
if (contentType == null || (!contentType.startsWith("video/"))) {
return createErrorLog("", "只支持视频文件格式", ownerName, ownerPhone, templateName);
}
// 验证文件大小限制为100MB
if (file.getSize() > 100 * 1024 * 1024) {
return createErrorLog("", "文件大小不能超过100MB", ownerName, ownerPhone, templateName);
}
// 2. 上传文件到MinIO
log.info("开始上传视频文件到MinIO...");
String fileUrl = minioService.uploadFile(file);
log.info("视频文件上传成功URL: {}", fileUrl);
// 3. 生成短链接临时访问URL
log.info("开始生成短链接,有效期: {}秒", expiresInSeconds);
String fileName = extractFileNameFromUrl(fileUrl);
MinIOUrlGenerator.UrlInfo urlInfo = urlGenerator.generateTempUrl(fileName, expiresInSeconds);
if (!urlInfo.isSuccess()) {
return createErrorLog(fileUrl, "生成短链接失败: " + urlInfo.getErrorMessage(), ownerName, ownerPhone, templateName);
}
String shortUrl = urlInfo.getUrl();
log.info("短链接生成成功: {}", shortUrl);
// 4. 进行视频模板检测
log.info("开始进行视频模板检测,使用模型: {}", model != null ? model : "默认模型");
DetectVideoTemplate detectLog = detectVideoTemplateAndSave(shortUrl, ownerName, ownerPhone, templateName, model);
// 5. 更新日志记录,添加文件信息和临时链接信息
detectLog.setVideoUrl(fileUrl);
detectLog.setRequestId(detectLog.getRequestId()); // 保持原有的requestId
detectLog.setTempUrl(shortUrl);
detectLog.setTempUrlExpiresAt(urlInfo.getExpiresAt());
// 如果检测日志中有task_id也保存到数据库
if (detectLog.getTaskId() != null) {
detectLog.setTaskId(detectLog.getTaskId());
}
// 保存更新后的日志
saveDetectVideoTemplateLog(detectLog);
log.info("视频模板上传和检测处理完成文件URL: {}, 短链接: {}", fileUrl, shortUrl);
return detectLog;
} catch (Exception e) {
log.error("视频模板上传和检测失败: {}", e.getMessage(), e);
return createErrorLog("", "视频模板上传和检测失败: " + e.getMessage(), ownerName, ownerPhone, templateName);
}
}
/**
* 从URL中提取文件名
*/
private String extractFileNameFromUrl(String fileUrl) {
if (fileUrl == null || fileUrl.trim().isEmpty()) {
return null;
}
// 从URL中提取文件名
// 例如: http://101.35.52.237:19005/car/20251009_105616_48320fc2d8e24f7bb4be66cbb54a6512.jpg
// 提取: 20251009_105616_48320fc2d8e24f7bb4be66cbb54a6512.jpg
String[] parts = fileUrl.split("/");
if (parts.length > 0) {
return parts[parts.length - 1];
}
return null;
}
}