调度定时把文件上传到minio , 播放基于minio
This commit is contained in:
@@ -293,6 +293,7 @@ public class AudioFileController {
|
||||
log.info("收到语音转写数据,设备号: {}", requestBody.get("deviceNo"));
|
||||
// 收到语音转写数据 , 不再处理: 保存数据库 ,用python 处理
|
||||
// processResult = handleAudioTextDataType(requestBody);
|
||||
log.info("---------------------AudioText不再保存数据库-----------------------------");
|
||||
break;
|
||||
case "LoginLog":
|
||||
log.info("收到登录日志数据,设备号: {}", requestBody.get("deviceNo"));
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.rj.dto.AsrRequest;
|
||||
import com.rj.dto.AsrResponse;
|
||||
import com.rj.config.MinIOConfig;
|
||||
import com.rj.entity.AudioManagementSegments;
|
||||
import com.rj.service.IAudioManagementSegmentsService;
|
||||
import com.rj.service.ITtsRequestLogService;
|
||||
@@ -15,6 +16,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -22,8 +24,10 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -118,52 +122,123 @@ public class AudioManagementSegmentsController {
|
||||
@PathVariable String id) {
|
||||
try {
|
||||
AudioManagementSegments segment = audioManagementSegmentsService.getById(id);
|
||||
|
||||
|
||||
if (segment == null) {
|
||||
log.warn("录音分段不存在,ID: {}", id);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
String audioFilePath = segment.getAudioFilePath();
|
||||
if (audioFilePath == null || audioFilePath.trim().isEmpty()) {
|
||||
log.warn("录音分段文件路径为空,ID: {}", id);
|
||||
return ResponseEntity.badRequest().build();
|
||||
if (isWindowsOs()) {
|
||||
return playSegmentUsingAudioFileUrl(segment, id);
|
||||
}
|
||||
return playSegmentUsingLocalFilePath(segment, id);
|
||||
|
||||
File file = new File(audioFilePath);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
log.warn("音频文件不存在或不是文件,路径: {}", audioFilePath);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
// 检查文件是否为音频文件
|
||||
if (!isAudioFile(audioFilePath)) {
|
||||
log.warn("文件不是音频文件,路径: {}", audioFilePath);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
Resource resource = new FileSystemResource(file);
|
||||
|
||||
// 设置响应头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(getContentType(audioFilePath)));
|
||||
headers.setContentLength(file.length());
|
||||
headers.set("Accept-Ranges", "bytes");
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.body(resource);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("播放录音分段音频文件异常,ID: {}, error: {}", id, e.getMessage(), e);
|
||||
return ResponseEntity.internalServerError().build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Linux 等环境:按分段表中的本地路径 {@link AudioManagementSegments#getAudioFilePath()} 读取并返回音频流(与原实现一致)。
|
||||
*/
|
||||
private ResponseEntity<Resource> playSegmentUsingLocalFilePath(AudioManagementSegments segment, String id) {
|
||||
String audioFilePath = segment.getAudioFilePath();
|
||||
if (audioFilePath == null || audioFilePath.trim().isEmpty()) {
|
||||
log.warn("录音分段文件路径为空,ID: {}", id);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
File file = new File(audioFilePath);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
log.warn("音频文件不存在或不是文件,路径: {}", audioFilePath);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (!isAudioFile(audioFilePath)) {
|
||||
log.warn("文件不是音频文件,路径: {}", audioFilePath);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
Resource resource = new FileSystemResource(file);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(getContentType(audioFilePath)));
|
||||
headers.setContentLength(file.length());
|
||||
headers.set("Accept-Ranges", "bytes");
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.body(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows:在已根据 ID 查到分段记录的前提下,使用 {@link AudioManagementSegments#getAudioFileUrl()}(MinIO 访问 URL)
|
||||
* 解析对象名并从 MinIO 拉流播放,逻辑对齐 {@link MinIOController#downloadFile} 的 downloadFile 调用方式。
|
||||
*/
|
||||
private ResponseEntity<Resource> playSegmentUsingAudioFileUrl(AudioManagementSegments segment, String id) {
|
||||
String audioFileUrl = segment.getAudioFileUrl();
|
||||
if (audioFileUrl == null || audioFileUrl.trim().isEmpty()) {
|
||||
log.warn("录音分段音频 URL 为空,ID: {}", id);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
String loc = audioFileUrl.trim();
|
||||
String nameProbe = lastPathSegmentForAudioCheck(loc);
|
||||
if (!isAudioFile(nameProbe)) {
|
||||
log.warn("文件不是音频文件,location: {}", loc);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
String objectName = resolveMinioObjectName(loc);
|
||||
if (objectName == null || objectName.isEmpty()) {
|
||||
log.warn("无法从 URL 解析 MinIO 对象名,ID: {}, location: {}", id, loc);
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
try {
|
||||
InputStream inputStream = minIOService.downloadFile(objectName);
|
||||
Resource resource = new InputStreamResource(inputStream);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(getContentType(nameProbe)));
|
||||
headers.set("Accept-Ranges", "bytes");
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.body(resource);
|
||||
} catch (Exception e) {
|
||||
log.error("从 MinIO 读取分段音频失败,ID: {}, objectName: {}", id, objectName, e);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWindowsOs() {
|
||||
String os = System.getProperty("os.name", "");
|
||||
return os != null && os.toLowerCase(Locale.ROOT).contains("win");
|
||||
}
|
||||
|
||||
/** 去掉查询串后取路径最后一段,避免 URL 中带 IP 时扩展名判断错误。 */
|
||||
private static String lastPathSegmentForAudioCheck(String urlOrPath) {
|
||||
if (urlOrPath == null) {
|
||||
return "";
|
||||
}
|
||||
String s = urlOrPath.trim();
|
||||
int q = s.indexOf('?');
|
||||
if (q >= 0) {
|
||||
s = s.substring(0, q);
|
||||
}
|
||||
int slash = Math.max(s.lastIndexOf('/'), s.lastIndexOf('\\'));
|
||||
return slash >= 0 ? s.substring(slash + 1) : s;
|
||||
}
|
||||
@Autowired
|
||||
private ITtsRequestLogService ttsRequestLogService;
|
||||
|
||||
@Autowired
|
||||
private MinIOService minIOService;
|
||||
|
||||
@Autowired
|
||||
private MinIOConfig minioConfig;
|
||||
|
||||
/**
|
||||
* 转文本请求
|
||||
@@ -341,6 +416,27 @@ public class AudioManagementSegmentsController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从分段表中的 MinIO 访问 URL 解析对象键:优先按 {@link MinIOConfig#getFileUrlPrefix()} 去掉前缀得到完整 object 路径
|
||||
*(与 {@link MinIOService#getFileUrl(String)} 生成的 URL 一致),否则回退为 {@link #extractObjectNameFromUrl(String)}。
|
||||
*/
|
||||
private String resolveMinioObjectName(String audioFileUrl) {
|
||||
if (audioFileUrl == null || audioFileUrl.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = audioFileUrl.trim();
|
||||
String withoutQuery = trimmed;
|
||||
int q = trimmed.indexOf('?');
|
||||
if (q >= 0) {
|
||||
withoutQuery = trimmed.substring(0, q);
|
||||
}
|
||||
String prefix = minioConfig.getFileUrlPrefix();
|
||||
if (prefix != null && !prefix.isEmpty() && withoutQuery.startsWith(prefix)) {
|
||||
return withoutQuery.substring(prefix.length());
|
||||
}
|
||||
return extractObjectNameFromUrl(trimmed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从MinIO URL中提取对象名
|
||||
* @param url MinIO文件URL
|
||||
|
||||
Reference in New Issue
Block a user