Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -45,19 +45,6 @@ public class ChatWebSocketHandler {
|
||||
// @Value("${whisper.language}")
|
||||
private String language = "en";
|
||||
|
||||
/**
|
||||
* 16kHz
|
||||
*/
|
||||
private static final int SAMPLE_RATE = 16000;
|
||||
/**
|
||||
* 4 KB 每次读取
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
/**
|
||||
* 每样本 16 位
|
||||
*/
|
||||
private static final int BITS_PER_SAMPLE = 16;
|
||||
|
||||
/**
|
||||
* 缓存客户端流式解析的语音文本数据
|
||||
*/
|
||||
@@ -68,12 +55,6 @@ public class ChatWebSocketHandler {
|
||||
*/
|
||||
private final Map<String, WebSocket> cacheWebSocket = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 为每个会话维护分片缓存(线程安全,支持多用户)
|
||||
*/
|
||||
private final ConcurrentHashMap<String, List<byte[]>> fragmentCache = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
// 语音文件保存目录
|
||||
private static final String VOICE_STORAGE_DIR = "/voice_files/";
|
||||
|
||||
@@ -98,6 +79,7 @@ public class ChatWebSocketHandler {
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("clientId") String clientId) {
|
||||
log.info("WebSocket 链接已建立:{}", clientId);
|
||||
log.info("WebSocket session 链接已建立:{}", session.getId());
|
||||
cacheClientTts.put(clientId,new String());
|
||||
//初始化STT流式语音转换文本的socket链接
|
||||
createWhisperRealtimeSocket(clientId);
|
||||
@@ -116,26 +98,14 @@ public class ChatWebSocketHandler {
|
||||
if("done".equals(resultFlag)){
|
||||
log.info("1、开始处理时间:{}",System.currentTimeMillis()/1000);
|
||||
// //开始合并语音流
|
||||
// List<byte[]> fragments = fragmentCache.get(clientId);
|
||||
// // 合并所有分片为完整语音数据
|
||||
// byte[] fullVoiceData = mergeFragments(fragments);
|
||||
// // 生成唯一文件名
|
||||
// String fileName = clientId + "_" + System.currentTimeMillis() + ".webm";
|
||||
// String pathUrl = RuoYiConfig.getProfile()+VOICE_STORAGE_DIR + fileName;
|
||||
// log.info("文件路径为:{}", pathUrl);
|
||||
// log.info("文件流的大小为:{}",fullVoiceData.length);
|
||||
// saveAsWebM(fullVoiceData,pathUrl);
|
||||
// //开始转换
|
||||
// WhisperClient whisperClient = SpringUtils.getBean(WhisperClient.class);
|
||||
// String cacheResultText = whisperClient.handleVoiceToText(pathUrl);
|
||||
|
||||
//发送消息
|
||||
WebSocket webSocket = cacheWebSocket.get(clientId);
|
||||
if(webSocket != null){
|
||||
|
||||
}
|
||||
webSocket.send("{\"type\": \"input_audio_buffer.commit\"}");
|
||||
webSocket.send("{\"type\": \"response.create\"}");
|
||||
// if(webSocket != null){
|
||||
// webSocket.close(1000,null);
|
||||
// }
|
||||
|
||||
//语音结束,开始进行回答解析
|
||||
String cacheResultText = cacheClientTts.get(clientId);
|
||||
log.info("返回的结果为:{}",cacheResultText);
|
||||
@@ -247,30 +217,14 @@ public class ChatWebSocketHandler {
|
||||
|
||||
}
|
||||
|
||||
// 接收二进制消息(流数据)
|
||||
// @OnMessage
|
||||
// public void onBinaryMessage(Session session, @PathParam("clientId") String clientId, ByteBuffer byteBuffer) {
|
||||
// log.info("1、开始接收数据流时间:{}",System.currentTimeMillis()/1000);
|
||||
// log.info("客户端ID为:{}", clientId);
|
||||
// // 处理二进制流数据
|
||||
// byte[] bytes = new byte[byteBuffer.remaining()];
|
||||
// //从缓冲区中读取数据并存储到指定的字节数组中
|
||||
// byteBuffer.get(bytes);
|
||||
//
|
||||
// // 1. 获取当前会话的缓存
|
||||
// List<byte[]> fragments = fragmentCache.get(clientId);
|
||||
// if (fragments == null) {
|
||||
// fragments = new ArrayList<>();
|
||||
// fragmentCache.put(clientId, fragments);
|
||||
// }
|
||||
// fragments.add(bytes);
|
||||
// fragmentCache.put(clientId, fragments);
|
||||
// }
|
||||
|
||||
// 连接关闭时调用
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason reason) {
|
||||
System.out.println("WebSocket连接已关闭: " + session.getId() + ", 原因: " + reason.getReasonPhrase());
|
||||
// WebSocket webSocket = cacheWebSocket.get(clientId);
|
||||
// if(webSocket != null){
|
||||
// webSocket.close(1000,null);
|
||||
// }
|
||||
}
|
||||
|
||||
// 发生错误时调用
|
||||
@@ -293,17 +247,10 @@ public class ChatWebSocketHandler {
|
||||
System.err.println("字节数组为空,无法生成WebM文件");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filePath == null || filePath.trim().isEmpty()) {
|
||||
System.err.println("文件路径不能为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保文件以.webm结尾
|
||||
// if (!filePath.toLowerCase().endsWith(".webm")) {
|
||||
// filePath += ".webm";
|
||||
// }
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(filePath);
|
||||
@@ -349,7 +296,6 @@ public class ChatWebSocketHandler {
|
||||
private void createWhisperRealtimeSocket(String clientId){
|
||||
try{
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
// CountDownLatch latch = new CountDownLatch(1);
|
||||
// 设置 WebSocket 请求
|
||||
Request request = new Request.Builder()
|
||||
.url(API_URL)
|
||||
@@ -419,33 +365,11 @@ public class ChatWebSocketHandler {
|
||||
// latch.countDown();
|
||||
}
|
||||
});
|
||||
// 等待 WebSocket 关闭
|
||||
// latch.await();
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 合并分片数组为完整字节数组
|
||||
*/
|
||||
private byte[] mergeFragments(List<byte[]> fragments) {
|
||||
// 计算总长度
|
||||
int totalLength = 0;
|
||||
for (byte[] fragment : fragments) {
|
||||
totalLength += fragment.length;
|
||||
}
|
||||
// 拼接所有分片
|
||||
byte[] result = new byte[totalLength];
|
||||
int offset = 0;
|
||||
for (byte[] fragment : fragments) {
|
||||
System.arraycopy(fragment, 0, result, offset, fragment.length);
|
||||
offset += fragment.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音流文件格式转换
|
||||
* @param pathUrl
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.vetti.web.controller.system;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -30,6 +33,7 @@ import com.vetti.system.service.ISysDictTypeService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="数据字典信息模块")
|
||||
@RestController
|
||||
@RequestMapping("/system/dict/data")
|
||||
public class SysDictDataController extends BaseController
|
||||
@@ -62,9 +66,10 @@ public class SysDictDataController extends BaseController
|
||||
/**
|
||||
* 查询字典数据详细
|
||||
*/
|
||||
@ApiOperation("查询字典数据详细")
|
||||
@PreAuthorize("@ss.hasPermi('system:dict:query')")
|
||||
@GetMapping(value = "/{dictCode}")
|
||||
public AjaxResult getInfo(@PathVariable Long dictCode)
|
||||
public AjaxResult<SysDictData> getInfo(@PathVariable Long dictCode)
|
||||
{
|
||||
return success(dictDataService.selectDictDataById(dictCode));
|
||||
}
|
||||
@@ -72,8 +77,9 @@ public class SysDictDataController extends BaseController
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@ApiOperation("根据字典类型查询字典数据信息")
|
||||
@GetMapping(value = "/type/{dictType}")
|
||||
public AjaxResult dictType(@PathVariable String dictType)
|
||||
public AjaxResult<List<SysDictData>> dictType(@PathVariable String dictType)
|
||||
{
|
||||
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
|
||||
if (StringUtils.isNull(data))
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import com.vetti.common.utils.MessageUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -29,6 +31,7 @@ import com.vetti.system.service.ISysMenuService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="登录模块")
|
||||
@RestController
|
||||
public class SysLoginController
|
||||
{
|
||||
@@ -53,6 +56,7 @@ public class SysLoginController
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiOperation("登录方法")
|
||||
@PostMapping("/login")
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
@@ -69,6 +73,7 @@ public class SysLoginController
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
@ApiOperation("获取用户信息")
|
||||
@GetMapping("getInfo")
|
||||
public AjaxResult getInfo()
|
||||
{
|
||||
@@ -84,11 +89,13 @@ public class SysLoginController
|
||||
tokenService.refreshToken(loginUser);
|
||||
}
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("user", user);
|
||||
ajax.put("roles", roles);
|
||||
ajax.put("permissions", permissions);
|
||||
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
Map mapInfo = new HashMap();
|
||||
mapInfo.put("user", user);
|
||||
mapInfo.put("roles", roles);
|
||||
mapInfo.put("permissions", permissions);
|
||||
mapInfo.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
|
||||
mapInfo.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
|
||||
ajax.put("data", mapInfo);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
@@ -97,6 +104,7 @@ public class SysLoginController
|
||||
*
|
||||
* @return 路由信息
|
||||
*/
|
||||
@ApiOperation("获取路由信息")
|
||||
@GetMapping("getRouters")
|
||||
public AjaxResult getRouters()
|
||||
{
|
||||
@@ -128,4 +136,19 @@ public class SysLoginController
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiOperation("忘记密码")
|
||||
@PostMapping("/forgotPassword")
|
||||
public AjaxResult handlePassword(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
loginService.resetPassword(loginBody.getUsername(),loginBody.getPassword(),loginBody.getRepeatPassword(),loginBody.getCode(),loginBody.getUuid());
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemCommonTip10001"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -16,23 +18,19 @@ import com.vetti.system.service.ISysConfigService;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Api(tags ="注册验证模块")
|
||||
@RestController
|
||||
public class SysRegisterController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private SysRegisterService registerService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@ApiOperation("注册方法")
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody RegisterBody user)
|
||||
{
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.vetti.web.controller.system;
|
||||
|
||||
import com.vetti.common.core.controller.BaseController;
|
||||
import com.vetti.common.core.domain.AjaxResult;
|
||||
import com.vetti.common.service.verification.VerificationService;
|
||||
import com.vetti.common.utils.MessageUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author ID
|
||||
* @date 2025/8/28 16:16
|
||||
*/
|
||||
@Api(tags ="验证码共通接口")
|
||||
@RestController
|
||||
@RequestMapping("/verification")
|
||||
@RequiredArgsConstructor
|
||||
public class VerificationController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private final VerificationService verificationEmailService;
|
||||
|
||||
|
||||
@ApiOperation("发送验证码(标题、内容走的配置文件)")
|
||||
@PostMapping("/email/send")
|
||||
public AjaxResult sendVerificationCode(@RequestParam String email) {
|
||||
boolean isSent = verificationEmailService.sendVerificationEm7941VerificationCode(email);
|
||||
if (isSent) {
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10001"));
|
||||
} else {
|
||||
return AjaxResult.error(MessageUtils.messageCustomize("systemVerificationEmailController10002"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮箱验证码
|
||||
*/
|
||||
@PostMapping("/email/verify")
|
||||
public AjaxResult verifyCode(@RequestParam String email, @RequestParam String code) {
|
||||
boolean isValid = verificationEmailService.verifyCode(email, code);
|
||||
if (isValid) {
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10003"));
|
||||
} else {
|
||||
return AjaxResult.error(MessageUtils.messageCustomize("systemVerificationEmailController10004"));
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation("发送验证码(手机)")
|
||||
@PostMapping("/phone/send")
|
||||
public AjaxResult sendPhoneVerificationCode(@RequestParam String phone) {
|
||||
verificationEmailService.sendPhoneVerificationCode(phone);
|
||||
return AjaxResult.success(MessageUtils.messageCustomize("systemVerificationEmailController10003"));
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,10 @@ twilio:
|
||||
from-name: RouteZ
|
||||
template-ids:
|
||||
routez-verification-code: d-321fee8a85704983849eb1f69313ae24
|
||||
accountSID: 1111
|
||||
authToken: 22222
|
||||
sendPhoneNumber: 33333
|
||||
|
||||
verification:
|
||||
code:
|
||||
email:
|
||||
@@ -148,6 +152,7 @@ elevenLabs:
|
||||
# apiKey: sk_5240d8f56cb1eb5225fffcf903f62479884d1af5b3de6812
|
||||
apiKey: sk_88f5a560e1bbde0e5b8b6b6eb1812163a98bfb98554acbec
|
||||
modelId: eleven_turbo_v2_5
|
||||
|
||||
# 语音转文本
|
||||
whisper:
|
||||
apiUrl: https://api.openai.com/v1/audio/transcriptions
|
||||
|
||||
@@ -37,6 +37,21 @@ systemVerificationEmailController10004 = The Verification Code Is Invalid Or Has
|
||||
|
||||
SystemCommandOverhaulAppController10001 = Operation Successful
|
||||
|
||||
|
||||
systemSysLoginService10001 = The username cannot be empty
|
||||
systemSysLoginService10002 = User password cannot be empty
|
||||
systemSysLoginService10003 = User does not exist
|
||||
systemSysLoginService10004 = Passwords do not match
|
||||
|
||||
systemSysRegisterService10001 = The username cannot be empty
|
||||
systemSysRegisterService10002 = User password cannot be empty
|
||||
systemSysRegisterService10003 = The account length must be between 2 and 20 characters
|
||||
systemSysRegisterService10004 = The password length must be between 5 and 20 characters
|
||||
systemSysRegisterService10005 = Save User
|
||||
systemSysRegisterService10006 = Failed, registered account already exists
|
||||
systemSysRegisterService10007 = Registration failed, please contact the system administrator
|
||||
|
||||
|
||||
systemEmailUtil10001 = Sending Email Failed
|
||||
systemR10001 = Operation Successful
|
||||
|
||||
|
||||
@@ -37,6 +37,19 @@ systemVerificationEmailController10004 = 验证码无效或已过期
|
||||
|
||||
SystemCommandOverhaulAppController10001 = 操作成功
|
||||
|
||||
systemSysLoginService10001 = 用户名不能为空
|
||||
systemSysLoginService10002 = 用户密码不能为空
|
||||
systemSysLoginService10003 = 用户不存在
|
||||
systemSysLoginService10004 = 密码不一致
|
||||
|
||||
systemSysRegisterService10001 = 用户名不能为空
|
||||
systemSysRegisterService10002 = 用户密码不能为空
|
||||
systemSysRegisterService10003 = 账户长度必须在2到20个字符之间
|
||||
systemSysRegisterService10004 = 密码长度必须在5到20个字符之间
|
||||
systemSysRegisterService10005 = 保存用户
|
||||
systemSysRegisterService10006 = 失败,注册账号已存在
|
||||
systemSysRegisterService10007 = 注册失败,请联系系统管理人员
|
||||
|
||||
systemEmailUtil10001 = 发送邮件失败
|
||||
systemR10001 = 操作成功
|
||||
|
||||
|
||||
@@ -135,6 +135,10 @@ twilio:
|
||||
from-name: RouteZ
|
||||
template-ids:
|
||||
routez-verification-code: d-321fee8a85704983849eb1f69313ae24
|
||||
accountSID: 1111
|
||||
authToken: 22222
|
||||
sendPhoneNumber: 33333
|
||||
|
||||
verification:
|
||||
code:
|
||||
email:
|
||||
@@ -148,6 +152,7 @@ elevenLabs:
|
||||
# apiKey: sk_5240d8f56cb1eb5225fffcf903f62479884d1af5b3de6812
|
||||
apiKey: sk_88f5a560e1bbde0e5b8b6b6eb1812163a98bfb98554acbec
|
||||
modelId: eleven_turbo_v2_5
|
||||
|
||||
# 语音转文本
|
||||
whisper:
|
||||
apiUrl: https://api.openai.com/v1/audio/transcriptions
|
||||
|
||||
@@ -37,6 +37,21 @@ systemVerificationEmailController10004 = The Verification Code Is Invalid Or Has
|
||||
|
||||
SystemCommandOverhaulAppController10001 = Operation Successful
|
||||
|
||||
|
||||
systemSysLoginService10001 = The username cannot be empty
|
||||
systemSysLoginService10002 = User password cannot be empty
|
||||
systemSysLoginService10003 = User does not exist
|
||||
systemSysLoginService10004 = Passwords do not match
|
||||
|
||||
systemSysRegisterService10001 = The username cannot be empty
|
||||
systemSysRegisterService10002 = User password cannot be empty
|
||||
systemSysRegisterService10003 = The account length must be between 2 and 20 characters
|
||||
systemSysRegisterService10004 = The password length must be between 5 and 20 characters
|
||||
systemSysRegisterService10005 = Save User
|
||||
systemSysRegisterService10006 = Failed, registered account already exists
|
||||
systemSysRegisterService10007 = Registration failed, please contact the system administrator
|
||||
|
||||
|
||||
systemEmailUtil10001 = Sending Email Failed
|
||||
systemR10001 = Operation Successful
|
||||
|
||||
|
||||
@@ -37,6 +37,19 @@ systemVerificationEmailController10004 = 验证码无效或已过期
|
||||
|
||||
SystemCommandOverhaulAppController10001 = 操作成功
|
||||
|
||||
systemSysLoginService10001 = 用户名不能为空
|
||||
systemSysLoginService10002 = 用户密码不能为空
|
||||
systemSysLoginService10003 = 用户不存在
|
||||
systemSysLoginService10004 = 密码不一致
|
||||
|
||||
systemSysRegisterService10001 = 用户名不能为空
|
||||
systemSysRegisterService10002 = 用户密码不能为空
|
||||
systemSysRegisterService10003 = 账户长度必须在2到20个字符之间
|
||||
systemSysRegisterService10004 = 密码长度必须在5到20个字符之间
|
||||
systemSysRegisterService10005 = 保存用户
|
||||
systemSysRegisterService10006 = 失败,注册账号已存在
|
||||
systemSysRegisterService10007 = 注册失败,请联系系统管理人员
|
||||
|
||||
systemEmailUtil10001 = 发送邮件失败
|
||||
systemR10001 = 操作成功
|
||||
|
||||
|
||||
Reference in New Issue
Block a user