Merge branch 'main' into mqtt-call

This commit is contained in:
hrz
2025-09-18 15:02:32 +08:00
committed by GitHub
42 changed files with 1523 additions and 261 deletions
@@ -55,4 +55,113 @@ public interface ErrorCode {
int OTA_DEVICE_NOT_FOUND = 10041;
int OTA_DEVICE_NEED_BIND = 10042;
// 新增错误编码
int DELETE_DATA_FAILED = 10043;
int USER_NOT_LOGIN = 10044;
int WEB_SOCKET_CONNECT_FAILED = 10045;
int VOICE_PRINT_SAVE_ERROR = 10046;
int TODAY_SMS_LIMIT_REACHED = 10047;
int OLD_PASSWORD_ERROR = 10048;
int INVALID_LLM_TYPE = 10049;
int TOKEN_GENERATE_ERROR = 10050;
int RESOURCE_NOT_FOUND = 10051;
// 新增错误编码
int DEFAULT_AGENT_NOT_FOUND = 10052;
int AGENT_NOT_FOUND = 10053;
int VOICEPRINT_API_NOT_CONFIGURED = 10054;
int SMS_SEND_FAILED = 10055;
int SMS_CONNECTION_FAILED = 10056;
int AGENT_VOICEPRINT_CREATE_FAILED = 10057;
int AGENT_VOICEPRINT_UPDATE_FAILED = 10058;
int AGENT_VOICEPRINT_DELETE_FAILED = 10059;
int SMS_SEND_TOO_FREQUENTLY = 10060;
int ACTIVATION_CODE_EMPTY = 10061;
int ACTIVATION_CODE_ERROR = 10062;
int DEVICE_ALREADY_ACTIVATED = 10063;
// 默认模型删除错误
int DEFAULT_MODEL_DELETE_ERROR = 10064;
// 设备相关错误码
int MAC_ADDRESS_ALREADY_EXISTS = 10090; // Mac地址已存在
// 模型相关错误码
int MODEL_PROVIDER_NOT_EXIST = 10091; // 供应器不存在
int LLM_NOT_EXIST = 10092; // 设置的LLM不存在
int MODEL_REFERENCED_BY_AGENT = 10093; // 该模型配置已被智能体引用,无法删除
int LLM_REFERENCED_BY_INTENT = 10094; // 该LLM模型已被意图识别配置引用,无法删除
// 登录相关错误码
int ADD_DATA_FAILED = 10065; // 新增数据失败
int UPDATE_DATA_FAILED = 10066; // 修改数据失败
int SMS_CAPTCHA_ERROR = 10067; // 短信验证码错误
int MOBILE_REGISTER_DISABLED = 10068; // 未开启手机注册
int USERNAME_NOT_PHONE = 10069; // 用户名不是手机号码
int PHONE_ALREADY_REGISTERED = 10070; // 手机号码已注册
int PHONE_NOT_REGISTERED = 10071; // 手机号码未注册
int USER_REGISTER_DISABLED = 10072; // 不允许用户注册
int RETRIEVE_PASSWORD_DISABLED = 10073; // 未开启找回密码功能
int PHONE_FORMAT_ERROR = 10074; // 手机号码格式不正确
int SMS_CODE_ERROR = 10075; // 手机验证码错误
// 字典类型相关错误码
int DICT_TYPE_NOT_EXIST = 10076; // 字典类型不存在
int DICT_TYPE_DUPLICATE = 10077; // 字典类型编码重复
// 资源处理相关错误码
int RESOURCE_READ_ERROR = 10078; // 读取资源失败
// 智能体相关错误码
int LLM_INTENT_PARAMS_MISMATCH = 10079; // LLM大模型和Intent意图识别,选择参数不匹配
// 声纹相关错误码
int VOICEPRINT_ALREADY_REGISTERED = 10080; // 此声音声纹已经注册
int VOICEPRINT_DELETE_ERROR = 10081; // 删除声纹出现错误
int VOICEPRINT_UPDATE_NOT_ALLOWED = 10082; // 声纹修改不允许,声音已注册
int VOICEPRINT_UPDATE_ADMIN_ERROR = 10083; // 修改声纹错误,请联系管理员
int VOICEPRINT_API_URI_ERROR = 10084; // 声纹接口地址错误
int VOICEPRINT_AUDIO_NOT_BELONG_AGENT = 10085; // 音频数据不属于智能体
int VOICEPRINT_AUDIO_EMPTY = 10086; // 音频数据为空
int VOICEPRINT_REGISTER_REQUEST_ERROR = 10087; // 声纹保存请求失败
int VOICEPRINT_REGISTER_PROCESS_ERROR = 10088; // 声纹保存处理失败
int VOICEPRINT_UNREGISTER_REQUEST_ERROR = 10089; // 声纹注销请求失败
int VOICEPRINT_UNREGISTER_PROCESS_ERROR = 10090; // 声纹注销处理失败
int VOICEPRINT_IDENTIFY_REQUEST_ERROR = 10091; // 声纹识别请求失败
// 服务端管理相关错误码
int INVALID_SERVER_ACTION = 10095; // 无效服务端操作
int SERVER_WEBSOCKET_NOT_CONFIGURED = 10096; // 未配置服务端WebSocket地址
int TARGET_WEBSOCKET_NOT_EXIST = 10097; // 目标WebSocket地址不存在
// 参数验证相关错误码
int WEBSOCKET_URLS_EMPTY = 10098; // WebSocket地址列表不能为空
int WEBSOCKET_URL_LOCALHOST = 10099; // WebSocket地址不能使用localhost或127.0.0.1
int WEBSOCKET_URL_FORMAT_ERROR = 10100; // WebSocket地址格式不正确
int WEBSOCKET_CONNECTION_FAILED = 10101; // WebSocket连接测试失败
int OTA_URL_EMPTY = 10102; // OTA地址不能为空
int OTA_URL_LOCALHOST = 10103; // OTA地址不能使用localhost或127.0.0.1
int OTA_URL_PROTOCOL_ERROR = 10104; // OTA地址必须以http或https开头
int OTA_URL_FORMAT_ERROR = 10105; // OTA地址必须以/ota/结尾
int OTA_INTERFACE_ACCESS_FAILED = 10106; // OTA接口访问失败
int OTA_INTERFACE_FORMAT_ERROR = 10107; // OTA接口返回内容格式不正确
int OTA_INTERFACE_VALIDATION_FAILED = 10108; // OTA接口验证失败
int MCP_URL_EMPTY = 10109; // MCP地址不能为空
int MCP_URL_LOCALHOST = 10110; // MCP地址不能使用localhost或127.0.0.1
int MCP_URL_INVALID = 10111; // 不是正确的MCP地址
int MCP_INTERFACE_ACCESS_FAILED = 10112; // MCP接口访问失败
int MCP_INTERFACE_FORMAT_ERROR = 10113; // MCP接口返回内容格式不正确
int MCP_INTERFACE_VALIDATION_FAILED = 10114; // MCP接口验证失败
int VOICEPRINT_URL_EMPTY = 10115; // 声纹接口地址不能为空
int VOICEPRINT_URL_LOCALHOST = 10116; // 声纹接口地址不能使用localhost或127.0.0.1
int VOICEPRINT_URL_INVALID = 10117; // 不是正确的声纹接口地址
int VOICEPRINT_URL_PROTOCOL_ERROR = 10118; // 声纹接口地址必须以http或https开头
int VOICEPRINT_INTERFACE_ACCESS_FAILED = 10119; // 声纹接口访问失败
int VOICEPRINT_INTERFACE_FORMAT_ERROR = 10120; // 声纹接口返回内容格式不正确
int VOICEPRINT_INTERFACE_VALIDATION_FAILED = 10121; // 声纹接口验证失败
int MQTT_SECRET_EMPTY = 10122; // mqtt密钥不能为空
int MQTT_SECRET_LENGTH_INSECURE = 10123; // mqtt密钥长度不安全
int MQTT_SECRET_CHARACTER_INSECURE = 10124; // mqtt密钥必须同时包含大小写字母
int MQTT_SECRET_WEAK_PASSWORD = 10125; // mqtt密钥包含弱密码
// 字典相关错误码
int DICT_LABEL_DUPLICATE = 10128; // 字典标签重复
}
@@ -13,6 +13,7 @@ import org.springframework.web.servlet.resource.NoResourceFoundException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import xiaozhi.common.utils.MessageUtils;
import xiaozhi.common.utils.Result;
/**
@@ -62,7 +63,7 @@ public class RenExceptionHandler {
@ExceptionHandler(NoResourceFoundException.class)
public Result<Void> handleNoResourceFoundException(NoResourceFoundException ex) {
log.warn("Resource not found: {}", ex.getMessage());
return new Result<Void>().error(404, "资源不存在");
return new Result<Void>().error(404, MessageUtils.getMessage(ErrorCode.RESOURCE_NOT_FOUND));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@@ -76,7 +77,7 @@ public class RenExceptionHandler {
})
.filter(Objects::nonNull)
.findFirst()
.orElse("请求参数错误!");
.orElse(MessageUtils.getMessage(ErrorCode.PARAM_VALUE_NULL));
return new Result<Void>().error(ErrorCode.PARAM_VALUE_NULL, errorMsg);
}
@@ -6,6 +6,7 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.exception.ErrorCode;
import java.io.BufferedReader;
@@ -37,7 +38,7 @@ public class ResourcesUtils {
}
} catch (IOException e){
log.error("方法:loadString()读取资源失败--{}",e.getMessage());
throw new RenException("读取资源失败");
throw new RenException(ErrorCode.RESOURCE_READ_ERROR);
}
return luaScriptBuilder.toString();
}
@@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.agent.dto.AgentVoicePrintSaveDTO;
@@ -42,7 +43,7 @@ public class AgentVoicePrintController {
if (b) {
return new Result<>();
}
return new Result<Void>().error("智能体的声纹创建失败");
return new Result<Void>().error(ErrorCode.AGENT_VOICEPRINT_CREATE_FAILED);
}
@PutMapping
@@ -54,7 +55,7 @@ public class AgentVoicePrintController {
if (b) {
return new Result<>();
}
return new Result<Void>().error("智能体的对应声纹更新失败");
return new Result<Void>().error(ErrorCode.AGENT_VOICEPRINT_UPDATE_FAILED);
}
@DeleteMapping("/{id}")
@@ -67,7 +68,7 @@ public class AgentVoicePrintController {
if (delete) {
return new Result<>();
}
return new Result<Void>().error("智能体的对应声纹删除失败");
return new Result<Void>().error(ErrorCode.AGENT_VOICEPRINT_DELETE_FAILED);
}
@GetMapping("/list/{id}")
@@ -76,7 +77,7 @@ public class AgentVoicePrintController {
public Result<List<AgentVoicePrintVO>> list(@PathVariable String id) {
String voiceprintUrl = sysParamsService.getValue("server.voice_print", true);
if (StringUtils.isBlank(voiceprintUrl) || "null".equals(voiceprintUrl)) {
throw new RenException("声纹接口未配置,请先在参数配置中配置声纹接口地址(server.voice_print)");
throw new RenException(ErrorCode.VOICEPRINT_API_NOT_CONFIGURED);
}
Long userId = SecurityUser.getUserId();
List<AgentVoicePrintVO> list = agentVoicePrintService.list(userId, id);
@@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.page.PageData;
import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
@@ -74,7 +75,7 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
AgentInfoVO agent = agentDao.selectAgentInfoById(id);
if (agent == null) {
throw new RenException("智能体不存在");
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
}
if (agent.getMemModelId() != null && agent.getMemModelId().equals(Constant.MEMORY_NO_MEM)) {
@@ -204,7 +205,7 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
// 先查询现有实体
AgentEntity existingEntity = this.getAgentById(agentId);
if (existingEntity == null) {
throw new RuntimeException("智能体不存在");
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
}
// 只更新提供的非空字段
@@ -328,7 +329,7 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
boolean b = validateLLMIntentParams(dto.getLlmModelId(), dto.getIntentModelId());
if (!b) {
throw new RenException("LLM大模型和Intent意图识别,选择参数不匹配");
throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH);
}
this.updateById(existingEntity);
}
@@ -26,6 +26,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.common.utils.JsonUtils;
@@ -78,7 +79,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
// 根据识别出的声纹ID查询对应的用户信息
AgentVoicePrintEntity existingVoicePrint = baseMapper.selectById(response.getSpeakerId());
String existingUserName = existingVoicePrint != null ? existingVoicePrint.getSourceName() : "未知用户";
throw new RenException("此声音声纹对应的人(" + existingUserName + ")已经注册,请选择其他声音注册");
throw new RenException(ErrorCode.VOICEPRINT_ALREADY_REGISTERED, existingUserName);
}
AgentVoicePrintEntity entity = ConvertUtils.sourceToTarget(dto, AgentVoicePrintEntity.class);
// 开启事务
@@ -100,7 +101,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
} catch (Exception e) {
status.setRollbackOnly(); // 标记事务回滚
log.error("保存声纹错误原因:{}", e.getMessage());
throw new RenException("保存声纹错误,请联系管理员");
throw new RenException(ErrorCode.VOICE_PRINT_SAVE_ERROR);
}
}));
}
@@ -123,7 +124,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
} catch (Exception e) {
status.setRollbackOnly(); // 标记事务回滚
log.error("删除声纹存在错误原因:{}", e.getMessage());
throw new RenException("删除声纹出现了错误");
throw new RenException(ErrorCode.VOICEPRINT_DELETE_ERROR);
}
}));
// 数据库声纹数据删除成功才继续执行删除声纹服务的数据
@@ -179,7 +180,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
// 根据识别出的声纹ID查询对应的用户信息
AgentVoicePrintEntity existingVoicePrint = baseMapper.selectById(response.getSpeakerId());
String existingUserName = existingVoicePrint != null ? existingVoicePrint.getSourceName() : "未知用户";
throw new RenException("此次修改不允许,此声音已经注册为声纹了(" + existingUserName + "");
throw new RenException(ErrorCode.VOICEPRINT_UPDATE_NOT_ALLOWED, existingUserName);
}
}
} else {
@@ -208,7 +209,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
} catch (Exception e) {
status.setRollbackOnly(); // 标记事务回滚
log.error("修改声纹错误原因:{}", e.getMessage());
throw new RenException("修改声纹错误,请联系管理员");
throw new RenException(ErrorCode.VOICEPRINT_UPDATE_ADMIN_ERROR);
}
}));
}
@@ -225,7 +226,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
return new URI(voicePrint);
} catch (URISyntaxException e) {
log.error("路径格式不正确路径:{}\n错误信息:{}", voicePrint, e.getMessage());
throw new RuntimeException("声纹接口的地址存在错误,请进入参数管理修改声纹接口地址");
throw new RenException(ErrorCode.VOICEPRINT_API_URI_ERROR);
}
}
@@ -270,13 +271,13 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
// 判断这个音频是否属于当前智能体
boolean b = agentChatHistoryService.isAudioOwnedByAgent(audioId, agentId);
if (!b) {
throw new RenException("音频数据不属于这个智能体");
throw new RenException(ErrorCode.VOICEPRINT_AUDIO_NOT_BELONG_AGENT);
}
// 获取到音频数据
byte[] audio = agentChatAudioService.getAudio(audioId);
// 如果音频数据为空的直接报错不进行下去
if (audio == null || audio.length == 0) {
throw new RenException("音频数据是空的请检查上传数据");
throw new RenException(ErrorCode.VOICEPRINT_AUDIO_EMPTY);
}
// 将字节数组包装为资源,返回
return new ByteArrayResource(audio) {
@@ -314,13 +315,13 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
if (response.getStatusCode() != HttpStatus.OK) {
log.error("声纹注册失败,请求路径:{}", requestUrl);
throw new RenException("声纹保存失败,请求不成功");
throw new RenException(ErrorCode.VOICEPRINT_REGISTER_REQUEST_ERROR);
}
// 检查响应内容
String responseBody = response.getBody();
if (responseBody == null || !responseBody.contains("true")) {
log.error("声纹注册失败,请求处理失败内容:{}", responseBody == null ? "空内容" : responseBody);
throw new RenException("声纹保存失败,请求处理失败");
throw new RenException(ErrorCode.VOICEPRINT_REGISTER_PROCESS_ERROR);
}
}
@@ -344,13 +345,13 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
String.class);
if (response.getStatusCode() != HttpStatus.OK) {
log.error("声纹注销失败,请求路径:{}", requestUrl);
throw new RenException("声纹注销失败,请求不成功");
throw new RenException(ErrorCode.VOICEPRINT_UNREGISTER_REQUEST_ERROR);
}
// 检查响应内容
String responseBody = response.getBody();
if (responseBody == null || !responseBody.contains("true")) {
log.error("声纹注销失败,请求处理失败内容:{}", responseBody == null ? "空内容" : responseBody);
throw new RenException("声纹注销失败,请求处理失败");
throw new RenException(ErrorCode.VOICEPRINT_UNREGISTER_PROCESS_ERROR);
}
}
@@ -398,7 +399,7 @@ public class AgentVoicePrintServiceImpl extends ServiceImpl<AgentVoicePrintDao,
if (response.getStatusCode() != HttpStatus.OK) {
log.error("声纹识别请求失败,请求路径:{}", requestUrl);
throw new RenException("声纹识别失败,请求不成功");
throw new RenException(ErrorCode.VOICEPRINT_IDENTIFY_REQUEST_ERROR);
}
// 检查响应内容
String responseBody = response.getBody();
@@ -70,7 +70,7 @@ public class ConfigServiceImpl implements ConfigService {
// 查询默认智能体
AgentTemplateEntity agent = agentTemplateService.getDefaultTemplate();
if (agent == null) {
throw new RenException("默认智能体未找到");
throw new RenException(ErrorCode.DEFAULT_AGENT_NOT_FOUND);
}
// 构建模块配置
@@ -113,7 +113,7 @@ public class ConfigServiceImpl implements ConfigService {
// 获取智能体信息
AgentEntity agent = agentService.getAgentById(device.getAgentId());
if (agent == null) {
throw new RenException("智能体未找到");
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
}
// 获取音色信息
String voice = null;
@@ -29,6 +29,7 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
import xiaozhi.common.redis.RedisKeys;
@@ -83,27 +84,27 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
@Override
public Boolean deviceActivation(String agentId, String activationCode) {
if (StringUtils.isBlank(activationCode)) {
throw new RenException("激活码不能为空");
throw new RenException(ErrorCode.ACTIVATION_CODE_EMPTY);
}
String deviceKey = "ota:activation:code:" + activationCode;
Object cacheDeviceId = redisUtils.get(deviceKey);
if (cacheDeviceId == null) {
throw new RenException("激活码错误");
throw new RenException(ErrorCode.ACTIVATION_CODE_ERROR);
}
String deviceId = (String) cacheDeviceId;
String safeDeviceId = deviceId.replace(":", "_").toLowerCase();
String cacheDeviceKey = String.format("ota:activation:data:%s", safeDeviceId);
Map<String, Object> cacheMap = (Map<String, Object>) redisUtils.get(cacheDeviceKey);
if (cacheMap == null) {
throw new RenException("激活码错误");
throw new RenException(ErrorCode.ACTIVATION_CODE_ERROR);
}
String cachedCode = (String) cacheMap.get("activation_code");
if (!activationCode.equals(cachedCode)) {
throw new RenException("激活码错误");
throw new RenException(ErrorCode.ACTIVATION_CODE_ERROR);
}
// 检查设备有没有被激活
if (selectById(deviceId) != null) {
throw new RenException("设备已激活");
throw new RenException(ErrorCode.DEVICE_ALREADY_ACTIVATED);
}
String macAddress = (String) cacheMap.get("mac_address");
@@ -111,7 +112,7 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
String appVersion = (String) cacheMap.get("app_version");
UserDetail user = SecurityUser.getUser();
if (user.getId() == null) {
throw new RenException("用户未登录");
throw new RenException(ErrorCode.USER_NOT_LOGIN);
}
Date currentTime = new Date();
@@ -441,7 +442,7 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
wrapper.eq("mac_address", dto.getMacAddress());
DeviceEntity exist = baseDao.selectOne(wrapper);
if (exist != null) {
throw new RenException("该Mac地址已存在");
throw new RenException(ErrorCode.MAC_ADDRESS_ALREADY_EXISTS);
}
Date now = new Date();
DeviceEntity entity = new DeviceEntity();
@@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
import xiaozhi.common.redis.RedisKeys;
@@ -94,7 +95,7 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
throw new RenException(ErrorCode.MODEL_PROVIDER_NOT_EXIST);
}
// 再保存供应器提供的模型
@@ -113,7 +114,7 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
throw new RenException(ErrorCode.MODEL_PROVIDER_NOT_EXIST);
}
if (modelConfigBodyDTO.getConfigJson().containsKey("llm")) {
String llm = modelConfigBodyDTO.getConfigJson().get("llm").toString();
@@ -122,12 +123,12 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
String selectModelType = (modelConfigEntity == null || modelConfigEntity.getModelType() == null) ? null
: modelConfigEntity.getModelType().toUpperCase();
if (modelConfigEntity == null || !"LLM".equals(selectModelType)) {
throw new RenException("设置的LLM不存在");
throw new RenException(ErrorCode.LLM_NOT_EXIST);
}
String type = modelConfigEntity.getConfigJson().get("type").toString();
// 如果查询大语言模型是openai或者ollama,意图识别选参数都可以
if (!"openai".equals(type) && !"ollama".equals(type)) {
throw new RenException("设置的LLM不是openai和ollama");
throw new RenException(ErrorCode.INVALID_LLM_TYPE);
}
}
@@ -146,7 +147,7 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
// 查看是否是默认
ModelConfigEntity modelConfig = modelConfigDao.selectById(id);
if (modelConfig != null && modelConfig.getIsDefault() == 1) {
throw new RenException("该模型为默认模型,请先设置其他模型为默认模型");
throw new RenException(ErrorCode.DEFAULT_MODEL_DELETE_ERROR);
}
// 验证是否有引用
checkAgentReference(id);
@@ -180,7 +181,7 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
String agentNames = agents.stream()
.map(AgentEntity::getAgentName)
.collect(Collectors.joining(""));
throw new RenException(String.format("该模型配置已被智能体[%s]引用,无法删除", agentNames));
throw new RenException(ErrorCode.MODEL_REFERENCED_BY_AGENT, agentNames);
}
}
@@ -198,7 +199,7 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
.eq("model_type", "Intent")
.like("config_json", "%" + modelId + "%"));
if (!intentConfigs.isEmpty()) {
throw new RenException("该LLM模型已被意图识别配置引用,无法删除");
throw new RenException(ErrorCode.LLM_REFERENCED_BY_INTENT);
}
}
}
@@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.hutool.json.JSONArray;
import lombok.AllArgsConstructor;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.impl.BaseServiceImpl;
@@ -109,7 +110,7 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
modelProviderDTO.setFields(modelProviderDTO.getFields());
ModelProviderEntity entity = ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class);
if (modelProviderDao.insert(entity) == 0) {
throw new RenException("新增数据失败");
throw new RenException(ErrorCode.ADD_DATA_FAILED);
}
return ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderDTO.class);
@@ -122,7 +123,7 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
modelProviderDTO.setUpdateDate(new Date());
if (modelProviderDao
.updateById(ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class)) == 0) {
throw new RenException("修改数据失败");
throw new RenException(ErrorCode.UPDATE_DATA_FAILED);
}
return ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderDTO.class);
}
@@ -130,14 +131,14 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
@Override
public void delete(String id) {
if (modelProviderDao.deleteById(id) == 0) {
throw new RenException("删除数据失败");
throw new RenException(ErrorCode.DELETE_DATA_FAILED);
}
}
@Override
public void delete(List<String> ids) {
if (modelProviderDao.deleteBatchIds(ids) == 0) {
throw new RenException("删除数据失败");
throw new RenException(ErrorCode.DELETE_DATA_FAILED);
}
}
@@ -2,8 +2,11 @@ package xiaozhi.modules.security.config;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
@@ -12,8 +15,10 @@ import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -95,5 +100,47 @@ public class WebMvcConfig implements WebMvcConfigurer {
converter.setObjectMapper(mapper);
return converter;
}
/**
* 国际化配置 - 根据请求头中的Accept-Language设置语言环境
*/
@Bean
public LocaleResolver localeResolver() {
return new AcceptHeaderLocaleResolver() {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String acceptLanguage = request.getHeader("Accept-Language");
if (acceptLanguage == null || acceptLanguage.isEmpty()) {
return Locale.getDefault();
}
// 解析Accept-Language请求头中的首选语言
String[] languages = acceptLanguage.split(",");
if (languages.length > 0) {
// 提取第一个语言代码,去除可能的质量值(q=...)
String[] parts = languages[0].split(";" + "\\s*");
String primaryLanguage = parts[0].trim();
// 根据前端发送的语言代码直接创建Locale对象
if (primaryLanguage.equals("zh-CN")) {
return Locale.SIMPLIFIED_CHINESE;
} else if (primaryLanguage.equals("zh-TW")) {
return Locale.TRADITIONAL_CHINESE;
} else if (primaryLanguage.equals("en-US")) {
return Locale.US;
} else if (primaryLanguage.startsWith("zh")) {
// 对于其他中文变体,默认使用简体中文
return Locale.SIMPLIFIED_CHINESE;
} else if (primaryLanguage.startsWith("en")) {
// 对于其他英文变体,默认使用美式英语
return Locale.US;
}
}
// 如果没有匹配的语言,使用默认语言
return Locale.getDefault();
}
};
}
}
@@ -68,12 +68,12 @@ public class LoginController {
// 验证图形验证码
boolean validate = captchaService.validate(dto.getCaptchaId(), dto.getCaptcha(), true);
if (!validate) {
throw new RenException("图形验证码错误");
throw new RenException(ErrorCode.SMS_CAPTCHA_ERROR);
}
Boolean isMobileRegister = sysParamsService
.getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class);
if (!isMobileRegister) {
throw new RenException("没有开启手机注册,没法使用短信验证码功能");
throw new RenException(ErrorCode.MOBILE_REGISTER_DISABLED);
}
// 发送短信验证码
captchaService.sendSMSValidateCode(dto.getPhone());
@@ -86,17 +86,17 @@ public class LoginController {
// 验证是否正确输入验证码
boolean validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha(), true);
if (!validate) {
throw new RenException("图形验证码错误,请重新获取");
throw new RenException(ErrorCode.SMS_CAPTCHA_ERROR);
}
// 按照用户名获取用户
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
// 判断用户是否存在
if (userDTO == null) {
throw new RenException("请检测用户和密码是否输入错误");
throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
}
// 判断密码是否正确,不一样则进入if
if (!PasswordUtils.matches(login.getPassword(), userDTO.getPassword())) {
throw new RenException("请检测用户和密码是否输入错误");
throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
}
return sysUserTokenService.createToken(userDTO.getId());
}
@@ -105,7 +105,7 @@ public class LoginController {
@Operation(summary = "注册")
public Result<Void> register(@RequestBody LoginDTO login) {
if (!sysUserService.getAllowUserRegister()) {
throw new RenException("当前不允许普通用户注册");
throw new RenException(ErrorCode.USER_REGISTER_DISABLED);
}
// 是否开启手机注册
Boolean isMobileRegister = sysParamsService
@@ -115,25 +115,25 @@ public class LoginController {
// 验证用户是否是手机号码
boolean validPhone = ValidatorUtils.isValidPhone(login.getUsername());
if (!validPhone) {
throw new RenException("用户名不是手机号码,请重新输入");
throw new RenException(ErrorCode.USERNAME_NOT_PHONE);
}
// 验证短信验证码是否正常
validate = captchaService.validateSMSValidateCode(login.getUsername(), login.getMobileCaptcha(), false);
if (!validate) {
throw new RenException("手机验证码错误,请重新获取");
throw new RenException(ErrorCode.SMS_CODE_ERROR);
}
} else {
// 验证是否正确输入验证码
validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha(), true);
if (!validate) {
throw new RenException("图形验证码错误,请重新获取");
throw new RenException(ErrorCode.SMS_CAPTCHA_ERROR);
}
}
// 按照用户名获取用户
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
if (userDTO != null) {
throw new RenException("此手机号码已经注册过");
throw new RenException(ErrorCode.PHONE_ALREADY_REGISTERED);
}
userDTO = new SysUserDTO();
userDTO.setUsername(login.getUsername());
@@ -168,26 +168,26 @@ public class LoginController {
Boolean isMobileRegister = sysParamsService
.getValueObject(Constant.SysMSMParam.SERVER_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class);
if (!isMobileRegister) {
throw new RenException("没有开启手机注册,没法使用找回密码功能");
throw new RenException(ErrorCode.RETRIEVE_PASSWORD_DISABLED);
}
// 判断非空
ValidatorUtils.validateEntity(dto);
// 验证用户是否是手机号码
boolean validPhone = ValidatorUtils.isValidPhone(dto.getPhone());
if (!validPhone) {
throw new RenException("输入的手机号码格式不正确");
throw new RenException(ErrorCode.PHONE_FORMAT_ERROR);
}
// 按照用户名获取用户
SysUserDTO userDTO = sysUserService.getByUsername(dto.getPhone());
if (userDTO == null) {
throw new RenException("输入的手机号码未注册");
throw new RenException(ErrorCode.PHONE_NOT_REGISTERED);
}
// 验证短信验证码是否正常
boolean validate = captchaService.validateSMSValidateCode(dto.getPhone(), dto.getCode(), false);
// 判断是否通过验证
if (!validate) {
throw new RenException("输入的手机验证码错误");
throw new RenException(ErrorCode.SMS_CODE_ERROR);
}
sysUserService.changePasswordDirectly(userDTO.getId(), dto.getPassword());
@@ -18,6 +18,7 @@ import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.utils.HttpContextUtils;
import xiaozhi.common.utils.JsonUtils;
import xiaozhi.common.utils.MessageUtils;
import xiaozhi.common.utils.Result;
/**
@@ -82,8 +83,8 @@ public class Oauth2Filter extends AuthenticatingFilter {
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
try {
Throwable throwable = e.getCause() == null ? e : e.getCause();
Result<Void> r = new Result<Void>().error(ErrorCode.UNAUTHORIZED, throwable.getMessage());
// 使用国际化消息替代直接使用异常消息
Result<Void> r = new Result<Void>().error(ErrorCode.UNAUTHORIZED);
String json = JsonUtils.toJsonString(r);
httpResponse.getWriter().print(json);
@@ -3,6 +3,7 @@ package xiaozhi.modules.security.oauth2;
import java.security.MessageDigest;
import java.util.UUID;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
/**
@@ -38,7 +39,7 @@ public class TokenGenerator {
byte[] messageDigest = algorithm.digest();
return toHexString(messageDigest);
} catch (Exception e) {
throw new RenException("token invalid", e);
throw new RenException(ErrorCode.TOKEN_GENERATE_ERROR, e);
}
}
}
@@ -16,6 +16,7 @@ import com.wf.captcha.base.Captcha;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
@@ -88,7 +89,7 @@ public class CaptchaServiceImpl implements CaptchaService {
long currentTime = System.currentTimeMillis();
long timeDiff = currentTime - lastSendTimeLong;
if (timeDiff < 60000) {
throw new RenException("发送太频繁,请" + (60000 - timeDiff) / 1000 + "秒后再试");
throw new RenException(ErrorCode.SMS_SEND_TOO_FREQUENTLY, String.valueOf((60000 - timeDiff) / 1000));
}
}
@@ -108,7 +109,7 @@ public class CaptchaServiceImpl implements CaptchaService {
}
if (todayCount >= maxSendCount) {
throw new RenException("今日发送次数已达上限");
throw new RenException(ErrorCode.TODAY_SMS_LIMIT_REACHED);
}
String key = RedisKeys.getSMSValidateCodeKey(phone);
@@ -9,6 +9,7 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
@@ -45,7 +46,7 @@ public class ALiYunSmsService implements SmsService {
redisUtils.delete(todayCountKey);
// 错误 message
log.error(e.getMessage());
throw new RenException("短信发送失败");
throw new RenException(ErrorCode.SMS_SEND_FAILED);
}
}
@@ -70,7 +71,7 @@ public class ALiYunSmsService implements SmsService {
}catch (Exception e){
// 错误 message
log.error(e.getMessage());
throw new RenException("短信连接建立失败");
throw new RenException(ErrorCode.SMS_CONNECTION_FAILED);
}
}
}
@@ -22,6 +22,7 @@ import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import xiaozhi.common.annotation.LogOperation;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.sys.dto.EmitSeverActionDTO;
@@ -64,17 +65,17 @@ public class ServerSideManageController {
@RequiresPermissions("sys:role:superAdmin")
public Result<Boolean> emitServerAction(@RequestBody @Valid EmitSeverActionDTO emitSeverActionDTO) {
if (emitSeverActionDTO.getAction() == null) {
throw new RenException("无效服务端操作");
throw new RenException(ErrorCode.INVALID_SERVER_ACTION);
}
String wsText = sysParamsService.getValue(Constant.SERVER_WEBSOCKET, true);
if (StringUtils.isBlank(wsText)) {
throw new RenException("未配置服务端WebSocket地址");
throw new RenException(ErrorCode.SERVER_WEBSOCKET_NOT_CONFIGURED);
}
String targetWs = emitSeverActionDTO.getTargetWs();
String[] wsList = wsText.split(";");
// 找到需要发起的
if (StringUtils.isBlank(targetWs) || !Arrays.asList(wsList).contains(targetWs)) {
throw new RenException("目标WebSocket地址不存在");
throw new RenException(ErrorCode.TARGET_WEBSOCKET_NOT_EXIST);
}
return new Result<Boolean>().ok(emitServerActionByWs(targetWs, emitSeverActionDTO.getAction()));
}
@@ -114,7 +115,7 @@ public class ServerSideManageController {
});
} catch (Exception e) {
// 捕获全部错误,由全局异常处理器返回
throw new RenException("WebSocket连接失败或连接超时");
throw new RenException(ErrorCode.WEB_SOCKET_CONNECT_FAILED);
}
return true;
}
@@ -25,6 +25,7 @@ import lombok.AllArgsConstructor;
import xiaozhi.common.annotation.LogOperation;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.page.PageData;
import xiaozhi.common.utils.Result;
import xiaozhi.common.validator.AssertUtils;
@@ -130,23 +131,23 @@ public class SysParamsController {
}
String[] wsUrls = urls.split("\\;");
if (wsUrls.length == 0) {
throw new RenException("WebSocket地址列表不能为空");
throw new RenException(ErrorCode.WEBSOCKET_URLS_EMPTY);
}
for (String url : wsUrls) {
if (StringUtils.isNotBlank(url)) {
// 检查是否包含localhost或127.0.0.1
if (url.contains("localhost") || url.contains("127.0.0.1")) {
throw new RenException("WebSocket地址不能使用localhost或127.0.0.1");
throw new RenException(ErrorCode.WEBSOCKET_URL_LOCALHOST);
}
// 验证WebSocket地址格式
if (!WebSocketValidator.validateUrlFormat(url)) {
throw new RenException("WebSocket地址格式不正确: " + url);
throw new RenException(ErrorCode.WEBSOCKET_URL_FORMAT_ERROR);
}
// 测试WebSocket连接
if (!WebSocketValidator.testConnection(url)) {
throw new RenException("WebSocket连接测试失败: " + url);
throw new RenException(ErrorCode.WEBSOCKET_CONNECTION_FAILED);
}
}
}
@@ -173,35 +174,35 @@ public class SysParamsController {
return;
}
if (StringUtils.isBlank(url) || url.equals("null")) {
throw new RenException("OTA地址不能为空");
throw new RenException(ErrorCode.OTA_URL_EMPTY);
}
// 检查是否包含localhost或127.0.0.1
if (url.contains("localhost") || url.contains("127.0.0.1")) {
throw new RenException("OTA地址不能使用localhost或127.0.0.1");
throw new RenException(ErrorCode.OTA_URL_LOCALHOST);
}
// 验证URL格式
if (!url.toLowerCase().startsWith("http")) {
throw new RenException("OTA地址必须以http或https开头");
throw new RenException(ErrorCode.OTA_URL_PROTOCOL_ERROR);
}
if (!url.endsWith("/ota/")) {
throw new RenException("OTA地址必须以/ota/结尾");
throw new RenException(ErrorCode.OTA_URL_FORMAT_ERROR);
}
try {
// 发送GET请求
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode() != HttpStatus.OK) {
throw new RenException("OTA接口访问失败,状态码:" + response.getStatusCode());
throw new RenException(ErrorCode.OTA_INTERFACE_ACCESS_FAILED);
}
// 检查响应内容是否包含OTA相关信息
String body = response.getBody();
if (body == null || !body.contains("OTA")) {
throw new RenException("OTA接口返回内容格式不正确,可能不是一个真实的OTA接口");
throw new RenException(ErrorCode.OTA_INTERFACE_FORMAT_ERROR);
}
} catch (Exception e) {
throw new RenException("OTA接口验证失败:" + e.getMessage());
throw new RenException(ErrorCode.OTA_INTERFACE_VALIDATION_FAILED);
}
}
@@ -210,28 +211,28 @@ public class SysParamsController {
return;
}
if (StringUtils.isBlank(url) || url.equals("null")) {
throw new RenException("MCP地址不能为空");
throw new RenException(ErrorCode.MCP_URL_EMPTY);
}
if (url.contains("localhost") || url.contains("127.0.0.1")) {
throw new RenException("MCP地址不能使用localhost或127.0.0.1");
throw new RenException(ErrorCode.MCP_URL_LOCALHOST);
}
if (!url.toLowerCase().contains("key")) {
throw new RenException("不是正确的MCP地址");
throw new RenException(ErrorCode.MCP_URL_INVALID);
}
try {
// 发送GET请求
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode() != HttpStatus.OK) {
throw new RenException("MCP接口访问失败,状态码:" + response.getStatusCode());
throw new RenException(ErrorCode.MCP_INTERFACE_ACCESS_FAILED);
}
// 检查响应内容是否包含mcp相关信息
String body = response.getBody();
if (body == null || !body.contains("success")) {
throw new RenException("MCP接口返回内容格式不正确,可能不是一个真实的MCP接口");
throw new RenException(ErrorCode.MCP_INTERFACE_FORMAT_ERROR);
}
} catch (Exception e) {
throw new RenException("MCP接口验证失败:" + e.getMessage());
throw new RenException(ErrorCode.MCP_INTERFACE_VALIDATION_FAILED);
}
}
@@ -241,31 +242,31 @@ public class SysParamsController {
return;
}
if (StringUtils.isBlank(url) || url.equals("null")) {
throw new RenException("声纹接口地址不能为空");
throw new RenException(ErrorCode.VOICEPRINT_URL_EMPTY);
}
if (url.contains("localhost") || url.contains("127.0.0.1")) {
throw new RenException("声纹接口地址不能使用localhost或127.0.0.1");
throw new RenException(ErrorCode.VOICEPRINT_URL_LOCALHOST);
}
if (!url.toLowerCase().contains("key")) {
throw new RenException("不是正确的声纹接口地址");
throw new RenException(ErrorCode.VOICEPRINT_URL_INVALID);
}
// 验证URL格式
if (!url.toLowerCase().startsWith("http")) {
throw new RenException("声纹接口地址必须以http或https开头");
throw new RenException(ErrorCode.VOICEPRINT_URL_PROTOCOL_ERROR);
}
try {
// 发送GET请求
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode() != HttpStatus.OK) {
throw new RenException("声纹接口访问失败,状态码:" + response.getStatusCode());
throw new RenException(ErrorCode.VOICEPRINT_INTERFACE_ACCESS_FAILED);
}
// 检查响应内容
String body = response.getBody();
if (body == null || !body.contains("healthy")) {
throw new RenException("声纹接口返回内容格式不正确,可能不是一个真实的MCP接口");
throw new RenException(ErrorCode.VOICEPRINT_INTERFACE_FORMAT_ERROR);
}
} catch (Exception e) {
throw new RenException("声纹接口验证失败:" + e.getMessage());
throw new RenException(ErrorCode.VOICEPRINT_INTERFACE_VALIDATION_FAILED);
}
}
@@ -275,20 +276,20 @@ public class SysParamsController {
return;
}
if (StringUtils.isBlank(secret) || secret.equals("null")) {
throw new RenException("mqtt密钥不能为空");
throw new RenException(ErrorCode.MQTT_SECRET_EMPTY);
}
if (secret.length() < 8) {
throw new RenException("您的mqtt密钥长度不安全,字符数需要至少8个字符且必须同时包含大小写字母");
throw new RenException(ErrorCode.MQTT_SECRET_LENGTH_INSECURE);
}
// 检查是否同时包含大小写字母
if (!secret.matches(".*[a-z].*") || !secret.matches(".*[A-Z].*")) {
throw new RenException("您的mqtt密钥长度不安全,mqtt密钥必须同时包含大小写字母");
throw new RenException(ErrorCode.MQTT_SECRET_CHARACTER_INSECURE);
}
// 不允许包含弱密码
String[] weakPasswords = { "test", "1234", "admin", "password", "qwerty", "xiaozhi" };
for (String weakPassword : weakPasswords) {
if (secret.toLowerCase().contains(weakPassword)) {
throw new RenException("您的mqtt密钥包含弱密码:" + weakPassword);
throw new RenException(ErrorCode.MQTT_SECRET_WEAK_PASSWORD);
}
}
}
@@ -17,6 +17,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.page.PageData;
import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
@@ -153,7 +154,7 @@ public class SysDictDataServiceImpl extends BaseServiceImpl<SysDictDataDao, SysD
}
boolean exists = baseDao.exists(queryWrapper);
if (exists) {
throw new RenException("字典标签重复");
throw new RenException(ErrorCode.DICT_LABEL_DUPLICATE);
}
}
@@ -18,6 +18,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
@@ -66,7 +67,7 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl<SysDictTypeDao, SysD
public SysDictTypeVO get(Long id) {
SysDictTypeEntity entity = baseDao.selectById(id);
if (entity == null) {
throw new RenException("字典类型不存在");
throw new RenException(ErrorCode.DICT_TYPE_NOT_EXIST);
}
return ConvertUtils.sourceToTarget(entity, SysDictTypeVO.class);
@@ -147,7 +148,7 @@ public class SysDictTypeServiceImpl extends BaseServiceImpl<SysDictTypeDao, SysD
}
boolean exists = baseDao.exists(queryWrapper);
if (exists) {
throw new RenException("字典类型编码重复");
throw new RenException(ErrorCode.DICT_TYPE_DUPLICATE);
}
}
}
@@ -115,7 +115,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
// 判断旧密码是否正确
if (!PasswordUtils.matches(passwordDTO.getPassword(), sysUserEntity.getPassword())) {
throw new RenException("旧密码输入错误");
throw new RenException(ErrorCode.OLD_PASSWORD_ERROR);
}
// 新密码强度
@@ -0,0 +1,54 @@
-- 添加阿里百炼流式TTS 供应器
delete from `ai_model_provider` where id = 'SYSTEM_TTS_AliBLStreamTTS';
INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES
('SYSTEM_TTS_AliBLStreamTTS', 'TTS', 'alibl_stream', '阿里百炼流式语音合成', '[{"key":"api_key","label":"API密钥","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"},{"key":"model","label":"模型","type":"string"},{"key":"voice","label":"音色","type":"string"},{"key":"format","label":"音频格式","type":"string"},{"key":"sample_rate","label":"采样率","type":"number"},{"key": "volume", "type": "number", "label": "音量"},{"key": "rate", "type": "number", "label": "语速"},{"key": "pitch", "type": "number", "label": "音调"}]', 19, 1, NOW(), 1, NOW());
-- 添加阿里百炼流式TTS模型配置
delete from `ai_model_config` where id = 'TTS_AliBLStreamTTS';
INSERT INTO `ai_model_config` VALUES ('TTS_AliBLStreamTTS', 'TTS', 'AliBLStreamTTS', '阿里百炼流式语音合成', 0, 1, '{\"type\": \"alibl_stream\", \"appkey\": \"\", \"output_dir\": \"tmp/\", \"model\": \"cosyvoice-v2\", \"voice\": \"longcheng_v2\", \"format\": \"pcm\", \"sample_rate\": 24000, \"volume\": 50, \"rate\": 1, \"pitch\": 1}', NULL, NULL, 22, NULL, NULL, NULL, NULL);
-- 更新阿里百炼流式TTS配置说明
UPDATE `ai_model_config` SET
`doc_link` = 'https://bailian.console.aliyun.com/?apiKey=1#/api-key',
`remark` = '阿里百炼流式TTS说明:
1. 访问 https://bailian.console.aliyun.com/?apiKey=1#/api-key 创建项目并获取appkey
2. 支持实时流式合成,具有较低的延迟
3. 支持多种音色设置和音频参数调整
4. 支持CosyVoice-V3大模型音色,价格实惠(0.4元/万字符)
5. 支持实时调节音量、语速、音调等参数
6. 如果需要使用CosyVoice-V3模型和一些限制类型的音色,需要联系阿里百炼客服申请
' WHERE `id` = 'TTS_AliBLStreamTTS';
-- 添加阿里百炼流式TTS音色
delete from `ai_tts_voice` where tts_model_id = 'TTS_AliBLStreamTTS';
-- 语音助手
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0001', 'TTS_AliBLStreamTTS', '龙小淳-知性积极女', 'longxiaochun_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0002', 'TTS_AliBLStreamTTS', '龙小夏-沉稳权威女', 'longxiaoxia_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL);
-- 直播带货
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0003', 'TTS_AliBLStreamTTS', '龙安燃-活泼质感女', 'longanran', '中文及中英文混合', NULL, NULL, NULL, NULL, 3, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0004', 'TTS_AliBLStreamTTS', '龙安宣-经典直播女', 'longanxuan', '中文及中英文混合', NULL, NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL);
-- 社交陪伴
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0005', 'TTS_AliBLStreamTTS', '龙寒-温暖痴情男', 'longhan_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 5, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0006', 'TTS_AliBLStreamTTS', '龙颜-温暖春风女', 'longyan_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 6, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0007', 'TTS_AliBLStreamTTS', '龙菲菲-甜美矫情女', 'longfeifei_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 7, NULL, NULL, NULL, NULL);
-- 方言
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0008', 'TTS_AliBLStreamTTS', '龙老铁-东北直率男', 'longlaotie_v2', '中文(东北)及中英文混合', NULL, NULL, NULL, NULL, 8, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0009', 'TTS_AliBLStreamTTS', '龙嘉怡-知性粤语女', 'longjiayi_v2', '中文(粤语)及中英文混合', NULL, NULL, NULL, NULL, 9, NULL, NULL, NULL, NULL);
-- 童声
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0010', 'TTS_AliBLStreamTTS', '龙杰力豆-阳光顽皮男', 'longjielidou_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0011', 'TTS_AliBLStreamTTS', '龙铃-稚气呆板女', 'longling_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 11, NULL, NULL, NULL, NULL);
-- 诗歌朗诵
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0012', 'TTS_AliBLStreamTTS', '李白-古代诗仙男', 'libai_v2', '中文及中英文混合', NULL, NULL, NULL, NULL, 12, NULL, NULL, NULL, NULL);
-- 出海营销
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0013', 'TTS_AliBLStreamTTS', 'loongeva-知性英文女', 'loongeva_v2', '英式英文', NULL, NULL, NULL, NULL, 13, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0014', 'TTS_AliBLStreamTTS', 'loongbrian-沉稳英文男', 'loongbrian_v2', '英式英文', NULL, NULL, NULL, NULL, 14, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0015', 'TTS_AliBLStreamTTS', 'loongkyong-韩语女', 'loongkyong_v2', '韩语', NULL, NULL, NULL, NULL, 15, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0016', 'TTS_AliBLStreamTTS', 'loongtomoka-日语女', 'loongtomoka_v2', '日语', NULL, NULL, NULL, NULL, 16, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('TTS_AliBLStreamTTS_0017', 'TTS_AliBLStreamTTS', 'loongtomoya-日语男', 'loongtomoya_v2', '日语', NULL, NULL, NULL, NULL, 17, NULL, NULL, NULL, NULL);
@@ -351,4 +351,11 @@ databaseChangeLog:
changes:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202509161609.sql
path: classpath:db/changelog/202509161609.sql
- changeSet:
id: 202509161701
author: RanChen
changes:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202509161701.sql
@@ -1,47 +1,137 @@
#Default
500=\u670D\u52A1\u5668\u5185\u90E8\u5F02\u5E38
401=\u672A\u6388\u6743
403=\u62D2\u7EDD\u8BBF\u95EE\uFF0C\u6CA1\u6709\u6743\u9650
10001={0}\u4E0D\u80FD\u4E3A\u7A7A
10002=\u6570\u636E\u5E93\u4E2D\u5DF2\u5B58\u5728\u8BE5\u8BB0\u5F55
10003=\u83B7\u53D6\u53C2\u6570\u5931\u8D25
10004=\u8D26\u53F7\u6216\u5BC6\u7801\u9519\u8BEF
10005=\u8D26\u53F7\u5DF2\u88AB\u505C\u7528
10006=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
10007=\u9A8C\u8BC1\u7801\u4E0D\u6B63\u786E
10008=\u624B\u673A\u53F7\u7801\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
10009=\u539F\u5BC6\u7801\u4E0D\u6B63\u786E
10010=\u8D26\u53F7\u6216\u5BC6\u7801\u4E0D\u6B63\u786E,\u60A8\u8FD8\u6709\u53EF\u4EE5\u5C1D\u8BD5{0}\u6B21
10011=\u4E0A\u7EA7\u90E8\u95E8\u9009\u62E9\u9519\u8BEF
10012=\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u4E3A\u81EA\u8EAB
10013=\u6570\u636E\u6743\u9650\u63A5\u53E3\uFF0C\u53EA\u80FD\u662FMap\u7C7B\u578B\u53C2\u6570
10014=\u8BF7\u5148\u5220\u9664\u4E0B\u7EA7\u90E8\u95E8
10015=\u8BF7\u5148\u5220\u9664\u90E8\u95E8\u4E0B\u7684\u7528\u6237
10016=\u90E8\u7F72\u5931\u8D25\uFF0C\u6CA1\u6709\u6D41\u7A0B
10017=\u6A21\u578B\u56FE\u4E0D\u6B63\u786E\uFF0C\u8BF7\u68C0\u67E5
10018=\u5BFC\u51FA\u5931\u8D25\uFF0C\u6A21\u578BID\u4E3A{0}
10019=\u8BF7\u4E0A\u4F20\u6587\u4EF6
10020=token\u4E0D\u80FD\u4E3A\u7A7A
10021=token\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
10022=\u8D26\u53F7\u5DF2\u88AB\u9501\u5B9A
10023=\u8BF7\u4E0A\u4F20zip\u3001bar\u3001bpmn\u3001bpmn20.xml\u683C\u5F0F\u6587\u4EF6
10024=\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25{0}
10025=\u53D1\u9001\u77ED\u4FE1\u5931\u8D25{0}
10026=\u90AE\u4EF6\u6A21\u677F\u4E0D\u5B58\u5728
10027=Redis\u670D\u52A1\u5F02\u5E38
10028=\u5B9A\u65F6\u4EFB\u52A1\u5931\u8D25
10029=\u4E0D\u80FD\u5305\u542B\u975E\u6CD5\u5B57\u7B26
10030=\u5BC6\u7801\u957F\u5EA6\u4E0D\u8DB3{0}\u4F4D
10031=\u5F31\u5BC6\u7801
10032=\u5220\u9664\u672C\u6570\u636E\u5F02\u5E38
10033=\u8BBE\u5907\u9A8C\u8BC1\u7801\u9519\u8BEF
10034=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
10035=\u53C2\u6570\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
10036=\u4E0D\u652F\u6301\u7684\u53C2\u6570\u7C7B\u578B
10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57
10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false
10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F
10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
#简体中文
500=服务器内部异常
401=未授权
403=拒绝访问,没有权限
10041=\u8BBE\u5907\u672A\u627E\u5230
10001={0}不能为空
10002=数据库中已存在该记录
10003=获取参数失败
10004=账号或密码错误
10005=账号已被停用
10006=唯一标识不能为空
10007=验证码不正确
10008=先删除子菜单或按钮
10009=原密码不正确
10010=账号或密码不正确,您还有可以尝试{0}次
10011=上级部门选择错误
10012=上级菜单不能为自身
10013=数据权限接口,只能是Map类型参数
10014=请先删除下级部门
10015=请先删除部门下的用户
10016=部署失败,没有流程
10017=模型图不正确,请检查
10018=导出失败,模型ID为{0}
10019=请上传文件
10020=token不能为空
10021=token失效,请重新登录
10022=账号已被锁定
10023=请上传zip、bar、bpmn、bpmn20.xml格式文件
10024=上传文件失败{0}
10025=发送短信失败{0}
10026=邮件模板不存在
10027=Redis服务异常
10028=定时任务失败
10029=不能包含非法字符
10030=密码长度不足{0}位
10031=密码必须同时包含数字、大小写字母和特殊字符组成
10032=删除本数据异常
10033=设备验证码错误
10034=参数值不能为空
10035=参数类型不能为空
10036=不支持的参数类型
10037=参数值必须是有效的数字
10038=参数值必须是true或false
10039=参数值必须是有效的JSON数组格式
10040=参数值必须是有效的JSON格式
10041=设备未找到
10042={0}
10043=删除数据失败
10044=用户未登录
10045=WebSocket连接失败或连接超时
10046=保存声纹错误,请联系管理员
10047=每日发送次数已达上限
10048=旧密码输入错误
10049=设置的LLM不是openai和ollama
10050=token生成失败
10051=资源不存在
10052=默认智能体未找到
10053=智能体未找到
10054=声纹接口未配置,请先在参数配置中配置声纹接口地址(server.voice_print)
10055=短信发送失败
10056=短信连接建立失败
10057=智能体的声纹创建失败
10058=智能体的对应声纹更新失败
10059=智能体的对应声纹删除失败
10060=发送太频繁,请{0}秒后再试
10061=激活码不能为空
10062=激活码错误
10063=设备已激活
10064=该模型为默认模型,请先设置其他模型为默认模型
10065=新增数据失败
10066=修改数据失败
10067=图形验证码错误
10068=没有开启手机注册,没法使用短信验证码功能
10069=用户名不是手机号码,请重新输入
10070=此手机号码已经注册过
10071=输入的手机号码未注册
10072=当前不允许普通用户注册
10073=没有开启手机注册,没法使用找回密码功能
10074=输入的手机号码格式不正确
10075=输入的手机验证码错误
10076=字典类型不存在
10077=字典类型编码重复
10078=读取资源失败
10079=LLM大模型和Intent意图识别,选择参数不匹配
10080=此声音声纹对应的人({0})已经注册,请选择其他声音注册
10081=删除声纹出现错误
10082=此次修改不允许,此声音已经注册为声纹了({0})
10083=修改声纹错误,请联系管理员
10084=声纹接口地址存在错误,请进入参数管理修改声纹接口地址
10085=音频数据不属于这个智能体
10086=音频数据是空的请检查上传数据
10087=声纹保存失败,请求不成功
10088=声纹保存失败,请求处理失败
10089=声纹注销失败,请求不成功
10090=声纹注销失败,请求处理失败
10091=供应器不存在
10092=设置的LLM不存在
10093=该模型配置已被智能体{0}引用,无法删除
10094=该LLM模型已被意图识别配置引用,无法删除
10095=无效服务端操作
10096=未配置服务端WebSocket地址
10097=目标WebSocket地址不存在
10098=WebSocket地址列表不能为空
10099=WebSocket地址不能使用localhost或127.0.0.1
10100=WebSocket地址格式不正确
10101=WebSocket连接测试失败
10102=OTA地址不能为空
10103=OTA地址不能使用localhost或127.0.0.1
10104=OTA地址必须以http或https开头
10105=OTA地址必须以/ota/结尾
10106=OTA接口访问失败
10107=OTA接口返回内容格式不正确
10108=OTA接口验证失败
10109=MCP地址不能为空
10110=MCP地址不能使用localhost或127.0.0.1
10111=不是正确的MCP地址
10112=MCP接口访问失败
10113=MCP接口返回内容格式不正确
10114=MCP接口验证失败
10115=声纹接口地址不能为空
10116=声纹接口地址不能使用localhost或127.0.0.1
10117=不是正确的声纹接口地址
10118=声纹接口地址必须以http或https开头
10119=声纹接口访问失败
10120=声纹接口返回内容格式不正确
10121=声纹接口验证失败
10122=mqtt密钥不能为空
10123=您的mqtt密钥长度不安全,字符数需要至少8个字符且必须同时包含大小写字母
10124=您的mqtt密钥长度不安全,mqtt密钥必须同时包含大小写字母
10125=您的mqtt密钥包含弱密码
10128=字典标签重复
@@ -11,19 +11,26 @@
10007=The verification code is incorrect
10008=First delete submenu or button
10009=The original password is incorrect
10010=The account or password is incorrect, you can try {0} more times
10011=The superior department made a wrong choice
10012=Upper menu cannot be for itself
10013=Data permission interface, which can only be a Map type parameter.
10014=Please delete the subordinate department first
10015=Please delete the user under the department first
10016=Deployment failed, no process
10017=The model diagram is incorrect, please check
10018=Export failed, model ID is {0}
10019=Please upload a file
10020=token cannot be empty
10021=token is invalid, please log in again
10022=The account has been locked
10023=Please upload files in zip, bar, bpmn, bpmn20.xml format
10024=Failed to upload file {0}
10025=Failed to send SMS {0}
10026=Email template does not exist
10027=Redis service exception
10028=Timed task failed
@@ -43,4 +50,88 @@
10040=Parameter value must be a valid JSON format
10041=Device not found
10042={0}
10042={0}
10043=Failed to delete data
10044=User not logged in
10045=WebSocket connection failed or timeout
10046=Failed to save voiceprint, please contact administrator
10047=Daily sending limit reached
10048=Old password is incorrect
10049=The set LLM is not openai or ollama
10050=Failed to generate token
10051=Resource not found
10052=Default agent not found
10053=Agent not found
10054=Voiceprint interface not configured, please configure voiceprint interface address (server.voice_print) in parameter configuration first
10055=Failed to send SMS
10056=Failed to establish SMS connection
10057=Failed to create voiceprint for agent
10058=Failed to update voiceprint for agent
10059=Failed to delete voiceprint for agent
10060=Sending too frequently, please try again after {0} seconds
10061=Activation code cannot be empty
10062=Activation code error
10063=Device already activated
10064=This model is the default model, please set another model as default first
10065=Failed to add data
10066=Failed to update data
10067=Graphic verification code error
10068=Mobile registration is not enabled, SMS verification code function cannot be used
10069=Username is not a mobile phone number, please re-enter
10070=This mobile phone number has already been registered
10071=The entered mobile phone number is not registered
10072=Ordinary user registration is not allowed currently
10073=Mobile registration is not enabled, password retrieval function cannot be used
10074=The entered mobile phone number format is incorrect
10075=The entered SMS verification code is incorrect
10076=Dictionary type does not exist
10077=Dictionary type code is duplicated
10078=Failed to read resource
10079=LLM model and Intent recognition, parameter selection does not match
10080=This voiceprint belongs to {0} who has already registered, please select another voice
10081=Error occurred while deleting voiceprint
10082=Modification not allowed, this voice has already been registered as a voiceprint ({0})
10083=Error modifying voiceprint, please contact administrator
10084=Voiceprint interface address error, please go to parameter management to modify the voiceprint interface address
10085=Audio data does not belong to this agent
10086=Audio data is empty, please check uploaded data
10087=Voiceprint registration failed, request unsuccessful
10088=Voiceprint registration failed, request processing failed
10089=Voiceprint cancellation failed, request unsuccessful
10090=Voiceprint cancellation failed, request processing failed
10091=Model provider does not exist
10092=The configured LLM does not exist
10093=This model configuration is referenced by agent {0} and cannot be deleted
10094=This LLM model is referenced by intent recognition configuration and cannot be deleted
10095=Invalid server operation
10096=Server WebSocket address not configured
10097=Target WebSocket address does not exist
10098=WebSocket address list cannot be empty
10099=WebSocket address cannot use localhost or 127.0.0.1
10100=WebSocket address format is incorrect
10101=WebSocket connection test failed
10102=OTA address cannot be empty
10103=OTA address cannot use localhost or 127.0.0.1
10104=OTA address must start with http or https
10105=OTA address must end with /ota/
10106=OTA interface access failed
10107=OTA interface return content format is incorrect
10108=OTA interface validation failed
10109=MCP address cannot be empty
10110=MCP address cannot use localhost or 127.0.0.1
10111=Not a valid MCP address
10112=MCP interface access failed
10113=MCP interface return content format is incorrect
10114=MCP interface validation failed
10115=Voiceprint interface address cannot be empty
10116=Voiceprint interface address cannot use localhost or 127.0.0.1
10117=Not a valid voiceprint interface address
10118=Voiceprint interface address must start with http or https
10119=Voiceprint interface access failed
10120=Voiceprint interface return content format is incorrect
10121=Voiceprint interface validation failed
10122=MQTT secret cannot be empty
10123=Your MQTT secret is not secure, it needs to be at least 8 characters and must contain both uppercase and lowercase letters
10124=Your MQTT secret is not secure, MQTT secret must contain both uppercase and lowercase letters
10125=Your MQTT secret contains weak password
10128=Dictionary label is duplicated
@@ -1,46 +1,137 @@
#\u7B80\u4F53\u4E2D\u6587
500=\u670D\u52A1\u5668\u5185\u90E8\u5F02\u5E38
401=\u672A\u6388\u6743
403=\u62D2\u7EDD\u8BBF\u95EE\uFF0C\u6CA1\u6709\u6743\u9650
#简体中文
500=服务器内部异常
401=未授权
403=拒绝访问,没有权限
10001={0}\u4E0D\u80FD\u4E3A\u7A7A
10002=\u6570\u636E\u5E93\u4E2D\u5DF2\u5B58\u5728\u8BE5\u8BB0\u5F55
10003=\u83B7\u53D6\u53C2\u6570\u5931\u8D25
10004=\u8D26\u53F7\u6216\u5BC6\u7801\u9519\u8BEF
10005=\u8D26\u53F7\u5DF2\u88AB\u505C\u7528
10006=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
10007=\u9A8C\u8BC1\u7801\u4E0D\u6B63\u786E
10008=\u5148\u5220\u9664\u5B50\u83DC\u5355\u6216\u6309\u94AE
10009=\u539F\u5BC6\u7801\u4E0D\u6B63\u786E
10001={0}不能为空
10002=数据库中已存在该记录
10003=获取参数失败
10004=账号或密码错误
10005=账号已被停用
10006=唯一标识不能为空
10007=验证码不正确
10008=先删除子菜单或按钮
10009=原密码不正确
10010=账号或密码不正确,您还有可以尝试{0}次
10011=\u4E0A\u7EA7\u90E8\u95E8\u9009\u62E9\u9519\u8BEF
10012=\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u4E3A\u81EA\u8EAB
10013=\u6570\u636E\u6743\u9650\u63A5\u53E3\uFF0C\u53EA\u80FD\u662FMap\u7C7B\u578B\u53C2\u6570
10014=\u8BF7\u5148\u5220\u9664\u4E0B\u7EA7\u90E8\u95E8
10015=\u8BF7\u5148\u5220\u9664\u90E8\u95E8\u4E0B\u7684\u7528\u6237
10011=上级部门选择错误
10012=上级菜单不能为自身
10013=数据权限接口,只能是Map类型参数
10014=请先删除下级部门
10015=请先删除部门下的用户
10016=部署失败,没有流程
10017=模型图不正确,请检查
10018=导出失败,模型ID为{0}
10019=\u8BF7\u4E0A\u4F20\u6587\u4EF6
10020=token\u4E0D\u80FD\u4E3A\u7A7A
10021=token\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
10022=\u8D26\u53F7\u5DF2\u88AB\u9501\u5B9A
10019=请上传文件
10020=token不能为空
10021=token失效,请重新登录
10022=账号已被锁定
10023=请上传zip、bar、bpmn、bpmn20.xml格式文件
10024=\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25{0}
10024=上传文件失败{0}
10025=发送短信失败{0}
10026=邮件模板不存在
10027=Redis\u670D\u52A1\u5F02\u5E38
10028=\u5B9A\u65F6\u4EFB\u52A1\u5931\u8D25
10029=\u4E0D\u80FD\u5305\u542B\u975E\u6CD5\u5B57\u7B26
10030=\u5BC6\u7801\u957F\u5EA6\u4E0D\u8DB3{0}\u4F4D
10031=\u5BC6\u7801\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6570\u5B57\u3001\u5927\u5C0F\u5B57\u6BCD\u548C\u7279\u6B8A\u5B57\u7B26\u7EC4\u6210
10032=\u5220\u9664\u672C\u6570\u636E\u5F02\u5E38
10033=\u8BBE\u5907\u9A8C\u8BC1\u7801\u9519\u8BEF
10027=Redis服务异常
10028=定时任务失败
10029=不能包含非法字符
10030=密码长度不足{0}位
10031=密码必须同时包含数字、大小写字母和特殊字符组成
10032=删除本数据异常
10033=设备验证码错误
10034=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
10035=\u53C2\u6570\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
10036=\u4E0D\u652F\u6301\u7684\u53C2\u6570\u7C7B\u578B
10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57
10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false
10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F
10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
10034=参数值不能为空
10035=参数类型不能为空
10036=不支持的参数类型
10037=参数值必须是有效的数字
10038=参数值必须是true或false
10039=参数值必须是有效的JSON数组格式
10040=参数值必须是有效的JSON格式
10041=\u8BBE\u5907\u672A\u627E\u5230
10042={0}
10041=设备未找到
10042={0}
10043=删除数据失败
10044=用户未登录
10045=WebSocket连接失败或连接超时
10046=保存声纹错误,请联系管理员
10047=每日发送次数已达上限
10048=旧密码输入错误
10049=设置的LLM不是openai和ollama
10050=token生成失败
10051=资源不存在
10052=默认智能体未找到
10053=智能体未找到
10054=声纹接口未配置,请先在参数配置中配置声纹接口地址(server.voice_print)
10055=短信发送失败
10056=短信连接建立失败
10057=智能体的声纹创建失败
10058=智能体的对应声纹更新失败
10059=智能体的对应声纹删除失败
10060=发送太频繁,请{0}秒后再试
10061=激活码不能为空
10062=激活码错误
10063=设备已激活
10064=该模型为默认模型,请先设置其他模型为默认模型
10065=新增数据失败
10066=修改数据失败
10067=图形验证码错误
10068=没有开启手机注册,没法使用短信验证码功能
10069=用户名不是手机号码,请重新输入
10070=此手机号码已经注册过
10071=输入的手机号码未注册
10072=当前不允许普通用户注册
10073=没有开启手机注册,没法使用找回密码功能
10074=输入的手机号码格式不正确
10075=输入的手机验证码错误
10076=字典类型不存在
10077=字典类型编码重复
10078=读取资源失败
10079=LLM大模型和Intent意图识别,选择参数不匹配
10080=此声音声纹对应的人({0})已经注册,请选择其他声音注册
10081=删除声纹出现错误
10082=此次修改不允许,此声音已经注册为声纹了({0})
10083=修改声纹错误,请联系管理员
10084=声纹接口地址存在错误,请进入参数管理修改声纹接口地址
10085=音频数据不属于这个智能体
10086=音频数据是空的请检查上传数据
10087=声纹保存失败,请求不成功
10088=声纹保存失败,请求处理失败
10089=声纹注销失败,请求不成功
10090=声纹注销失败,请求处理失败
10091=供应器不存在
10092=设置的LLM不存在
10093=该模型配置已被智能体{0}引用,无法删除
10094=该LLM模型已被意图识别配置引用,无法删除
10095=无效服务端操作
10096=未配置服务端WebSocket地址
10097=目标WebSocket地址不存在
10098=WebSocket地址列表不能为空
10099=WebSocket地址不能使用localhost或127.0.0.1
10100=WebSocket地址格式不正确
10101=WebSocket连接测试失败
10102=OTA地址不能为空
10103=OTA地址不能使用localhost或127.0.0.1
10104=OTA地址必须以http或https开头
10105=OTA地址必须以/ota/结尾
10106=OTA接口访问失败
10107=OTA接口返回内容格式不正确
10108=OTA接口验证失败
10109=MCP地址不能为空
10110=MCP地址不能使用localhost或127.0.0.1
10111=不是正确的MCP地址
10112=MCP接口访问失败
10113=MCP接口返回内容格式不正确
10114=MCP接口验证失败
10115=声纹接口地址不能为空
10116=声纹接口地址不能使用localhost或127.0.0.1
10117=不是正确的声纹接口地址
10118=声纹接口地址必须以http或https开头
10119=声纹接口访问失败
10120=声纹接口返回内容格式不正确
10121=声纹接口验证失败
10122=mqtt密钥不能为空
10123=您的mqtt密钥长度不安全,字符数需要至少8个字符且必须同时包含大小写字母
10124=您的mqtt密钥长度不安全,mqtt密钥必须同时包含大小写字母
10125=您的mqtt密钥包含弱密码
10128=字典标签重复
@@ -1,46 +1,137 @@
#\u7E41\u4F53\u4E2D\u6587
500=\u670D\u52D9\u5668\u5167\u90E8\u7570\u5E38
401=\u672A\u6388\u6B0A
403=\u62D2\u7D55\u8A2A\u554F\uFF0C\u6C92\u6709\u6B0A\u9650
#繁體中文
500=服務器內部異常
401=未授權
403=拒絕訪問,沒有权限
10001={0}\u4E0D\u80FD\u70BA\u7A7A
10002=\u6578\u64DA\u5EAB\u4E2D\u5DF2\u5B58\u5728\u8A72\u8A18\u9304
10003=\u7372\u53D6\u53C3\u6578\u5931\u6557
10004=\u8CEC\u865F\u6216\u5BC6\u78BC\u932F\u8AA4
10005=\u8CEC\u865F\u5DF2\u88AB\u505C\u7528
10006=\u552F\u4E00\u6A19\u8B58\u4E0D\u80FD\u70BA\u7A7A
10007=\u9A57\u8B49\u78BC\u4E0D\u6B63\u78BA
10008=\u5148\u522A\u9664\u5B50\u83DC\u55AE\u6216\u6309\u9215
10009=\u539F\u5BC6\u78BC\u4E0D\u6B63\u78BA
10001={0}不能為空
10002=數據庫中已存在該記錄
10003=獲取參數失敗
10004=賬號或密碼錯誤
10005=賬號已被停用
10006=唯一標識不能為空
10007=驗證碼不正確
10008=先刪除子菜單或按鈕
10009=原密碼不正確
10010=帳號或密碼不正確,您還有可以嘗試{0}次
10011=\u4E0A\u7D1A\u90E8\u9580\u9078\u64C7\u932F\u8AA4
10012=\u4E0A\u7D1A\u83DC\u55AE\u4E0D\u80FD\u70BA\u81EA\u8EAB
10013=\u6578\u64DA\u6B0A\u9650\u63A5\u53E3\uFF0C\u53EA\u80FD\u662FMap\u985E\u578B\u53C3\u6578
10014=\u8ACB\u5148\u522A\u9664\u4E0B\u7D1A\u90E8\u9580
10015=\u8ACB\u5148\u522A\u9664\u90E8\u9580\u4E0B\u7684\u7528\u6236
10011=上級部門選擇錯誤
10012=上級菜單不能為自身
10013=數據權限接口,只能是Map類型參數
10014=請先刪除下級部門
10015=請先刪除部門下的用戶
10016=部署失敗,沒有流程
10017=模型圖不正確,請檢查
10018=導出失敗,模型ID為{0}
10019=\u8ACB\u4E0A\u50B3\u6587\u4EF6
10020=token\u4E0D\u80FD\u70BA\u7A7A
10021=token\u5931\u6548\uFF0C\u8ACB\u91CD\u65B0\u767B\u9304
10022=\u8CEC\u865F\u5DF2\u88AB\u9396\u5B9A
10019=請上傳文件
10020=token不能為空
10021=token失效,請重新登錄
10022=賬號已被鎖定
10023=請上傳zip、bar、bpmn、bpmn20.xml格式文件
10024=\u4E0A\u50B3\u6587\u4EF6\u5931\u6557{0}
10024=上傳文件失敗{0}
10025=發送短信失敗{0}
10026=郵件模板不存在
10027=Redis\u670D\u52D9\u7570\u5E38
10028=\u5B9A\u6642\u4EFB\u52D9\u5931\u6557
10029=\u4E0D\u80FD\u5305\u542B\u975E\u6CD5\u5B57\u7B26
10030=\u5BC6\u78BC\u9577\u5EA6\u4E0D\u8DB3{0}\u4F4D
10031=\u5BC6\u78BC\u5FC5\u9808\u540C\u6642\u5305\u542B\u6578\u5B57\u3001\u5927\u5C0F\u5B57\u6BCD\u548C\u7279\u6B8A\u5B57\u7B26\u7D44\u6210
10032=\u522A\u9664\u6B64\u6578\u64DA\u7570\u5E38
10033=\u8A2D\u5099\u9A57\u8B49\u78BC\u932F\u8AA4
10027=Redis服務異常
10028=定時任務失敗
10029=不能包含非法字符
10030=密碼長度不足{0}位
10031=密碼必須同時包含數字、大小寫字母和特殊字符組成
10032=刪除本數據異常
10033=設備驗證碼錯誤
10034=\u53C3\u6578\u503C\u4E0D\u80FD\u70BA\u7A7A
10035=\u53C3\u6578\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
10036=\u4E0D\u652F\u63F4\u7684\u53C3\u6578\u985E\u578B
10037=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684\u6578\u5B57
10038=\u53C3\u6578\u503C\u5FC5\u9808\u662Ftrue\u6216false
10039=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u6578\u7D44\u683C\u5F0F
10040=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
10034=參數值不能為空
10035=參數類型不能為空
10036=不支持的參數類型
10037=參數值必須是有效的數字
10038=參數值必須是true或false
10039=參數值必須是有效的JSON數組格式
10040=參數值必須是有效的JSON格式
10041=\u8A2D\u5099\u672A\u627E\u5230
10042={0}
10041=設備未找到
10042={0}
10043=刪除數據失敗
10044=用戶未登錄
10045=WebSocket連接失敗或連接超時
10046=保存聲紋錯誤,請聯繫管理員
10047=每日發送次數已達上限
10048=舊密碼輸入錯誤
10049=設置的LLM不是openai和ollama
10050=token生成失敗
10051=資源不存在
10052=默認智能體未找到
10053=智能體未找到
10054=聲紋接口未配置,請先在參數配置中配置聲紋接口地址(server.voice_print)
10055=短信發送失敗
10056=短信連接建立失敗
10057=智能體的聲紋創建失敗
10058=智能體的對應聲紋更新失敗
10059=智能體的對應聲紋刪除失敗
10060=發送太頻繁,請{0}秒後再試
10061=激活碼不能為空
10062=激活碼錯誤
10063=設備已激活
10064=該模型為預設模型,請先設置其他模型為預設模型
10065=新增數據失敗
10066=更新數據失敗
10067=圖形驗證碼錯誤
10068=未開啟手機註冊,無法使用短信驗證碼功能
10069=用戶名不是手機號碼,請重新輸入
10070=該手機號碼已註冊
10071=輸入的手機號碼未註冊
10072=目前不允許普通用戶註冊
10073=未開啟手機註冊,無法使用密碼找回功能
10074=輸入的手機號碼格式不正確
10075=輸入的短信驗證碼不正確
10076=字典類型不存在
10077=字典類型編碼重複
10078=讀取資源失敗
10079=LLM模型與意圖識別、參數選擇不匹配
10080=此聲紋屬於已註冊的{0},請選擇其他聲音
10081=刪除聲紋時發生錯誤
10082=不允許修改,此聲音已註冊為聲紋({0})
10083=修改聲紋錯誤,請聯繫管理員
10084=聲紋接口地址錯誤,請前往參數管理修改聲紋接口地址
10085=音頻數據不屬於此智能體
10086=音頻數據為空,請檢查上傳數據
10087=聲紋註冊失敗,請求未成功
10088=聲紋註冊失敗,請求處理失敗
10089=聲紋註銷失敗,請求未成功
10090=聲紋註銷失敗,請求處理失敗
10091=模型提供商不存在
10092=配置的LLM不存在
10093=此模型配置被智能體{0}引用,無法刪除
10094=此LLM模型被意圖識別配置引用,無法刪除
10095=無效的服務器操作
10096=未配置服務器WebSocket地址
10097=目標WebSocket地址不存在
10098=WebSocket地址列表不能為空
10099=WebSocket地址不能使用localhost或127.0.0.1
10100=WebSocket地址格式不正確
10101=WebSocket連接測試失敗
10102=OTA地址不能為空
10103=OTA地址不能使用localhost或127.0.0.1
10104=OTA地址必須以http或https開頭
10105=OTA地址必須以/ota/結尾
10106=OTA接口訪問失敗
10107=OTA接口返回內容格式不正確
10108=OTA接口驗證失敗
10109=MCP地址不能為空
10110=MCP地址不能使用localhost或127.0.0.1
10111=不是有效的MCP地址
10112=MCP接口訪問失敗
10113=MCP接口返回內容格式不正確
10114=MCP接口驗證失敗
10115=聲紋接口地址不能為空
10116=聲紋接口地址不能使用localhost或127.0.0.1
10117=不是有效的聲紋接口地址
10118=聲紋接口地址必須以http或https開頭
10119=聲紋接口訪問失敗
10120=聲紋接口返回內容格式不正確
10121=聲紋接口驗證失敗
10122=MQTT密鑰不能為空
10123=您的MQTT密鑰不安全,需至少8個字符且必須同時包含大小寫字母
10124=您的MQTT密鑰不安全,MQTT密鑰必須同時包含大小寫字母
10125=您的MQTT密鑰包含弱密碼
10128=字典標籤重複