diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java index 63ddfb37..1bf2b8f2 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java @@ -1,6 +1,11 @@ package com.fuyuanshen.app.controller; import cn.dev33.satoken.annotation.SaIgnore; +import com.fuyuanshen.app.domain.bo.AppBusinessFileBo; +import com.fuyuanshen.app.domain.dto.AppAudioFileDto; +import com.fuyuanshen.app.domain.dto.AppFileDto; +import com.fuyuanshen.app.domain.dto.TextToSpeechRequest; +import com.fuyuanshen.app.domain.vo.AppFileVo; import com.fuyuanshen.app.service.AudioProcessService; import com.fuyuanshen.app.service.VideoProcessService; import com.fuyuanshen.common.core.domain.R; @@ -8,6 +13,7 @@ import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; import com.fuyuanshen.common.web.core.BaseController; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -56,6 +62,7 @@ public class AppVideoController extends BaseController { return R.ok(audioProcessService.generateStandardPcmData(text)); } + /** * 提取文本内容(只支持txt/docx) */ @@ -65,4 +72,52 @@ public class AppVideoController extends BaseController { return R.ok("Success",audioProcessService.extract(file)); } + + /** + * 上传音频文件进行处理 + * 支持MP3、WAV、PCM格式 + */ + @PostMapping("/uploadAudioToOss") + public R uploadAudioToOss(@RequestParam("file") @ModelAttribute AppAudioFileDto bo) { + try { + String result = audioProcessService.uploadAudioToOss(bo); + return R.ok(result); + } catch (IllegalArgumentException e) { + return R.fail("文件格式错误: " + e.getMessage()); + } catch (Exception e) { + + return R.fail("上传处理失败: " + e.getMessage()); + } + } + + /** + * 文本转语音 + * 支持MP3、WAV、PCM格式 + */ + @PostMapping("/ttsToOss") + public R textToSpeech(@RequestBody TextToSpeechRequest request) { + try { + if (request.getDeviceId() == null) { + return R.fail("设备ID不能为空"); + } + + String result = audioProcessService.textToSpeech( + request.getDeviceId(), + request.getText(), + request.getFileSuffix() + ); + return R.ok(result); + } catch (Exception e) { + return R.fail("文本转语音失败: " + e.getMessage()); + } + } + + + /** + * 查询语音文件列表 + */ + @GetMapping("/queryAudioFileList") + public R> queryAudioFileList(Long deviceId) { + return R.ok(audioProcessService.queryAudioFileList(deviceId)); + } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppAudioFileDto.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppAudioFileDto.java new file mode 100644 index 00000000..4789ab32 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppAudioFileDto.java @@ -0,0 +1,17 @@ +package com.fuyuanshen.app.domain.dto; + +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +@Data +public class AppAudioFileDto { + + private Long deviceId; + + /** + * 文件 + */ + private MultipartFile file; + + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/PcmGenerationRequest.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/PcmGenerationRequest.java new file mode 100644 index 00000000..bc58bda0 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/PcmGenerationRequest.java @@ -0,0 +1,11 @@ +package com.fuyuanshen.app.domain.dto; + +import lombok.Data; + +/** + * PCM生成请求实体 + */ +@Data +public class PcmGenerationRequest { + private String text; +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/TextToSpeechRequest.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/TextToSpeechRequest.java new file mode 100644 index 00000000..6888e515 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/TextToSpeechRequest.java @@ -0,0 +1,19 @@ +package com.fuyuanshen.app.domain.dto; + +import lombok.Data; + +/** + * 文本转语音请求实体 + */ +@Data +public class TextToSpeechRequest { + + private Long deviceId; + + private String text; + + /** + * 文件后缀格式 + */ + private String fileSuffix; +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/http/ApacheHttpTtsClient.java b/fys-admin/src/main/java/com/fuyuanshen/app/http/ApacheHttpTtsClient.java new file mode 100644 index 00000000..40e4e8eb --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/http/ApacheHttpTtsClient.java @@ -0,0 +1,84 @@ +package com.fuyuanshen.app.http; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Base64; + +public class ApacheHttpTtsClient { + + private String accessKeyId; + private String accessKeySecret; + private String appKey; + + public ApacheHttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) { + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.appKey = appKey; + } + + /** + * 使用Apache HttpClient调用TTS服务 + */ + public byte[] synthesizeTextToMp3(String text) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + + try { + HttpPost httpPost = new HttpPost("https://nls-gateway.cn-shanghai.aliyuncs.com/v1/tts"); + + // 设置请求头 + httpPost.setHeader("Content-Type", "application/json"); + httpPost.setHeader("Authorization", "Bearer " + getAccessToken()); + + // 设置请求体 + String jsonPayload = String.format( + "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}", + appKey, + text.replace("\"", "\\\"") + ); + + StringEntity entity = new StringEntity(jsonPayload, "UTF-8"); + httpPost.setEntity(entity); + + // 执行请求 + CloseableHttpResponse response = httpClient.execute(httpPost); + try { + HttpEntity responseEntity = response.getEntity(); + if (response.getStatusLine().getStatusCode() == 200) { + // 读取响应数据(Base64编码的音频数据) + String responseStr = EntityUtils.toString(responseEntity); + + // 如果返回的是Base64编码的数据 + if (responseStr.startsWith("data:audio/mp3;base64,")) { + String base64Data = responseStr.substring("data:audio/mp3;base64,".length()); + return Base64.getDecoder().decode(base64Data); + } else { + // 直接返回音频数据 + return EntityUtils.toByteArray(responseEntity); + } + } else { + throw new IOException("请求失败: " + response.getStatusLine().getStatusCode()); + } + } finally { + response.close(); + } + } finally { + httpClient.close(); + } + } + + /** + * 获取访问令牌 + */ + private String getAccessToken() { + // 实现获取阿里云访问令牌的逻辑 + return "your-access-token"; + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsClient.java b/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsClient.java new file mode 100644 index 00000000..413ab83d --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsClient.java @@ -0,0 +1,130 @@ +package com.fuyuanshen.app.http; + +import com.alibaba.nls.client.AccessToken; +import com.fuyuanshen.common.redis.utils.RedisUtils; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.time.Duration; +import java.util.Base64; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import static cn.dev33.satoken.SaManager.log; + +public class HttpTtsClient { + + private String accessKeyId; + private String accessKeySecret; + private String appKey; + /** + * 阿里云TTS服务基础URL + */ + private static final String BASE_URL = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts"; + + public HttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) { + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.appKey = appKey; + } + private String refreshAccessToken() { + try { + // 调用阿里云API获取访问令牌 + AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret); + accessToken.apply(); + String token = accessToken.getToken(); + log.info("访问令牌刷新成功"); + + return token; + } catch (Exception e) { + log.error("刷新访问令牌失败: {}", e.getMessage(), e); + return null; + } + } + /** + * 使用HTTP POST方式调用阿里云TTS服务生成MP3格式语音 + */ + public byte[] synthesizeTextToMp3(String text) throws IOException { + String endpoint = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts"; + + // 构建请求体 +// String requestBody = String.format( +// "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}", +// appKey, +// text.replace("\"", "\\\"") +// ); + + String token = refreshAccessToken(); + String requestBody = " {\n" + + " \"appkey\":\""+appKey+"\",\n" + + " \"text\":\""+text+"\",\n" + + " \"token\":\""+token+"\",\n" + + " \"format\":\"mp3\"\n" + + " }"; + + URL url = new URL(endpoint); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + // 设置请求方法和头部 + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestProperty("Authorization", buildAuthorization()); + conn.setRequestProperty("Content-Length", String.valueOf(requestBody.getBytes().length)); + conn.setDoOutput(true); + + // 发送请求体 + try (OutputStream os = conn.getOutputStream()) { + os.write(requestBody.getBytes("UTF-8")); + } + + // 读取响应 + int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + // 读取音频数据 + try (InputStream is = conn.getInputStream()) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } + } else { + throw new IOException("HTTP请求失败,状态码: " + responseCode); + } + } + + /** + * 构建授权头部 + */ + private String buildAuthorization() { + // 实际实现需要根据阿里云API规范构建签名 + // 这里是简化示例 + return "Bearer " + generateAccessToken(); + } + + /** + * 生成访问令牌 + */ + private String generateAccessToken() { + // 实际实现需要调用阿里云获取token的API + return "your-access-token"; + } + + /** + * 保存MP3到文件 + */ + public String saveMp3ToFile(String text, String outputPath) throws IOException { + byte[] mp3Data = synthesizeTextToMp3(text); + + try (FileOutputStream fos = new FileOutputStream(outputPath)) { + fos.write(mp3Data); + } + + return outputPath; + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsExample.java b/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsExample.java new file mode 100644 index 00000000..5644474c --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/http/HttpTtsExample.java @@ -0,0 +1,32 @@ +package com.fuyuanshen.app.http; + +import java.io.IOException; + +public class HttpTtsExample { + + /** + * appKey: lbGuq5K5bEH4uxmT + * akId: LTAI5t66moCkhNC32TDJ5ReP + * akSecret: 2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH + * @param args + */ + public static void main(String[] args) { + String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP"; + String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH"; + String appKey = "lbGuq5K5bEH4uxmT"; + + try { + // 使用HTTP方式调用 + HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey); + + String text = "大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。"; + String outputPath = "D:\\http_output9.mp3"; + + String resultFile = httpClient.saveMp3ToFile(text, outputPath); + System.out.println("MP3音频已保存至: " + resultFile); + + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/http/OkHttpTtsClient.java b/fys-admin/src/main/java/com/fuyuanshen/app/http/OkHttpTtsClient.java new file mode 100644 index 00000000..eaf29392 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/http/OkHttpTtsClient.java @@ -0,0 +1,58 @@ +package com.fuyuanshen.app.http; + +import okhttp3.*; + +import java.io.IOException; + +public class OkHttpTtsClient { + + private OkHttpClient client = new OkHttpClient(); + private String accessKeyId; + private String accessKeySecret; + private String appKey; + + public OkHttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) { + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.appKey = appKey; + } + + /** + * 使用OkHttp调用TTS服务 + */ + public byte[] synthesizeTextToMp3(String text) throws IOException { + MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + String jsonPayload = String.format( + "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}", + appKey, + text.replace("\"", "\\\"") + ); + + RequestBody body = RequestBody.create(JSON,jsonPayload); + Request request = new Request.Builder() + .url("https://nls-gateway.cn-shanghai.aliyuncs.com/v1/tts") + .post(body) + .addHeader("Content-Type", "application/json") + .addHeader("Authorization", "Bearer " + getAccessToken()) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("HTTP请求失败: " + response.code()); + } + + ResponseBody responseBody = response.body(); + if (responseBody != null) { + return responseBody.bytes(); + } else { + throw new IOException("响应体为空"); + } + } + } + + private String getAccessToken() { + // 实现获取访问令牌的逻辑 + return "your-access-token"; + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/http/TokenClient.java b/fys-admin/src/main/java/com/fuyuanshen/app/http/TokenClient.java new file mode 100644 index 00000000..40c2984d --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/http/TokenClient.java @@ -0,0 +1,48 @@ +package com.fuyuanshen.app.http; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * 获取阿里云TTS服务访问令牌 + */ +public class TokenClient { + + public static String getAccessToken(String accessKeyId, String accessKeySecret) throws IOException { + String endpoint = "https://nls-meta.cn-shanghai.aliyuncs.com/v1/token"; + + URL url = new URL(endpoint); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setDoOutput(true); + + // 发送认证信息 + String params = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s", + accessKeyId, accessKeySecret); + + try (OutputStream os = conn.getOutputStream()) { + os.write(params.getBytes("UTF-8")); + } + + int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + try (InputStream is = conn.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + + // 解析响应获取token(实际需要使用JSON解析库) + return response.toString().replaceAll(".*\"access_token\":\"([^\"]+)\".*", "$1"); + } + } else { + throw new IOException("获取令牌失败,状态码: " + responseCode); + } + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppFileService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppFileService.java index 0b450f39..096040a8 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppFileService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppFileService.java @@ -96,5 +96,4 @@ public class AppFileService { } return appBusinessFileService.deleteWithValidByIds(List.of(ids), true); } - } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java index 31c5ac36..af530042 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java @@ -1,7 +1,16 @@ package com.fuyuanshen.app.service; +import com.fuyuanshen.app.domain.bo.AppBusinessFileBo; +import com.fuyuanshen.app.domain.dto.AppAudioFileDto; +import com.fuyuanshen.app.domain.vo.AppFileVo; +import com.fuyuanshen.app.http.HttpTtsClient; +import com.fuyuanshen.common.satoken.utils.AppLoginHelper; import com.fuyuanshen.equipment.utils.AlibabaTTSUtil; import com.fuyuanshen.equipment.utils.AudioProcessUtil; +import com.fuyuanshen.equipment.utils.FileHashUtil; +import com.fuyuanshen.equipment.utils.Mp3Duration; +import com.fuyuanshen.system.domain.vo.SysOssVo; +import com.fuyuanshen.system.service.ISysOssService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -17,8 +26,12 @@ import javax.xml.stream.XMLStreamReader; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; +import java.util.Random; +import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -39,6 +52,10 @@ public class AudioProcessService { private final AudioProcessUtil audioProcessUtil; private final AlibabaTTSUtil alibabaTTSUtil; + private final FileHashUtil fileHashUtil; + private final ISysOssService ossService; + private final IAppBusinessFileService appBusinessFileService; + /** * 处理上传的音频文件 */ @@ -305,4 +322,158 @@ public class AudioProcessService { } + public String uploadAudioToOss(AppAudioFileDto bo) { + MultipartFile file = bo.getFile(); + // 校验文件格式和大小 + validateAudioFileForRestful(file); + // 上传文件 + // SysOssVo upload = sysOssService.upload(file); + + try { + String fileHash = fileHashUtil.hash(file); + SysOssVo upload = ossService.updateHash(file, fileHash); + // 强制将HTTP替换为HTTPS + if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) { + upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://")); + } + + AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo(); + appBusinessFileBo.setFileId(upload.getOssId()); + appBusinessFileBo.setBusinessId(bo.getDeviceId()); + appBusinessFileBo.setFileType(3L); + appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId()); + + appBusinessFileService.insertByBo(appBusinessFileBo); + if (upload != null) { + return upload.getUrl(); + } + } catch (Exception e){ + log.error("上传音频文件失败", e); + } + + return null; + } + + /** + * 校验音频文件格式 + */ + private void validateAudioFileForRestful(MultipartFile file) { + if (file == null || file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null) { + throw new IllegalArgumentException("文件名不能为空"); + } + + // 检查文件扩展名 + if (!isSupportedFormat(originalFilename)) { + throw new IllegalArgumentException("只允许上传MP3、WAV、PCM格式的音频文件"); + } + + // 检查文件大小 + if (file.getSize() > MAX_AUDIO_SIZE) { + throw new IllegalArgumentException("音频大小不能超过5MB"); + } + } + + /** + * 判断文件是否为支持的音频格式 + */ + private boolean isSupportedFormat(String filename) { + if (filename == null || filename.lastIndexOf('.') == -1) { + return false; + } + String ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); + return SUPPORTED_FORMATS.contains(ext); + } + + public String textToSpeech(Long deviceId,String text, String fileSuffix) { + //支持PCM/WAV/MP3格式 + if (fileSuffix == null || fileSuffix.isEmpty()) { + fileSuffix = "mp3"; + } + fileSuffix = fileSuffix.toLowerCase(); + List SUPPORTED_FORMATS = Arrays.asList( + "wav", "mp3", "pcm" + ); + boolean contains = SUPPORTED_FORMATS.contains(fileSuffix); + if (!contains) { + throw new IllegalArgumentException("不支持的音频格式"); + } + String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP"; + String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH"; + String appKey = "lbGuq5K5bEH4uxmT"; + String savedPath = null; + try { + // 使用HTTP方式调用 + HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey); +// + byte[] mp3Data = httpClient.synthesizeTextToMp3(text); +// byte[] mp3Data = alibabaTTSUtil.synthesizeTextToMp3(text); + + SysOssVo upload = ossService.upload(mp3Data, generateRandomFileName(fileSuffix)); + + // 强制将HTTP替换为HTTPS + if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) { + upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://")); + } + + + AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo(); + appBusinessFileBo.setFileId(upload.getOssId()); + appBusinessFileBo.setBusinessId(deviceId); + appBusinessFileBo.setFileType(3L); + appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId()); + savedPath = saveByteArrayToFile(mp3Data, generateRandomFileName(fileSuffix)); + if (savedPath != null) { + log.info("MP3文件已保存: {}", savedPath); + Integer mp3Duration = Mp3Duration.getMp3Duration(savedPath); + log.info("MP3文件时长: {} 秒", mp3Duration); + appBusinessFileBo.setDuration(mp3Duration); + } + appBusinessFileService.insertByBo(appBusinessFileBo); + if (upload != null) { + return upload.getUrl(); + } + } catch (Exception e){ + log.error("上传音频文件失败", e); + } finally { + log.info("删除临时文件: {}", savedPath); + if(savedPath != null){ + deleteTempFile(new File(savedPath)); + } + } + return null; + } + + private static final Random random = new Random(); + private static final DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + /** + * 生成纯随机文件名(无原文件名依赖) + */ + public static String generateRandomFileName(String extension) { + String timestamp = LocalDateTime.now().format(formatter); + int randomNum = random.nextInt(10000); + String uuidPart = UUID.randomUUID().toString().substring(0, 8); + + if (!extension.startsWith(".")) { + extension = "." + extension; + } + + return timestamp + "_" + String.format("%04d", randomNum) + "_" + uuidPart + extension; + } + + public List queryAudioFileList(Long deviceId) { + if(deviceId == null){ + return null; + } + AppBusinessFileBo bo = new AppBusinessFileBo(); + bo.setBusinessId(deviceId); + bo.setFileType(3L); + List appFileVos = appBusinessFileService.queryAppFileList(bo); + return appFileVos; + } } \ No newline at end of file diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppBusinessFile.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppBusinessFile.java index 307b4bbd..481b2c4f 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppBusinessFile.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppBusinessFile.java @@ -47,5 +47,8 @@ public class AppBusinessFile extends TenantEntity { */ private String remark; - + /** + * 文件时长 + */ + private Integer duration; } diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppBusinessFileBo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppBusinessFileBo.java index 0454e728..a9cc5952 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppBusinessFileBo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppBusinessFileBo.java @@ -38,7 +38,7 @@ public class AppBusinessFileBo extends BaseEntity { private Long businessId; /** - * 文件类型(1:操作说明,2:产品参数) + * 文件类型(1:操作说明,2:产品参数,3:语音管理) */ private Long fileType; @@ -49,4 +49,6 @@ public class AppBusinessFileBo extends BaseEntity { private List ids; + + private Integer duration; } diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppFileVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppFileVo.java index fdad1f1a..60c3ab9e 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppFileVo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppFileVo.java @@ -27,4 +27,6 @@ public class AppFileVo { * 文件url */ private String fileUrl; + + private Integer duration; } diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppBusinessFileService.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppBusinessFileService.java index 339f926d..6c33cd4a 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppBusinessFileService.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppBusinessFileService.java @@ -78,4 +78,5 @@ public interface IAppBusinessFileService { List queryAppFileList(AppBusinessFileBo bo); + } diff --git a/fys-modules/fys-app/src/main/resources/mapper/app/AppBusinessFileMapper.xml b/fys-modules/fys-app/src/main/resources/mapper/app/AppBusinessFileMapper.xml index 2b0a9a93..7764ed1a 100644 --- a/fys-modules/fys-app/src/main/resources/mapper/app/AppBusinessFileMapper.xml +++ b/fys-modules/fys-app/src/main/resources/mapper/app/AppBusinessFileMapper.xml @@ -5,7 +5,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"