From e5cba62007f1e687e370c47c43777d8379b940e4 Mon Sep 17 00:00:00 2001 From: spllzh <28668817@qq.com> Date: Wed, 8 Oct 2025 11:50:49 +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=E5=90=8E=EF=BC=8C=E4=B8=8A=E4=BC=A0=EF=BC=8C=E6=9F=A5?= =?UTF-8?q?=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rj/common/PasswordUtil.java | 2 + .../java/com/rj/common/ServiceManager.java | 2 + src/main/java/com/rj/config/AliyunConfig.java | 2 + .../controller/SiliconFlowTtsController.java | 127 ++++++++++++++++++ .../com/rj/controller/sys/MenuController.java | 2 + .../com/rj/controller/sys/RoleController.java | 2 + .../rj/controller/sys/UserRoleController.java | 2 + .../com/rj/dto/DifyWorkflowResponseDto.java | 2 + .../com/rj/dto/VideoSynthesisRequestDto.java | 3 + .../java/com/rj/entity/VideoSynthesisLog.java | 12 ++ .../mapper/CustomerProfileAnalysisMapper.java | 2 + .../scheduler/AudioStatisticsScheduler.java | 2 + .../VideoSynthesisStatusScheduler.java | 43 +++++- .../biz/ICustomerProfileAnalysisService.java | 2 + .../CustomerProfileAnalysisServiceImpl.java | 2 + .../impl/VideoSynthesisServiceImpl.java | 44 ++++++ .../java/com/rj/service/sys/IMenuService.java | 2 + .../rj/service/sys/impl/MenuServiceImpl.java | 2 + .../rj/service/sys/impl/RoleServiceImpl.java | 2 + .../service/sys/impl/UserRoleServiceImpl.java | 2 + src/main/resources/application-audio.yml | 2 + .../AudioManagementStatisticsMapper.xml | 2 + src/main/resources/static/tts-demo.html | 2 + .../sql/add_audio_management_sales_phone.sql | 2 + .../sql/add_audio_name_to_tts_request_log.sql | 2 + .../rj/service/TtsRequestLogShortUrlTest.java | 2 + 26 files changed, 266 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rj/common/PasswordUtil.java b/src/main/java/com/rj/common/PasswordUtil.java index c87db01..305b02d 100644 --- a/src/main/java/com/rj/common/PasswordUtil.java +++ b/src/main/java/com/rj/common/PasswordUtil.java @@ -139,6 +139,8 @@ public class PasswordUtil { + + diff --git a/src/main/java/com/rj/common/ServiceManager.java b/src/main/java/com/rj/common/ServiceManager.java index 28217cf..96f6519 100644 --- a/src/main/java/com/rj/common/ServiceManager.java +++ b/src/main/java/com/rj/common/ServiceManager.java @@ -123,6 +123,8 @@ public class ServiceManager { + + diff --git a/src/main/java/com/rj/config/AliyunConfig.java b/src/main/java/com/rj/config/AliyunConfig.java index ae459f2..d9e6c02 100644 --- a/src/main/java/com/rj/config/AliyunConfig.java +++ b/src/main/java/com/rj/config/AliyunConfig.java @@ -101,6 +101,8 @@ public class AliyunConfig { + + diff --git a/src/main/java/com/rj/controller/SiliconFlowTtsController.java b/src/main/java/com/rj/controller/SiliconFlowTtsController.java index 62c15a8..3c064a6 100644 --- a/src/main/java/com/rj/controller/SiliconFlowTtsController.java +++ b/src/main/java/com/rj/controller/SiliconFlowTtsController.java @@ -2,6 +2,9 @@ package com.rj.controller; import com.rj.dto.SiliconFlowTtsRequest; import com.rj.dto.SiliconFlowTtsResponse; +import com.rj.entity.TtsRequestLog; +import com.rj.service.ITtsRequestLogService; +import com.rj.service.MinIOService; import com.rj.service.SiliconFlowTtsService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -13,10 +16,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.time.LocalDateTime; import java.util.Base64; import java.util.HashMap; import java.util.Map; +import java.util.UUID; /** * SiliconFlow TTS 控制器 @@ -32,6 +38,13 @@ public class SiliconFlowTtsController { @Autowired private SiliconFlowTtsService ttsService; + + @Autowired + private MinIOService minIOService; + + @Autowired + private ITtsRequestLogService ttsRequestLogService; + @PostMapping("/speech") @Operation(summary = "文本转语音", description = "将文本转换为语音音频") @@ -370,4 +383,118 @@ public class SiliconFlowTtsController { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); } } + + @PostMapping(value = "/upload-audio", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @Operation(summary = "音频文件上传", description = "上传音频文件到MinIO并生成临时访问链接") + public ResponseEntity> uploadAudio( + @Parameter(description = "音频文件") @RequestParam("file") MultipartFile file, + @Parameter(description = "音频名称") @RequestParam("audioName") String audioName, + @Parameter(description = "创建人姓名") @RequestParam("creatorName") String creatorName, + @Parameter(description = "创建人电话") @RequestParam("creatorPhone") String creatorPhone) { + + Map result = new HashMap<>(); + + try { + log.info("开始上传音频文件: {}, 创建人: {}, 电话: {}", audioName, creatorName, creatorPhone); + + // 验证文件 + if (file.isEmpty()) { + log.error("上传文件为空"); + result.put("success", false); + result.put("message", "上传文件为空"); + return ResponseEntity.badRequest().body(result); + } + + // 验证文件类型 + String contentType = file.getContentType(); + if (contentType == null || !contentType.startsWith("audio/")) { + log.error("文件类型不是音频文件: {}", contentType); + result.put("success", false); + result.put("message", "文件类型不是音频文件,请上传音频文件"); + return ResponseEntity.badRequest().body(result); + } + + // 生成唯一文件名 + String originalFilename = file.getOriginalFilename(); + String fileExtension = originalFilename != null && originalFilename.contains(".") + ? originalFilename.substring(originalFilename.lastIndexOf(".")) + : ".mp3"; + String uniqueFileName = "audio/" + UUID.randomUUID().toString() + fileExtension; + + // 上传文件到MinIO + String minioUrl = minIOService.uploadFileWithName(file, uniqueFileName); + if (minioUrl == null) { + log.error("文件上传到MinIO失败"); + result.put("success", false); + result.put("message", "文件上传到MinIO失败"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + + log.info("文件上传成功,MinIO URL: {}", minioUrl); + + // 生成7天临时访问链接 + int expiresInSeconds = 7 * 24 * 60 * 60; // 7天 + String shortUrl = minIOService.getPresignedUrl(uniqueFileName, expiresInSeconds); + if (shortUrl == null) { + log.error("生成临时访问链接失败"); + result.put("success", false); + result.put("message", "生成临时访问链接失败"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + + LocalDateTime expireTime = LocalDateTime.now().plusSeconds(expiresInSeconds); + log.info("生成临时访问链接成功,过期时间: {}", expireTime); + + // 创建TTS请求日志记录 + TtsRequestLog ttsLog = new TtsRequestLog(); + ttsLog.setId(UUID.randomUUID().toString()); + ttsLog.setRequestTime(LocalDateTime.now()); + ttsLog.setModel("AUDIO_UPLOAD"); + ttsLog.setInputText("音频文件上传"); + ttsLog.setInputLength(0); + ttsLog.setStatus("SUCCESS"); + ttsLog.setAudioSizeBytes(file.getSize()); + ttsLog.setMinioUrl(minioUrl); + ttsLog.setAudioName(audioName); + ttsLog.setShortUrl(shortUrl); + ttsLog.setShortUrlExpireTime(expireTime); + ttsLog.setCreatorName(creatorName); + ttsLog.setCreatorPhone(creatorPhone); + ttsLog.setCreateTime(LocalDateTime.now()); + ttsLog.setUpdateTime(LocalDateTime.now()); + + // 保存到数据库 + boolean saveResult = ttsRequestLogService.saveTtsRequestLog(ttsLog); + if (!saveResult) { + log.error("保存TTS请求日志失败"); + result.put("success", false); + result.put("message", "保存TTS请求日志失败"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + + // 构建成功响应 + result.put("success", true); + result.put("message", "音频文件上传成功"); + result.put("id", ttsLog.getId()); + result.put("audioName", audioName); + result.put("minioUrl", minioUrl); + result.put("shortUrl", shortUrl); + result.put("shortUrlExpireTime", expireTime); + result.put("creatorName", creatorName); + result.put("creatorPhone", creatorPhone); + result.put("audioSizeBytes", file.getSize()); + result.put("status", "SUCCESS"); + result.put("createTime", LocalDateTime.now()); + + log.info("音频文件上传完成,记录ID: {}, MinIO URL: {}, 临时URL: {}", + ttsLog.getId(), minioUrl, shortUrl); + return ResponseEntity.ok(result); + + } catch (Exception e) { + log.error("音频文件上传异常: {}", e.getMessage(), e); + result.put("success", false); + result.put("message", "音频文件上传异常: " + e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).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 1905474..a7b172d 100644 --- a/src/main/java/com/rj/controller/sys/MenuController.java +++ b/src/main/java/com/rj/controller/sys/MenuController.java @@ -361,6 +361,8 @@ 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 cb80bd1..971f828 100644 --- a/src/main/java/com/rj/controller/sys/RoleController.java +++ b/src/main/java/com/rj/controller/sys/RoleController.java @@ -331,6 +331,8 @@ 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 fcea0db..032e8a3 100644 --- a/src/main/java/com/rj/controller/sys/UserRoleController.java +++ b/src/main/java/com/rj/controller/sys/UserRoleController.java @@ -337,6 +337,8 @@ public class UserRoleController { + + diff --git a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java index 1b330ab..7fa8cb7 100644 --- a/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java +++ b/src/main/java/com/rj/dto/DifyWorkflowResponseDto.java @@ -104,6 +104,8 @@ public class DifyWorkflowResponseDto { + + diff --git a/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java b/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java index 8f22c6d..9974c48 100644 --- a/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java +++ b/src/main/java/com/rj/dto/VideoSynthesisRequestDto.java @@ -18,6 +18,9 @@ import java.util.Map; @Schema(description = "视频合成请求参数") public class VideoSynthesisRequestDto { + @Schema(description = "视频名称") + private String videoName; + @NotBlank(message = "图片URL不能为空") @Schema(description = "图片URL", required = true) private String imageUrl; diff --git a/src/main/java/com/rj/entity/VideoSynthesisLog.java b/src/main/java/com/rj/entity/VideoSynthesisLog.java index aa413e4..3e12335 100644 --- a/src/main/java/com/rj/entity/VideoSynthesisLog.java +++ b/src/main/java/com/rj/entity/VideoSynthesisLog.java @@ -145,6 +145,18 @@ public class VideoSynthesisLog { @TableField("video_url") private String videoUrl; + /** + * 视频名称 + */ + @TableField("video_name") + private String videoName; + + /** + * 临时对外URL链接 + */ + @TableField("video_temp_url") + private String videoTempUrl; + /** * 视频时长(秒) */ diff --git a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java index 0938cb8..c60979c 100644 --- a/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java +++ b/src/main/java/com/rj/mapper/CustomerProfileAnalysisMapper.java @@ -47,6 +47,8 @@ public interface CustomerProfileAnalysisMapper extends BaseMapper pendingTasks = getPendingTasks(); if (pendingTasks.isEmpty()) { - log.info("没有找到PENDING状态的任务"); + log.info("没有找到PENDING或RUNNING状态的任务"); return; } - log.info("找到{}个PENDING状态的任务,开始检查状态", pendingTasks.size()); + log.info("找到{}个PENDING或RUNNING状态的任务,开始检查状态", pendingTasks.size()); // 遍历每个任务,检查状态 for (VideoSynthesisLog task : pendingTasks) { @@ -83,11 +83,11 @@ public class VideoSynthesisStatusScheduler { } /** - * 查询所有PENDING状态的任务 + * 查询所有PENDING或RUNNING状态的任务 */ private List getPendingTasks() { QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("task_status", "PENDING"); + queryWrapper.in("task_status", "PENDING", "RUNNING"); return videoSynthesisLogMapper.selectList(queryWrapper); } @@ -166,6 +166,15 @@ public class VideoSynthesisStatusScheduler { task.setSuccess(true); task.setResponseTime(LocalDateTime.now()); + + // 更新临时访问URL(使用MinIO的预签名URL) + try { + String tempUrl = generateTempVideoUrl(task.getVideoName(), task.getRequestId()); + task.setVideoTempUrl(tempUrl); + log.info("更新临时访问URL: {}", tempUrl); + } catch (Exception e) { + log.warn("更新临时访问URL失败: {}", e.getMessage()); + } } } else if ("FAILED".equals(taskStatus)) { task.setSuccess(false); @@ -355,4 +364,28 @@ public class VideoSynthesisStatusScheduler { return null; } } + + /** + * 生成临时视频访问URL + * + * @param videoName 视频名称 + * @param requestId 请求ID + * @return 临时访问URL + */ + private String generateTempVideoUrl(String videoName, String requestId) { + try { + // 构建临时访问URL + // 格式: https://your-domain.com/video/temp/{requestId}?name={videoName} + String baseUrl = "https://your-domain.com"; // 这里应该从配置文件读取 + String encodedVideoName = java.net.URLEncoder.encode(videoName, "UTF-8"); + String tempUrl = String.format("%s/video/temp/%s?name=%s", baseUrl, requestId, encodedVideoName); + + log.info("生成临时视频URL: 视频名称={}, 请求ID={}, URL={}", videoName, requestId, tempUrl); + return tempUrl; + + } catch (Exception e) { + log.error("生成临时视频URL失败: {}", 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 7e83130..20b44f5 100644 --- a/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java +++ b/src/main/java/com/rj/service/biz/ICustomerProfileAnalysisService.java @@ -68,6 +68,8 @@ public interface ICustomerProfileAnalysisService 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 c5010dd..30135a1 100644 --- a/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/MenuServiceImpl.java @@ -74,6 +74,8 @@ 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 6198e98..742a0f8 100644 --- a/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/RoleServiceImpl.java @@ -74,6 +74,8 @@ 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 fb0fc7a..215934b 100644 --- a/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java +++ b/src/main/java/com/rj/service/sys/impl/UserRoleServiceImpl.java @@ -74,6 +74,8 @@ public class UserRoleServiceImpl extends ServiceImpl i + + diff --git a/src/main/resources/application-audio.yml b/src/main/resources/application-audio.yml index 1b3a25f..7d3511d 100644 --- a/src/main/resources/application-audio.yml +++ b/src/main/resources/application-audio.yml @@ -84,6 +84,8 @@ spring: + + diff --git a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml index c359e96..7b1f61b 100644 --- a/src/main/resources/mapper/AudioManagementStatisticsMapper.xml +++ b/src/main/resources/mapper/AudioManagementStatisticsMapper.xml @@ -60,6 +60,8 @@ + + diff --git a/src/main/resources/static/tts-demo.html b/src/main/resources/static/tts-demo.html index 350e5f8..0c17127 100644 --- a/src/main/resources/static/tts-demo.html +++ b/src/main/resources/static/tts-demo.html @@ -263,3 +263,5 @@ + + diff --git a/src/main/sql/add_audio_management_sales_phone.sql b/src/main/sql/add_audio_management_sales_phone.sql index 359e6e5..47fe7cc 100644 --- a/src/main/sql/add_audio_management_sales_phone.sql +++ b/src/main/sql/add_audio_management_sales_phone.sql @@ -23,3 +23,5 @@ 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 fd42b01..9bf5087 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 @@ -12,3 +12,5 @@ ADD INDEX `idx_audio_name` (`audio_name`); + + diff --git a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java index e3b7af8..ebcb1cc 100644 --- a/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java +++ b/src/test/java/com/rj/service/TtsRequestLogShortUrlTest.java @@ -142,3 +142,5 @@ public class TtsRequestLogShortUrlTest { + +