@@ -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 < Map < String , Object > > 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 < String , Object > 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 ) ;
}
}
}