From 45d061bad7b738d1f7003d71fe23fcd0c7bbd99d Mon Sep 17 00:00:00 2001 From: spllzh <28668817@qq.com> Date: Wed, 8 Oct 2025 08:02:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=B4=E5=83=8F=E8=A7=86=E9=A2=91=E5=90=88?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rj/common/PasswordUtil.java | 3 + .../java/com/rj/common/ServiceManager.java | 3 + src/main/java/com/rj/config/AliyunConfig.java | 3 + .../controller/TtsRequestLogController.java | 2 +- .../VideoSynthesisFromController.java | 81 +++- .../com/rj/controller/sys/MenuController.java | 3 + .../com/rj/controller/sys/RoleController.java | 3 + .../rj/controller/sys/UserRoleController.java | 3 + .../com/rj/dto/DifyWorkflowResponseDto.java | 3 + .../com/rj/dto/VideoSynthesisRequestDto.java | 51 ++- .../mapper/CustomerProfileAnalysisMapper.java | 3 + .../scheduler/AudioStatisticsScheduler.java | 3 + .../VideoSynthesisStatusScheduler.java | 358 ++++++++++++++++++ .../biz/ICustomerProfileAnalysisService.java | 3 + .../CustomerProfileAnalysisServiceImpl.java | 3 + .../impl/VideoSynthesisServiceImpl.java | 37 +- .../java/com/rj/service/sys/IMenuService.java | 3 + .../com/rj/service/sys/IUserRoleService.java | 3 + .../rj/service/sys/impl/MenuServiceImpl.java | 3 + .../rj/service/sys/impl/RoleServiceImpl.java | 3 + .../service/sys/impl/UserRoleServiceImpl.java | 3 + src/main/resources/application-audio.yml | 3 + .../AudioManagementStatisticsMapper.xml | 3 + src/main/resources/static/tts-demo.html | 3 + .../sql/add_audio_management_sales_phone.sql | 3 + .../sql/add_audio_name_to_tts_request_log.sql | 3 + .../VideoSynthesisStatusSchedulerTest.java | 107 ++++++ .../rj/service/TtsRequestLogShortUrlTest.java | 3 + 28 files changed, 689 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/rj/scheduler/VideoSynthesisStatusScheduler.java create mode 100644 src/test/java/com/rj/scheduler/VideoSynthesisStatusSchedulerTest.java diff --git a/src/main/java/com/rj/common/PasswordUtil.java b/src/main/java/com/rj/common/PasswordUtil.java index 28e5b14..c87db01 100644 --- a/src/main/java/com/rj/common/PasswordUtil.java +++ b/src/main/java/com/rj/common/PasswordUtil.java @@ -135,6 +135,9 @@ public class PasswordUtil { + + + diff --git a/src/main/java/com/rj/common/ServiceManager.java b/src/main/java/com/rj/common/ServiceManager.java index 692e8d7..28217cf 100644 --- a/src/main/java/com/rj/common/ServiceManager.java +++ b/src/main/java/com/rj/common/ServiceManager.java @@ -119,6 +119,9 @@ public class ServiceManager { + + + diff --git a/src/main/java/com/rj/config/AliyunConfig.java b/src/main/java/com/rj/config/AliyunConfig.java index 5795b11..ae459f2 100644 --- a/src/main/java/com/rj/config/AliyunConfig.java +++ b/src/main/java/com/rj/config/AliyunConfig.java @@ -97,6 +97,9 @@ public class AliyunConfig { + + + diff --git a/src/main/java/com/rj/controller/TtsRequestLogController.java b/src/main/java/com/rj/controller/TtsRequestLogController.java index 48fbab8..b926d0c 100644 --- a/src/main/java/com/rj/controller/TtsRequestLogController.java +++ b/src/main/java/com/rj/controller/TtsRequestLogController.java @@ -26,7 +26,7 @@ import java.util.Map; @Slf4j @RestController @RequestMapping("/api/tts/log") -@Tag(name = "TTS请求日志", description = "TTS请求日志管理接口") +@Tag(name = "TTS请求日志", description = "音频合成,TTS请求日志管理接口") public class TtsRequestLogController { @Autowired diff --git a/src/main/java/com/rj/controller/VideoSynthesisFromController.java b/src/main/java/com/rj/controller/VideoSynthesisFromController.java index 7f901b4..690dc2d 100644 --- a/src/main/java/com/rj/controller/VideoSynthesisFromController.java +++ b/src/main/java/com/rj/controller/VideoSynthesisFromController.java @@ -1,7 +1,10 @@ package com.rj.controller; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.rj.dto.VideoSynthesisRequestDto; import com.rj.entity.VideoSynthesisLog; +import com.rj.mapper.VideoSynthesisLogMapper; import com.rj.service.IVideoSynthesisService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -29,6 +32,9 @@ public class VideoSynthesisFromController { @Autowired private IVideoSynthesisService videoSynthesisService; + + @Autowired + private VideoSynthesisLogMapper videoSynthesisLogMapper; /** * 视频合成接口 @@ -47,7 +53,7 @@ public class VideoSynthesisFromController { // 构建响应结果 result.put("success", synthesisLog.getSuccess()); - result.put("message", synthesisLog.getSuccess() ? "视频合成成功" : "视频合成失败"); + result.put("message", synthesisLog.getTaskStatus()); result.put("requestId", synthesisLog.getRequestId()); result.put("taskId", synthesisLog.getTaskId()); result.put("taskStatus", synthesisLog.getTaskStatus()); @@ -177,4 +183,77 @@ public class VideoSynthesisFromController { return ResponseEntity.internalServerError().body(result); } } + + /** + * 分页查询视频合成日志列表 + */ + @GetMapping("/list") + @Operation(summary = "查询视频合成日志列表", description = "分页查询视频合成日志") + public ResponseEntity> getVideoSynthesisLogs( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer pageNum, + @Parameter(description = "每页大小") @RequestParam(defaultValue = "10") Integer pageSize, + @Parameter(description = "任务状态") @RequestParam(required = false) String taskStatus, + @Parameter(description = "模型") @RequestParam(required = false) String model, + @Parameter(description = "模型供应商") @RequestParam(required = false) String modelProvider, + @Parameter(description = "归属人姓名") @RequestParam(required = false) String ownerName, + @Parameter(description = "归属人电话") @RequestParam(required = false) String ownerPhone, + @Parameter(description = "是否成功") @RequestParam(required = false) Boolean success, + @Parameter(description = "开始时间") @RequestParam(required = false) String startTime, + @Parameter(description = "结束时间") @RequestParam(required = false) String endTime) { + + Map result = new HashMap<>(); + + try { + Page page = new Page<>(pageNum, pageSize); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 添加查询条件 + if (taskStatus != null && !taskStatus.trim().isEmpty()) { + queryWrapper.eq("task_status", taskStatus); + } + if (model != null && !model.trim().isEmpty()) { + queryWrapper.like("model", model); + } + if (modelProvider != null && !modelProvider.trim().isEmpty()) { + queryWrapper.like("model_provider", modelProvider); + } + if (ownerName != null && !ownerName.trim().isEmpty()) { + queryWrapper.like("owner_name", ownerName); + } + if (ownerPhone != null && !ownerPhone.trim().isEmpty()) { + queryWrapper.like("owner_phone", ownerPhone); + } + if (success != null) { + queryWrapper.eq("success", success); + } + if (startTime != null && !startTime.trim().isEmpty()) { + queryWrapper.ge("request_time", startTime); + } + if (endTime != null && !endTime.trim().isEmpty()) { + queryWrapper.le("request_time", endTime); + } + + // 按请求时间倒序排列 + queryWrapper.orderByDesc("request_time"); + + // 执行查询 + Page pageResult = videoSynthesisLogMapper.selectPage(page, queryWrapper); + + result.put("success", true); + result.put("message", "查询成功"); + result.put("data", pageResult.getRecords()); + result.put("total", pageResult.getTotal()); + result.put("pageNum", pageResult.getCurrent()); + result.put("pageSize", pageResult.getSize()); + result.put("pages", pageResult.getPages()); + + return ResponseEntity.ok(result); + + } catch (Exception e) { + log.error("查询视频合成日志失败: {}", e.getMessage(), e); + result.put("success", false); + result.put("message", "查询失败: " + e.getMessage()); + return ResponseEntity.status(500).body(result); + } + } } diff --git a/src/main/java/com/rj/controller/sys/MenuController.java b/src/main/java/com/rj/controller/sys/MenuController.java index e849200..1905474 100644 --- a/src/main/java/com/rj/controller/sys/MenuController.java +++ b/src/main/java/com/rj/controller/sys/MenuController.java @@ -357,6 +357,9 @@ public class MenuController { + + + diff --git a/src/main/java/com/rj/controller/sys/RoleController.java b/src/main/java/com/rj/controller/sys/RoleController.java index a1ea756..cb80bd1 100644 --- a/src/main/java/com/rj/controller/sys/RoleController.java +++ b/src/main/java/com/rj/controller/sys/RoleController.java @@ -327,6 +327,9 @@ public class RoleController { + + + diff --git a/src/main/java/com/rj/controller/sys/UserRoleController.java b/src/main/java/com/rj/controller/sys/UserRoleController.java index 30ff08c..fcea0db 100644 --- a/src/main/java/com/rj/controller/sys/UserRoleController.java +++ b/src/main/java/com/rj/controller/sys/UserRoleController.java @@ -333,6 +333,9 @@ public class UserRoleController { + + + diff --git a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java index c4040d5..1b330ab 100644 --- a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java +++ b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java @@ -100,6 +100,9 @@ public class DifyWorkflowResponseDto { + + + diff --git a/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java b/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java index 5e66dad..8f22c6d 100644 --- a/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java +++ b/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java @@ -5,6 +5,8 @@ import lombok.Data; import jakarta.validation.constraints.NotBlank; import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; /** * 视频合成请求DTO @@ -17,11 +19,11 @@ import java.math.BigDecimal; public class VideoSynthesisRequestDto { @NotBlank(message = "图片URL不能为空") - @Schema(description = "图片URL", required = true, example = "https://example.com/image.jpg") + @Schema(description = "图片URL", required = true) private String imageUrl; @NotBlank(message = "音频URL不能为空") - @Schema(description = "音频URL", required = true, example = "https://example.com/audio.wav") + @Schema(description = "音频URL", required = true) private String audioUrl; @Schema(description = "使用的模型", example = "liveportrait") @@ -30,7 +32,7 @@ public class VideoSynthesisRequestDto { @Schema(description = "图片ID", example = "img-12345") private String imageId; - @Schema(description = "音频ID", example = "audio-67890") + @Schema(description = "音频ID", example ="audio-67890") private String audioId; @Schema(description = "归属人姓名", example = "张三") @@ -59,4 +61,47 @@ public class VideoSynthesisRequestDto { @Schema(description = "头部动作强度", example = "0.7") private BigDecimal headMoveStrength = new BigDecimal("0.7"); + + @Schema(description = "输入数据", example = "{\"image_url\": \"http://xxx/1.jpg\", \"audio_url\": \"http://xxx/1.wav\"}") + private Map input; + + @Schema(description = "参数配置", example = "{\"template_id\": \"normal\", \"eye_move_freq\": 0.5, \"video_fps\": 30, \"mouth_move_strength\": 1, \"paste_back\": true, \"head_move_strength\": 0.7}") + private Map parameters; + + /** + * 构建参数方法 + * 用于构建 input 和 parameters 属性 + */ + public void buildParam() { + // 构建 input 属性 + this.input = new HashMap<>(); + if (this.imageUrl != null) { + this.input.put("image_url", this.imageUrl); + } + if (this.audioUrl != null) { + this.input.put("audio_url", this.audioUrl); + } + + // 构建 parameters 属性 + this.parameters = new HashMap<>(); + if (this.templateId != null) { + this.parameters.put("template_id", this.templateId); + } + if (this.eyeMoveFreq != null) { + this.parameters.put("eye_move_freq", this.eyeMoveFreq); + } + if (this.videoFps != null) { + this.parameters.put("video_fps", this.videoFps); + } + if (this.mouthMoveStrength != null) { + this.parameters.put("mouth_move_strength", this.mouthMoveStrength); + } + if (this.pasteBack != null) { + this.parameters.put("paste_back", this.pasteBack); + } + if (this.headMoveStrength != null) { + this.parameters.put("head_move_strength", this.headMoveStrength); + } + } + } diff --git a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java index a5c8a3c..0938cb8 100644 --- a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java +++ b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java @@ -43,6 +43,9 @@ public interface CustomerProfileAnalysisMapper extends BaseMapper pendingTasks = getPendingTasks(); + + if (pendingTasks.isEmpty()) { + log.info("没有找到PENDING状态的任务"); + return; + } + + log.info("找到{}个PENDING状态的任务,开始检查状态", pendingTasks.size()); + + // 遍历每个任务,检查状态 + for (VideoSynthesisLog task : pendingTasks) { + try { + checkAndUpdateTaskStatus(task); + } catch (Exception e) { + log.error("检查任务状态失败,任务ID: {}, 错误: {}", task.getTaskId(), e.getMessage(), e); + } + } + + log.info("视频合成任务状态检查完成"); + + } catch (Exception e) { + log.error("视频合成任务状态检查执行失败", e); + } + } + + /** + * 查询所有PENDING状态的任务 + */ + private List getPendingTasks() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("task_status", "PENDING"); + + return videoSynthesisLogMapper.selectList(queryWrapper); + } + + /** + * 检查并更新单个任务状态 + */ + private void checkAndUpdateTaskStatus(VideoSynthesisLog task) { + try { + + log.info("检查任务状态,任务ID: {}", task.getTaskId()); + if (task == null || task.getTaskId() == null || task.getTaskId().isEmpty()) return; + // 调用阿里云API检查任务状态 + String apiUrl = "https://dashscope.aliyuncs.com/api/v1/tasks/" + task.getTaskId(); + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Bearer " + aliyunConfig.getApiKey()); + headers.set("Content-Type", "application/json"); + + HttpEntity entity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange( + apiUrl, + HttpMethod.GET, + entity, + String.class + ); + + if (response.getStatusCode().is2xxSuccessful()) { + String responseBody = response.getBody(); + log.info("API响应: {}", responseBody); + + // 解析响应并更新数据库 + updateTaskFromResponse(task, responseBody); + } else { + log.error("API调用失败,状态码: {}, 任务ID: {}", response.getStatusCode(), task.getTaskId()); + } + + } catch (Exception e) { + log.error("检查任务状态异常,任务ID: {}, 错误: {}", task.getTaskId(), e.getMessage(), e); + } + } + + /** + * 根据API响应更新任务状态 + */ + private void updateTaskFromResponse(VideoSynthesisLog task, String responseBody) { + try { + JSONObject responseJson = JSON.parseObject(responseBody); + + if (responseJson.containsKey("output")) { + JSONObject output = responseJson.getJSONObject("output"); + + // 更新任务状态 + String taskStatus = output.getString("task_status"); + task.setTaskStatus(taskStatus); + task.setUpdatedAt(LocalDateTime.now()); + + // 如果任务成功完成,处理视频文件 + if ("SUCCEEDED".equals(taskStatus)) { + JSONObject results = output.getJSONObject("results"); + if (results != null && results.containsKey("video_url")) { + String originalVideoUrl = results.getString("video_url"); + log.info("任务成功完成,原始视频URL: {}", originalVideoUrl); + + // 从阿里云OSS下载视频并上传到MinIO + String minioVideoUrl = downloadAndUploadToMinIO(originalVideoUrl, task.getTaskId()); + if (minioVideoUrl != null) { + task.setVideoUrl(minioVideoUrl); + log.info("视频已成功转存到MinIO: {}", minioVideoUrl); + } else { + // 如果转存失败,保留原始URL + task.setVideoUrl(originalVideoUrl); + log.warn("视频转存到MinIO失败,保留原始URL: {}", originalVideoUrl); + } + + task.setSuccess(true); + task.setResponseTime(LocalDateTime.now()); + } + } else if ("FAILED".equals(taskStatus)) { + task.setSuccess(false); + task.setErrorMessage("任务执行失败"); + task.setResponseTime(LocalDateTime.now()); + } + + // 更新usage信息 + if (responseJson.containsKey("usage")) { + JSONObject usage = responseJson.getJSONObject("usage"); + if (usage.containsKey("video_duration")) { + task.setVideoDuration(usage.getBigDecimal("video_duration")); + } + if (usage.containsKey("video_ratio")) { + task.setVideoRatio(usage.getString("video_ratio")); + } + } + + // 保存到数据库 + int updateResult = videoSynthesisLogMapper.updateById(task); + if (updateResult > 0) { + log.info("任务状态更新成功,任务ID: {}, 新状态: {}", task.getTaskId(), taskStatus); + } else { + log.error("任务状态更新失败,任务ID: {}", task.getTaskId()); + } + + } else { + log.error("API响应格式异常,任务ID: {}, 响应: {}", task.getTaskId(), responseBody); + } + + } catch (Exception e) { + log.error("解析API响应失败,任务ID: {}, 响应: {}, 错误: {}", task.getTaskId(), responseBody, e.getMessage(), e); + } + } + + /** + * 从阿里云OSS下载视频并上传到MinIO + * + * @param ossVideoUrl 阿里云OSS视频URL + * @param taskId 任务ID,用于生成文件名 + * @return MinIO中的视频URL,失败时返回null + */ + private String downloadAndUploadToMinIO(String ossVideoUrl, String taskId) { + try { + log.info("开始从阿里云OSS下载视频: {}", ossVideoUrl); + + // 从阿里云OSS下载视频 + byte[] videoData = downloadVideoFromOSS(ossVideoUrl); + if (videoData == null || videoData.length == 0) { + log.error("从阿里云OSS下载视频失败,数据为空"); + return null; + } + + log.info("视频下载成功,大小: {} bytes", videoData.length); + + // 生成MinIO文件名 + String fileName = "video_synthesis/" + taskId + ".mp4"; + + // 上传到MinIO + String minioUrl = minIOService.uploadFile( + new ByteArrayInputStream(videoData), + fileName, + "video/mp4" + ); + + log.info("视频已成功上传到MinIO: {}", minioUrl); + return minioUrl; + + } catch (Exception e) { + log.error("下载并上传视频到MinIO失败: {}", e.getMessage(), e); + return null; + } + } + + /** + * 从阿里云OSS下载视频文件 + * + * @param videoUrl 视频URL + * @return 视频字节数组 + */ + private byte[] downloadVideoFromOSS(String videoUrl) { + try { + log.info("开始下载视频: {}", videoUrl); + + // 方法1: 使用HttpURLConnection下载视频,避免RestTemplate的URL编码问题 + byte[] videoData = downloadWithHttpURLConnection(videoUrl); + if (videoData != null) { + return videoData; + } + + // 方法2: 如果HttpURLConnection失败,尝试使用RestTemplate但禁用URL编码 + log.warn("HttpURLConnection下载失败,尝试使用RestTemplate备用方案"); + return downloadWithRestTemplate(videoUrl); + + } catch (Exception e) { + log.error("下载视频异常: {}", e.getMessage(), e); + return null; + } + } + + /** + * 使用HttpURLConnection下载视频 + */ + private byte[] downloadWithHttpURLConnection(String videoUrl) { + try { + URL url = new URL(videoUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + // 设置请求头 + connection.setRequestMethod("GET"); + connection.setConnectTimeout(30000); // 30秒连接超时 + connection.setReadTimeout(300000); // 5分钟读取超时 + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + connection.setRequestProperty("Accept", "*/*"); + connection.setRequestProperty("Accept-Encoding", "identity"); // 禁用压缩 + + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + try (InputStream inputStream = connection.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + byte[] videoData = outputStream.toByteArray(); + log.info("HttpURLConnection视频下载成功,大小: {} bytes", videoData.length); + return videoData; + } + } else { + log.error("HttpURLConnection下载失败,HTTP状态码: {}", responseCode); + // 读取错误信息 + try (InputStream errorStream = connection.getErrorStream()) { + if (errorStream != null) { + byte[] errorBytes = new byte[1024]; + int errorBytesRead = errorStream.read(errorBytes); + if (errorBytesRead > 0) { + String errorMessage = new String(errorBytes, 0, errorBytesRead); + log.error("错误响应内容: {}", errorMessage); + } + } + } + return null; + } + + } catch (Exception e) { + log.error("HttpURLConnection下载异常: {}", e.getMessage(), e); + return null; + } + } + + /** + * 使用RestTemplate下载视频(备用方案) + */ + private byte[] downloadWithRestTemplate(String videoUrl) { + try { + // 创建自定义的RestTemplate,禁用URL编码 + RestTemplate customRestTemplate = new RestTemplate(); + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + headers.set("Accept", "*/*"); + headers.set("Accept-Encoding", "identity"); + + HttpEntity entity = new HttpEntity<>(headers); + + ResponseEntity response = customRestTemplate.exchange( + videoUrl, + HttpMethod.GET, + entity, + byte[].class + ); + + if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { + log.info("RestTemplate视频下载成功,大小: {} bytes", response.getBody().length); + return response.getBody(); + } else { + log.error("RestTemplate下载失败,状态码: {}", response.getStatusCode()); + return null; + } + + } catch (Exception e) { + log.error("RestTemplate下载异常: {}", e.getMessage(), e); + return null; + } + } +} diff --git a/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java b/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java index ecc3e26..7e83130 100644 --- a/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java +++ b/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java @@ -64,6 +64,9 @@ public interface ICustomerProfileAnalysisService extends IService entity = new HttpEntity<>(request, headers); @@ -76,14 +78,33 @@ public class VideoSynthesisServiceImpl implements IVideoSynthesisService { String responseBody = response.getBody(); log.info("API响应: {}", responseBody); - // 简单解析关键字段 - if (responseBody != null && responseBody.contains("task_id")) { - // 这里可以添加更复杂的JSON解析逻辑 - // 暂时设置基本状态 - synthesisLog.setTaskStatus("PENDING"); - synthesisLog.setSuccess(true); + // 解析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); + + } catch (Exception e) { + log.error("解析API响应JSON失败: {}", e.getMessage(), e); + synthesisLog.setErrorMessage("解析API响应失败: " + e.getMessage()); + synthesisLog.setSuccess(false); + } } else { - synthesisLog.setErrorMessage("API响应格式异常"); + synthesisLog.setErrorMessage("API响应为空"); synthesisLog.setSuccess(false); } diff --git a/src/main/java/com/rj/service/sys/IMenuService.java b/src/main/java/com/rj/service/sys/IMenuService.java index 58c3f2d..fd0e63b 100644 --- a/src/main/java/com/rj/service/sys/IMenuService.java +++ b/src/main/java/com/rj/service/sys/IMenuService.java @@ -66,6 +66,9 @@ public interface IMenuService extends IService { + + + diff --git a/src/main/java/com/rj/service/sys/IUserRoleService.java b/src/main/java/com/rj/service/sys/IUserRoleService.java index 13a8161..9a4b9f7 100644 --- a/src/main/java/com/rj/service/sys/IUserRoleService.java +++ b/src/main/java/com/rj/service/sys/IUserRoleService.java @@ -66,6 +66,9 @@ public interface IUserRoleService extends IService { + + + diff --git a/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java b/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java index 67ac65c..c5010dd 100644 --- a/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java @@ -70,6 +70,9 @@ public class MenuServiceImpl extends ServiceImpl implements IM + + + diff --git a/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java b/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java index f03e754..6198e98 100644 --- a/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java @@ -70,6 +70,9 @@ public class RoleServiceImpl extends ServiceImpl implements IR + + + diff --git a/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java b/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java index cabb77b..fb0fc7a 100644 --- a/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java @@ -70,6 +70,9 @@ public class UserRoleServiceImpl extends ServiceImpl i + + + diff --git a/src/main/resources/application-audio.yml b/src/main/resources/application-audio.yml index 42c475c..1b3a25f 100644 --- a/src/main/resources/application-audio.yml +++ b/src/main/resources/application-audio.yml @@ -80,6 +80,9 @@ spring: + + + diff --git a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml index 48636f1..c359e96 100644 --- a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml +++ b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml @@ -56,6 +56,9 @@ + + + diff --git a/src/main/resources/static/tts-demo.html b/src/main/resources/static/tts-demo.html index f447a92..350e5f8 100644 --- a/src/main/resources/static/tts-demo.html +++ b/src/main/resources/static/tts-demo.html @@ -260,3 +260,6 @@ + + + diff --git a/src/main/sql/add_audio_management_sales_phone.sql b/src/main/sql/add_audio_management_sales_phone.sql index 369d06a..359e6e5 100644 --- a/src/main/sql/add_audio_management_sales_phone.sql +++ b/src/main/sql/add_audio_management_sales_phone.sql @@ -20,3 +20,6 @@ AFTER `sales_name`; + + + diff --git a/src/main/sql/add_audio_name_to_tts_request_log.sql b/src/main/sql/add_audio_name_to_tts_request_log.sql index fcc237c..fd42b01 100644 --- a/src/main/sql/add_audio_name_to_tts_request_log.sql +++ b/src/main/sql/add_audio_name_to_tts_request_log.sql @@ -9,3 +9,6 @@ ADD INDEX `idx_audio_name` (`audio_name`); + + + diff --git a/src/test/java/com/rj/scheduler/VideoSynthesisStatusSchedulerTest.java b/src/test/java/com/rj/scheduler/VideoSynthesisStatusSchedulerTest.java new file mode 100644 index 0000000..cc326a8 --- /dev/null +++ b/src/test/java/com/rj/scheduler/VideoSynthesisStatusSchedulerTest.java @@ -0,0 +1,107 @@ +package com.rj.scheduler; + +import com.rj.entity.VideoSynthesisLog; +import com.rj.mapper.VideoSynthesisLogMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 视频合成状态检查定时器测试类 + * + * @author rj + * @date 2025-01-30 + */ +@SpringBootTest +@ActiveProfiles("test") +public class VideoSynthesisStatusSchedulerTest { + + @Autowired + private VideoSynthesisStatusScheduler videoSynthesisStatusScheduler; + + @Autowired + private VideoSynthesisLogMapper videoSynthesisLogMapper; + + /** + * 测试查询PENDING状态的任务 + */ + @Test + public void testGetPendingTasks() { + // 这里可以添加一些测试数据,然后验证查询功能 + System.out.println("测试查询PENDING状态的任务..."); + + // 手动执行定时器方法进行测试 + videoSynthesisStatusScheduler.checkVideoSynthesisStatus(); + } + + /** + * 测试手动创建PENDING状态的任务(用于测试) + */ + @Test + public void testCreatePendingTask() { + VideoSynthesisLog testTask = new VideoSynthesisLog(); + testTask.setRequestId("test-request-" + System.currentTimeMillis()); + testTask.setTaskId("test-task-" + System.currentTimeMillis()); + testTask.setModel("test-model"); + testTask.setImageUrl("http://test.com/image.jpg"); + testTask.setAudioUrl("http://test.com/audio.mp3"); + testTask.setTaskStatus("PENDING"); + testTask.setRequestTime(LocalDateTime.now()); + testTask.setCreatedAt(LocalDateTime.now()); + testTask.setUpdatedAt(LocalDateTime.now()); + + int result = videoSynthesisLogMapper.insert(testTask); + System.out.println("创建测试任务结果: " + (result > 0 ? "成功" : "失败")); + } + + /** + * 测试查询所有PENDING状态的任务 + */ + @Test + public void testQueryPendingTasks() { + List pendingTasks = videoSynthesisLogMapper.selectList( + new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() + .eq("task_status", "PENDING") + ); + + System.out.println("找到PENDING状态的任务数量: " + pendingTasks.size()); + for (VideoSynthesisLog task : pendingTasks) { + System.out.println("任务ID: " + task.getTaskId() + ", 状态: " + task.getTaskStatus()); + } + } + + /** + * 测试视频转存功能(模拟API响应) + */ + @Test + public void testVideoTransfer() { + // 模拟API响应数据 + String mockResponse = "{\n" + + " \"request_id\":\"f2c33c8b-4bd8-46d5-b035-7a1cdeaaedc1\",\n" + + " \"output\":{\n" + + " \"task_id\":\"3c692370-6572-4aba-b03a-534cb9866ef3\",\n" + + " \"task_status\":\"SUCCEEDED\",\n" + + " \"submit_time\":\"2025-10-07 20:31:19.337\",\n" + + " \"scheduled_time\":\"2025-10-07 20:31:27.368\",\n" + + " \"end_time\":\"2025-10-07 20:32:00.900\",\n" + + " \"results\":{\n" + + " \"video_url\":\"http://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/1d/3c/20251007/5cf64d65/3c692370-6572-4aba-b03a-534cb9866ef3.mp4?Expires=1759926720&OSSAccessKeyId=LTAI5tKPD3TMqf2Lna1fASuh&Signature=s2WX6hQ%2BLBDWWmW%2F3sbxEKf%2BUu0%3D\"\n" + + " }\n" + + " },\n" + + " \"usage\":{\n" + + " \"video_duration\":10.86,\n" + + " \"video_ratio\":\"standard\"\n" + + " }\n" + + "}"; + + System.out.println("模拟API响应测试:"); + System.out.println(mockResponse); + + // 这里可以添加更多测试逻辑 + System.out.println("测试完成"); + } +} diff --git a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java index 356d21f..e3b7af8 100644 --- a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java +++ b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java @@ -139,3 +139,6 @@ public class TtsRequestLogShortUrlTest { } + + +