音频处理服务
This commit is contained in:
@ -1,24 +1,24 @@
|
|||||||
package com.fuyuanshen;
|
package com.fuyuanshen;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动程序
|
* 启动程序
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class DromaraApplication {
|
public class DromaraApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication application = new SpringApplication(DromaraApplication.class);
|
||||||
|
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
||||||
|
application.run(args);
|
||||||
|
System.out.println("(♥◠‿◠)ノ゙ fys-Vue-Plus启动成功 ლ(´ڡ`ლ)゙");
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication application = new SpringApplication(DromaraApplication.class);
|
|
||||||
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
|
||||||
application.run(args);
|
|
||||||
System.out.println("(♥◠‿◠)ノ゙ fys-Vue-Plus启动成功 ლ(´ڡ`ლ)゙");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -101,6 +102,12 @@ public class AudioProcessService {
|
|||||||
// log.info("测试文件已保存: {}", savedPath);
|
// log.info("测试文件已保存: {}", savedPath);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// 保存WAV文件到本地
|
||||||
|
String savedPath = saveByteArrayToFile(pcmData, "tts_output.wav");
|
||||||
|
if (savedPath != null) {
|
||||||
|
log.info("WAV文件已保存: {}", savedPath);
|
||||||
|
}
|
||||||
|
|
||||||
// 将byte[]转换为16进制字符串列表
|
// 将byte[]转换为16进制字符串列表
|
||||||
List<String> hexList = audioProcessUtil.bytesToHexList(pcmData);
|
List<String> hexList = audioProcessUtil.bytesToHexList(pcmData);
|
||||||
|
|
||||||
@ -113,6 +120,55 @@ public class AudioProcessService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String saveWavFileLocally(String text, String filename) throws IOException {
|
||||||
|
// 参数校验
|
||||||
|
if (text == null || text.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("文本内容不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename == null || filename.trim().isEmpty()) {
|
||||||
|
filename = "tts_output.wav"; // 默认文件名
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 生成PCM数据
|
||||||
|
byte[] rawPcmData = alibabaTTSUtil.generateStandardPcmData(text);
|
||||||
|
|
||||||
|
// 转换为标准WAV格式(添加44字节头部)
|
||||||
|
byte[] wavData = audioProcessUtil.rawPcmToStandardWav(rawPcmData);
|
||||||
|
|
||||||
|
// 保存到本地文件
|
||||||
|
String filePath = saveByteArrayToFile(wavData, filename);
|
||||||
|
|
||||||
|
log.info("WAV文件已保存: {}", filePath);
|
||||||
|
return filePath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存WAV文件失败: {}", e.getMessage(), e);
|
||||||
|
throw new IOException("保存WAV文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String saveByteArrayToFile(byte[] data, String filename) throws IOException {
|
||||||
|
// 确定保存路径(可以是临时目录或指定目录)
|
||||||
|
String directory = System.getProperty("java.io.tmpdir"); // 使用系统临时目录
|
||||||
|
File dir = new File(directory);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建完整文件路径
|
||||||
|
File file = new File(dir, filename);
|
||||||
|
|
||||||
|
// 写入文件
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
fos.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证音频文件
|
* 验证音频文件
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -52,32 +52,32 @@ spring:
|
|||||||
url: jdbc:mysql://47.120.79.150:3306/fys-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
url: jdbc:mysql://47.120.79.150:3306/fys-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
username: root
|
username: root
|
||||||
password: Jq_123456#
|
password: Jq_123456#
|
||||||
# # 从库数据源
|
# # 从库数据源
|
||||||
# slave:
|
# slave:
|
||||||
# lazy: true
|
# lazy: true
|
||||||
# type: ${spring.datasource.type}
|
# type: ${spring.datasource.type}
|
||||||
# driverClassName: com.mysql.cj.jdbc.Driver
|
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
# username:
|
# username:
|
||||||
# password:
|
# password:
|
||||||
# oracle:
|
# oracle:
|
||||||
# type: ${spring.datasource.type}
|
# type: ${spring.datasource.type}
|
||||||
# driverClassName: oracle.jdbc.OracleDriver
|
# driverClassName: oracle.jdbc.OracleDriver
|
||||||
# url: jdbc:oracle:thin:@//localhost:1521/XE
|
# url: jdbc:oracle:thin:@//localhost:1521/XE
|
||||||
# username: ROOT
|
# username: ROOT
|
||||||
# password: root
|
# password: root
|
||||||
# postgres:
|
# postgres:
|
||||||
# type: ${spring.datasource.type}
|
# type: ${spring.datasource.type}
|
||||||
# driverClassName: org.postgresql.Driver
|
# driverClassName: org.postgresql.Driver
|
||||||
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
|
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
|
||||||
# username: root
|
# username: root
|
||||||
# password: root
|
# password: root
|
||||||
# sqlserver:
|
# sqlserver:
|
||||||
# type: ${spring.datasource.type}
|
# type: ${spring.datasource.type}
|
||||||
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||||
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
|
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
|
||||||
# username: SA
|
# username: SA
|
||||||
# password: root
|
# password: root
|
||||||
hikari:
|
hikari:
|
||||||
# 最大连接池数量
|
# 最大连接池数量
|
||||||
maxPoolSize: 20
|
maxPoolSize: 20
|
||||||
@ -177,12 +177,12 @@ sms:
|
|||||||
access-key-id: LTAI5tJdDNpZootsPQ5hdELx
|
access-key-id: LTAI5tJdDNpZootsPQ5hdELx
|
||||||
# 称为accessSecret有些称之为apiSecret
|
# 称为accessSecret有些称之为apiSecret
|
||||||
access-key-secret: mU4WtffcCXpHPz5tLwQpaGtLsJXONt
|
access-key-secret: mU4WtffcCXpHPz5tLwQpaGtLsJXONt
|
||||||
#模板ID 非必须配置,如果使用sendMessage的快速发送需此配置
|
#模板ID 非必须配置,如果使用sendMessage的快速发送需此配置
|
||||||
template-id: SMS_322180518
|
template-id: SMS_322180518
|
||||||
#模板变量 上述模板的变量
|
#模板变量 上述模板的变量
|
||||||
templateName: code
|
templateName: code
|
||||||
signature: 湖北星汉研创科技
|
signature: 湖北星汉研创科技
|
||||||
# sdk-app-id: 您的sdkAppId
|
# sdk-app-id: 您的sdkAppId
|
||||||
config2:
|
config2:
|
||||||
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
|
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
|
||||||
supplier: tencent
|
supplier: tencent
|
||||||
@ -210,7 +210,7 @@ justauth:
|
|||||||
client-id: 449c4*********937************759
|
client-id: 449c4*********937************759
|
||||||
client-secret: ac7***********1e0************28d
|
client-secret: ac7***********1e0************28d
|
||||||
redirect-uri: ${justauth.address}/social-callback?source=topiam
|
redirect-uri: ${justauth.address}/social-callback?source=topiam
|
||||||
scopes: [openid, email, phone, profile]
|
scopes: [ openid, email, phone, profile ]
|
||||||
qq:
|
qq:
|
||||||
client-id: 10**********6
|
client-id: 10**********6
|
||||||
client-secret: 1f7d08**********5b7**********29e
|
client-secret: 1f7d08**********5b7**********29e
|
||||||
@ -276,27 +276,6 @@ justauth:
|
|||||||
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
||||||
|
|
||||||
|
|
||||||
# 文件存储路径
|
|
||||||
file:
|
|
||||||
mac:
|
|
||||||
path: ~/file/
|
|
||||||
avatar: ~/avatar/
|
|
||||||
linux:
|
|
||||||
path: /home/eladmin/file/
|
|
||||||
avatar: /home/eladmin/avatar/
|
|
||||||
windows:
|
|
||||||
path: C:\eladmin\file\
|
|
||||||
avatar: C:\eladmin\avatar\
|
|
||||||
# 文件大小 /M
|
|
||||||
maxSize: 100
|
|
||||||
avatarMaxSize: 5
|
|
||||||
device:
|
|
||||||
pic: C:\eladmin\file\ #设备图片存储路径
|
|
||||||
ip: http://fuyuanshen.com:81/ #服务器地址
|
|
||||||
app_avatar:
|
|
||||||
pic: C:\eladmin\file\ #设备图片存储路径
|
|
||||||
#ip: http://fuyuanshen.com:81/ #服务器地址
|
|
||||||
ip: https://fuyuanshen.com/ #服务器地址
|
|
||||||
# MQTT配置
|
# MQTT配置
|
||||||
mqtt:
|
mqtt:
|
||||||
username: admin
|
username: admin
|
||||||
@ -306,3 +285,11 @@ mqtt:
|
|||||||
subTopic: A/#
|
subTopic: A/#
|
||||||
pubTopic: B/#
|
pubTopic: B/#
|
||||||
pubClientId: fys_pubClient
|
pubClientId: fys_pubClient
|
||||||
|
|
||||||
|
|
||||||
|
# TTS语音交互配置
|
||||||
|
alibaba:
|
||||||
|
tts:
|
||||||
|
appKey: KTwSUKMrf2olFfjC
|
||||||
|
akId: LTAI5t6RsfCvQh57qojzbEoe
|
||||||
|
akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R
|
||||||
@ -294,24 +294,3 @@ alibaba:
|
|||||||
akId: LTAI5t6RsfCvQh57qojzbEoe
|
akId: LTAI5t6RsfCvQh57qojzbEoe
|
||||||
akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R
|
akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R
|
||||||
|
|
||||||
# 文件存储路径
|
|
||||||
file:
|
|
||||||
mac:
|
|
||||||
path: ~/file/
|
|
||||||
avatar: ~/avatar/
|
|
||||||
linux:
|
|
||||||
path: /home/eladmin/file/
|
|
||||||
avatar: /home/eladmin/avatar/
|
|
||||||
windows:
|
|
||||||
path: C:\eladmin\file\
|
|
||||||
avatar: C:\eladmin\avatar\
|
|
||||||
# 文件大小 /M
|
|
||||||
maxSize: 100
|
|
||||||
avatarMaxSize: 5
|
|
||||||
device:
|
|
||||||
pic: C:\eladmin\file\ #设备图片存储路径
|
|
||||||
ip: http://fuyuanshen.com:81/ #服务器地址
|
|
||||||
app_avatar:
|
|
||||||
pic: C:\eladmin\file\ #设备图片存储路径
|
|
||||||
#ip: http://fuyuanshen.com:81/ #服务器地址
|
|
||||||
ip: https://fuyuanshen.com/ #服务器地址
|
|
||||||
@ -3,7 +3,7 @@ package com.fuyuanshen.equipment.domain.vo;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据总览
|
* 首页数据总览
|
||||||
*
|
*
|
||||||
* @author: 默苍璃
|
* @author: 默苍璃
|
||||||
* @date: 2025-09-0114:24
|
* @date: 2025-09-0114:24
|
||||||
|
|||||||
@ -66,11 +66,6 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
|||||||
|
|
||||||
private final ISysRoleService roleService;
|
private final ISysRoleService roleService;
|
||||||
|
|
||||||
@Value("${file.device.pic}")
|
|
||||||
private String filePath;
|
|
||||||
@Value("${file.device.ip}")
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
private final DeviceMapper deviceMapper;
|
private final DeviceMapper deviceMapper;
|
||||||
private final DeviceTypeMapper deviceTypeMapper;
|
private final DeviceTypeMapper deviceTypeMapper;
|
||||||
private final CustomerMapper customerMapper;
|
private final CustomerMapper customerMapper;
|
||||||
@ -301,35 +296,6 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存设备图片并返回访问路径
|
|
||||||
*
|
|
||||||
* @param file MultipartFile
|
|
||||||
* @param deviceMac 设备MAC用于生成唯一文件名
|
|
||||||
* @return 文件存储路径 URL 形式
|
|
||||||
*/
|
|
||||||
private String saveDeviceImage(MultipartFile file, String deviceMac) throws IOException {
|
|
||||||
if (file == null || file.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String originalFileName = file.getOriginalFilename();
|
|
||||||
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
|
|
||||||
String newFileName = "PS_" + deviceMac + "." + fileExtension;
|
|
||||||
|
|
||||||
File newFile = new File(filePath + DeviceConstants.FILE_ACCESS_ISOLATION + File.separator + newFileName);
|
|
||||||
|
|
||||||
if (!newFile.getParentFile().exists()) {
|
|
||||||
newFile.getParentFile().mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("图片保存路径: {}", newFile.getAbsolutePath());
|
|
||||||
file.transferTo(newFile);
|
|
||||||
|
|
||||||
return ip + DeviceConstants.FILE_ACCESS_PREFIX + "/" + DeviceConstants.FILE_ACCESS_ISOLATION + "/" + newFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除设备
|
* 删除设备
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user