Merge branch 'main' into yinseyemian

This commit is contained in:
hrz
2025-11-17 17:09:53 +08:00
committed by GitHub
89 changed files with 8922 additions and 6013 deletions
@@ -299,7 +299,7 @@ public interface Constant {
/**
* 版本号
*/
public static final String VERSION = "0.8.7";
public static final String VERSION = "0.8.8";
/**
* 无效固件URL
@@ -205,8 +205,27 @@ public interface ErrorCode {
int RAG_CONFIG_NOT_FOUND = 10164; // RAG配置未找到
int RAG_CONFIG_TYPE_ERROR = 10165; // RAG配置类型错误
int RAG_DEFAULT_CONFIG_NOT_FOUND = 10166; // 默认RAG配置未找到
int RAG_API_ERROR = 10167; // RAG配置缺少必要参数
int RAG_API_ERROR = 10167; // RAG调用失败
int UPLOAD_FILE_ERROR = 10168; // 上传文件失败
int NO_PERMISSION = 10169; // 没有权限
int KNOWLEDGE_BASE_NAME_EXISTS = 10170; // 同名知识库已存在
int RAG_API_ERROR_URL_NULL = 10171; // RAG配置中base_url为空,请完善配置
int RAG_API_ERROR_API_KEY_NULL = 10172; // RAG配置中api_key为空,请完善配置
int RAG_API_ERROR_API_KEY_INVALID = 10173; // RAG配置中api_key包含占位符,请替换为实际的API密钥
int RAG_API_ERROR_URL_INVALID = 10174; // RAG配置中base_url格式不正确,请检查协议是否正确
int RAG_DATASET_ID_NOT_NULL = 10176; // RAG配置中dataset_id不能为空
int RAG_MODEL_ID_NOT_NULL = 10177; // RAG配置中model_id不能为空
int RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL = 10178; // RAG配置中dataset_id和model_id不能为空
int RAG_FILE_NAME_NOT_NULL = 10179; // 文件名称不能为空
int RAG_FILE_CONTENT_EMPTY = 10180; // 文件内容不能为空
// 设备相关错误码(补充)
int MCA_NOT_NULL = 10175; // mac地址不能为空
// 音色克隆(补充)
int VOICE_CLONE_NAME_NOT_NULL = 10181; // 音色克隆名称不能为空
int VOICE_CLONE_AUDIO_NOT_FOUND = 10182; // 音色克隆音频不存在
// 智能体模板相关错误码(补充)
int AGENT_TEMPLATE_NOT_FOUND = 10183; // 默认智能体未找到
}
@@ -139,14 +139,14 @@ public class AgentChatHistoryController {
// 从Redis获取agentId和sessionId
String agentSessionInfo = (String) redisUtils.get(RedisKeys.getChatHistoryKey(uuid));
if (StringUtils.isBlank(agentSessionInfo)) {
throw new RenException("下载链接已过期或无效");
throw new RenException(ErrorCode.DOWNLOAD_LINK_EXPIRED);
}
try {
// 解析agentId和sessionId
String[] parts = agentSessionInfo.split(":");
if (parts.length != 2) {
throw new RenException("下载链接无效");
throw new RenException(ErrorCode.DOWNLOAD_LINK_INVALID);
}
String agentId = parts[0];
String sessionId = parts[1];
@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import xiaozhi.common.utils.JsonUtils;
import xiaozhi.modules.agent.dao.AgentPluginMappingMapper;
import xiaozhi.modules.agent.entity.AgentPluginMapping;
@@ -27,6 +28,7 @@ import xiaozhi.modules.model.service.ModelConfigService;
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class AgentPluginMappingServiceImpl extends ServiceImpl<AgentPluginMappingMapper, AgentPluginMapping>
implements AgentPluginMappingService {
private final AgentPluginMappingMapper agentPluginMappingMapper;
@@ -85,7 +87,7 @@ public class AgentPluginMappingServiceImpl extends ServiceImpl<AgentPluginMappin
String description = "如果用户询问与【"
+ String.join(",", knowledgeBaseList.stream().map(KnowledgeBaseEntity::getName).toList())
+ "相关的问题应调用本方法,用于查询:" + String.join(",",
+ "涵盖的主体范围相关内容时应调用本方法,用于查询:" + String.join(",",
knowledgeBaseList.stream().map(KnowledgeBaseEntity::getDescription).toList());
paramInfo.put("description", description);
agentPluginMapping.setParamInfo(JsonUtils.toJsonString(paramInfo));
@@ -73,7 +73,7 @@ public class ConfigServiceImpl implements ConfigService {
// 查询默认智能体
AgentTemplateEntity agent = agentTemplateService.getDefaultTemplate();
if (agent == null) {
throw new RenException("默认智能体未找到");
throw new RenException(ErrorCode.AGENT_TEMPLATE_NOT_FOUND);
}
// 构建模块配置
@@ -111,13 +111,13 @@ public class ConfigServiceImpl implements ConfigService {
if (StringUtils.isNotBlank(cachedCode)) {
throw new RenException(ErrorCode.OTA_DEVICE_NEED_BIND, cachedCode);
}
throw new RenException(ErrorCode.OTA_DEVICE_NOT_FOUND, "not found device");
throw new RenException(ErrorCode.OTA_DEVICE_NOT_FOUND);
}
// 获取智能体信息
AgentEntity agent = agentService.getAgentById(device.getAgentId());
if (agent == null) {
throw new RenException("智能体未找到");
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
}
// 获取音色信息
String voice = null;
@@ -69,7 +69,7 @@ public class DeviceController {
public Result<String> registerDevice(@RequestBody DeviceRegisterDTO deviceRegisterDTO) {
String macAddress = deviceRegisterDTO.getMacAddress();
if (StringUtils.isBlank(macAddress)) {
return new Result<String>().error(ErrorCode.NOT_NULL, "mac地址不能为空");
return new Result<String>().error(ErrorCode.MCA_NOT_NULL);
}
// 生成六位验证码
String code = String.valueOf(Math.random()).substring(2, 8);
@@ -1,6 +1,7 @@
package xiaozhi.modules.knowledge.dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import xiaozhi.common.dao.BaseDao;
import xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity;
@@ -11,4 +12,11 @@ import xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity;
@Mapper
public interface KnowledgeBaseDao extends BaseDao<KnowledgeBaseEntity> {
/**
* 根据知识库ID删除相关的插件映射记录
*
* @param knowledgeBaseId 知识库ID
*/
void deletePluginMappingByKnowledgeBaseId(@Param("knowledgeBaseId") String knowledgeBaseId);
}
@@ -71,11 +71,12 @@ public interface KnowledgeBaseService extends BaseService<KnowledgeBaseEntity> {
Map<String, Object> getRAGConfig(String ragModelId);
/**
* 获取默认RAG配置信息
* 根据知识库ID获取对应的RAG配置
*
* @return 默认RAG配置信息
* @param datasetId 知识库ID
* @return RAG配置
*/
Map<String, Object> getDefaultRAGConfig();
Map<String, Object> getRAGConfigByDatasetId(String datasetId);
/**
* 获取RAG模型列表
@@ -74,13 +74,6 @@ public interface KnowledgeFilesService {
*/
Map<String, Object> getRAGConfig(String ragModelId);
/**
* 获取默认RAG配置信息
*
* @return 默认RAG配置信息
*/
Map<String, Object> getDefaultRAGConfig();
/**
* 解析文档(切块)
*
@@ -1,5 +1,6 @@
package xiaozhi.modules.knowledge.service.impl;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
@@ -51,6 +52,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
private final ModelConfigDao modelConfigDao;
private final RedisUtils redisUtils;
private RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public KnowledgeBaseEntity selectById(Serializable datasetId) {
@@ -108,7 +110,10 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
knowledgeBase.getRagModelId());
knowledgeBase.setDocumentCount(documentCount);
} catch (Exception e) {
log.warn("获取知识库 {} 的文档数量失败: {}", knowledgeBase.getDatasetId(), e.getMessage());
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName() + " - 获取知识库文档数量失败";
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.warn("知识库 {} {}", knowledgeBase.getDatasetId(), errorMessage);
knowledgeBase.setDocumentCount(0); // 设置默认值
}
}
@@ -149,7 +154,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
knowledgeBaseDTO.getDescription(),
ragConfig);
} catch (Exception e) {
// 如果RAG API调用失败,直接抛出异常,无需回滚(因为还没有插入本地数据库)
// 如果RAG API调用失败,直接抛出异常
throw e;
}
@@ -162,7 +167,12 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
deleteDatasetInRAGFlow(datasetId, ragConfig);
} catch (Exception deleteException) {
log.warn("删除重复datasetId的RAGFlow数据集失败: {}", deleteException.getMessage());
// 提供更详细的错误信息,包括异常类型和消息
String errorMessage = "删除重复datasetId的RAGFlow数据集失败: " + deleteException.getClass().getSimpleName();
if (deleteException.getMessage() != null) {
errorMessage += " - " + deleteException.getMessage();
}
log.warn(errorMessage, deleteException);
}
throw new RenException(ErrorCode.DB_RECORD_EXISTS);
}
@@ -201,6 +211,35 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
}
}
boolean needRagValidation = StringUtils.isNotBlank(knowledgeBaseDTO.getDatasetId())
&& StringUtils.isNotBlank(knowledgeBaseDTO.getRagModelId());
if (needRagValidation) {
try {
// 先校验RAG配置
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
// 调用RAGFlow API更新数据集
updateDatasetInRAGFlow(
knowledgeBaseDTO.getDatasetId(),
knowledgeBaseDTO.getName(),
knowledgeBaseDTO.getDescription(),
ragConfig);
log.info("RAGFlow API更新成功,datasetId: {}", knowledgeBaseDTO.getDatasetId());
} catch (Exception e) {
// 提供更详细的错误信息,包括异常类型和消息
String errorMessage = "更新RAGFlow数据集失败: " + e.getClass().getSimpleName();
if (e.getMessage() != null) {
errorMessage += " - " + e.getMessage();
}
log.error(errorMessage, e);
throw e;
}
} else {
log.warn("datasetId或ragModelId为空,跳过RAGFlow更新");
}
KnowledgeBaseEntity entity = ConvertUtils.sourceToTarget(knowledgeBaseDTO, KnowledgeBaseEntity.class);
knowledgeBaseDao.updateById(entity);
@@ -209,22 +248,6 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entity.getId()));
}
// 调用RAGFlow API更新数据集
if (StringUtils.isNotBlank(knowledgeBaseDTO.getDatasetId())) {
try {
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
updateDatasetInRAGFlow(
knowledgeBaseDTO.getDatasetId(),
knowledgeBaseDTO.getName(),
knowledgeBaseDTO.getDescription(),
ragConfig);
} catch (Exception e) {
// 如果RAG API调用失败,回滚本地数据库操作
knowledgeBaseDao.updateById(existingEntity);
throw e;
}
}
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
}
@@ -265,22 +288,40 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
log.info("找到记录: ID={}, datasetId={}, ragModelId={}",
entity.getId(), entity.getDatasetId(), entity.getRagModelId());
// 先删除本地数据库记录
int deleteCount = knowledgeBaseDao.deleteById(entity.getId());
log.info("本地数据库删除结果: {}", deleteCount > 0 ? "成功" : "失败");
// 调用RAGFlow API删除数据集
// 先调用RAGFlow API删除数据集
boolean apiDeleteSuccess = false;
if (StringUtils.isNotBlank(entity.getDatasetId()) && StringUtils.isNotBlank(entity.getRagModelId())) {
try {
log.info("开始调用RAGFlow API删除数据集");
// 在删除前进行RAG配置校验
Map<String, Object> ragConfig = getValidatedRAGConfig(entity.getRagModelId());
deleteDatasetInRAGFlow(entity.getDatasetId(), ragConfig);
log.info("RAGFlow API删除调用完成");
apiDeleteSuccess = true;
} catch (Exception e) {
log.warn("删除RAGFlow数据集失败: {}", e.getMessage());
// 提供更详细的错误信息,包括异常类型和消息
String errorMessage = "删除RAGFlow数据集失败: " + e.getClass().getSimpleName();
if (e.getMessage() != null) {
errorMessage += " - " + e.getMessage();
}
log.error(errorMessage, e);
throw e;
}
} else {
log.warn("datasetId或ragModelId为空,跳过RAGFlow删除");
apiDeleteSuccess = true; // 没有RAG数据集,视为成功
}
// API删除成功后再删除本地记录
if (apiDeleteSuccess) {
log.info("开始删除ai_agent_plugin_mapping表中与知识库ID '{}' 相关的映射记录", entity.getId());
// 先删除相关的插件映射记录
knowledgeBaseDao.deletePluginMappingByKnowledgeBaseId(entity.getId());
log.info("插件映射记录删除完成");
int deleteCount = knowledgeBaseDao.deleteById(entity.getId());
log.info("本地数据库删除结果: {}", deleteCount > 0 ? "成功" : "失败");
}
log.info("=== 通过datasetId删除操作结束 ===");
@@ -313,29 +354,27 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
}
@Override
public Map<String, Object> getDefaultRAGConfig() {
// 获取默认RAG模型配置
QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", Constant.RAG_CONFIG_TYPE)
.eq("is_default", 1)
.eq("is_enabled", 1);
List<ModelConfigEntity> modelConfigs = modelConfigDao.selectList(queryWrapper);
if (modelConfigs == null || modelConfigs.isEmpty()) {
throw new RenException(ErrorCode.RAG_DEFAULT_CONFIG_NOT_FOUND);
public Map<String, Object> getRAGConfigByDatasetId(String datasetId) {
if (StringUtils.isBlank(datasetId)) {
throw new RenException(ErrorCode.RAG_DATASET_ID_NOT_NULL);
}
ModelConfigEntity defaultConfig = modelConfigs.get(0);
if (defaultConfig.getConfigJson() == null) {
// 根据datasetId查询知识库信息
KnowledgeBaseDTO knowledgeBase = getByDatasetId(datasetId);
if (knowledgeBase == null) {
log.warn("未找到datasetId为{}的知识库", datasetId);
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
}
// 如果知识库指定了ragModelId,使用该配置
String ragModelId = knowledgeBase.getRagModelId();
if (StringUtils.isBlank(ragModelId)) {
log.warn("知识库datasetId为{}未配置ragModelId", datasetId);
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND);
}
Map<String, Object> config = defaultConfig.getConfigJson();
// 验证必要的配置参数
validateRagConfig(config);
return config;
// 获取并返回RAG配置
return getRAGConfig(ragModelId);
}
@Override
@@ -373,7 +412,22 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
// 验证base_url是否存在且非空
if (StringUtils.isBlank(baseUrl)) {
throw new RenException(ErrorCode.RAG_API_ERROR);
throw new RenException(ErrorCode.RAG_API_ERROR_URL_NULL);
}
// 验证api_key是否存在且非空
if (StringUtils.isBlank(apiKey)) {
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_NULL);
}
// 检查api_key是否包含占位符
if (apiKey.contains("")) {
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_INVALID);
}
// 验证base_url格式
if (!baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")) {
throw new RenException(ErrorCode.RAG_API_ERROR_URL_INVALID);
}
}
@@ -410,14 +464,22 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
// 发送POST请求
log.info("发送POST请求到RAGFlow API...");
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
ResponseEntity<String> response;
try {
response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
} catch (Exception e) {
String errorMessage = url + e.getMessage();
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
log.debug("RAGFlow API响应内容: {}", response.getBody());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode().toString());
String errorMessage = response.getStatusCode() + ", 响应内容: " + response.getBody();
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
// 解析响应体,提取datasetId
@@ -448,22 +510,36 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
}
} else {
// 如果响应码不为0,说明API调用失败
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, message);
throw new RenException(ErrorCode.RAG_API_ERROR,
"RAGFlow API调用失败,响应码: " + code + ", 消息: " + message);
String errorMessage = code + (message != null ? message : "null");
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
log.info("从RAGFlow API响应中解析出datasetId: {}", datasetId);
log.debug("完整响应内容: {}", responseBody);
} catch (IOException e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} catch (Exception e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析响应失败: " + e.getMessage());
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
// 如果解析失败,但响应体不为空,尝试直接使用响应体作为错误信息
String finalErrorMessage = responseBody;
if (e.getMessage() != null) {
finalErrorMessage += errorMessage;
}
throw new RenException(ErrorCode.RAG_API_ERROR, finalErrorMessage);
}
}
if (StringUtils.isBlank(datasetId)) {
log.error("无法从RAGFlow API响应中获取datasetId,响应内容: {}", responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API响应中未包含datasetId");
throw new RenException(ErrorCode.RAG_DATASET_ID_NOT_NULL);
}
log.info("RAGFlow数据集创建成功,datasetId: {}", datasetId);
@@ -503,14 +579,55 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
// 发送PUT请求
log.info("发送PUT请求到RAGFlow API...");
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class);
ResponseEntity<String> response;
try {
response = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class);
} catch (Exception e) {
String errorMessage = url + e.getMessage();
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
log.debug("RAGFlow API响应内容: {}", response.getBody());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
String errorMessage = response.getStatusCode() + ", 响应内容: " + response.getBody();
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
// 解析响应体,验证操作是否真正成功
String responseBody = response.getBody();
if (responseBody != null) {
try {
Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
Integer code = (Integer) responseMap.get("code");
String message = (String) responseMap.get("message");
if (code != null && code != 0) {
String errorMessage = code + (message != null ? message : "null");
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
} catch (IOException e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} catch (Exception e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
// 如果解析失败,但响应体不为空,尝试直接使用响应体作为错误信息
String finalErrorMessage = responseBody;
if (e.getMessage() != null) {
finalErrorMessage += errorMessage;
}
throw new RenException(ErrorCode.RAG_API_ERROR, finalErrorMessage);
}
}
log.info("RAGFlow数据集更新成功,datasetId: {}", datasetId);
@@ -545,16 +662,57 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
// 发送DELETE请求
log.info("发送DELETE请求到RAGFlow API...");
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity,
String.class);
ResponseEntity<String> response;
try {
response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, String.class);
} catch (Exception e) {
String errorMessage = url + e.getMessage();
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
log.debug("RAGFlow API响应内容: {}", response.getBody());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
String errorMessage = response.getStatusCode() + response.getBody();
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
// 解析响应体,验证操作是否真正成功
String responseBody = response.getBody();
if (responseBody != null) {
try {
Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
Integer code = (Integer) responseMap.get("code");
String message = (String) responseMap.get("message");
if (code != null && code != 0) {
String errorMessage = code + (message != null ? message : "null");
log.error(errorMessage);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
} catch (IOException e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} catch (Exception e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName();
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
// 如果解析失败,但响应体不为空,尝试直接使用响应体作为错误信息
String finalErrorMessage = responseBody;
if (e.getMessage() != null) {
finalErrorMessage += errorMessage;
}
throw new RenException(ErrorCode.RAG_API_ERROR, finalErrorMessage);
}
}
log.info("RAGFlow数据集删除成功,datasetId: {}", datasetId);
}
@@ -563,48 +721,18 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
* 获取RAG配置并验证
*/
private Map<String, Object> getValidatedRAGConfig(String ragModelId) {
Map<String, Object> ragConfig;
if (StringUtils.isNotBlank(ragModelId)) {
ragConfig = getRAGConfig(ragModelId);
} else {
ragConfig = getDefaultRAGConfig();
if (StringUtils.isBlank(ragModelId)) {
throw new RenException(ErrorCode.RAG_MODEL_ID_NOT_NULL);
}
// 验证baseUrl和apiKey
validateRAGConfigParameters(ragConfig);
Map<String, Object> ragConfig = getRAGConfig(ragModelId);
// 验证RAG配置参数
validateRagConfig(ragConfig);
return ragConfig;
}
/**
* 验证RAG配置参数
*/
private void validateRAGConfigParameters(Map<String, Object> ragConfig) {
if (ragConfig == null) {
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND, "RAG配置为空,请检查配置");
}
// 从配置中提取必要的参数
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
if (StringUtils.isBlank(baseUrl)) {
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG配置中base_url为空,请完善配置");
}
if (StringUtils.isBlank(apiKey)) {
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG配置中api_key为空,请完善配置");
}
if (apiKey.contains("")) {
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG配置中api_key包含占位符'你',请替换为实际的API密钥");
}
if (!baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")) {
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG配置中base_url格式不正确,必须以http://或https://开头");
}
}
/**
* 检查是否存在同名知识库
*
@@ -660,7 +788,14 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
// 发送GET请求
log.info("发送GET请求到RAGFlow API获取文档数量...");
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
ResponseEntity<String> response;
try {
response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
} catch (Exception e) {
String errorMessage = url + e.getMessage();
log.error(errorMessage, e);
return 0;
}
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
@@ -696,8 +831,16 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
} else {
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody);
}
} catch (IOException e) {
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName() + " - 解析RAGFlow API响应时发生IO异常";
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
} catch (Exception e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
// 构建详细的错误信息,包含异常类型和消息
String baseErrorMessage = e.getClass().getSimpleName() + " - 解析RAGFlow API响应失败";
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
log.error(errorMessage, e);
}
return 0;
}
@@ -16,43 +16,39 @@ import org.springframework.core.io.AbstractResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
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.modules.knowledge.dto.KnowledgeFilesDTO;
import xiaozhi.modules.knowledge.service.KnowledgeBaseService;
import xiaozhi.modules.knowledge.service.KnowledgeFilesService;
import xiaozhi.modules.model.dao.ModelConfigDao;
import xiaozhi.modules.model.entity.ModelConfigEntity;
import xiaozhi.modules.model.service.ModelConfigService;
@Service
@AllArgsConstructor
@Slf4j
public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
private final ModelConfigService modelConfigService;
private final ModelConfigDao modelConfigDao;
private final KnowledgeBaseService knowledgeBaseService;
private RestTemplate restTemplate = new RestTemplate();
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public Map<String, Object> getRAGConfig(String ragModelId) {
return knowledgeBaseService.getRAGConfig(ragModelId);
}
@Override
public PageData<KnowledgeFilesDTO> getPageList(KnowledgeFilesDTO knowledgeFilesDTO, Integer page, Integer limit) {
try {
@@ -64,17 +60,17 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
knowledgeFilesDTO != null ? knowledgeFilesDTO.getStatus() : null,
page, limit);
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
// 构建请求URL - 根据RAGFlow API文档,获取文档列表的接口
String datasetId = knowledgeFilesDTO != null ? knowledgeFilesDTO.getDatasetId() : null;
if (StringUtils.isBlank(datasetId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_NOT_NULL);
}
// 获取RAG配置
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
String url = baseUrl + "/api/v1/datasets/" + datasetId + "/documents";
// 添加查询参数
@@ -112,8 +108,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode().toString());
}
String responseBody = response.getBody();
@@ -127,27 +123,22 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
Object dataObj = responseMap.get("data");
return parseDocumentListResponse(dataObj, page, limit);
} else {
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败,响应码: " + code);
log.error("RAGFlow API调用失败,响应码: {}", code);
// 获取错误消息,如果存在的话
String apiMessage = (String) responseMap.get("message");
String errorDetail = apiMessage != null ? apiMessage : "无详细错误信息";
log.error("RAGFlow API调用失败,响应码: {}, 错误详情: {}", errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("获取文档列表失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取文档列表失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 获取文档列表操作结束 ===");
}
@@ -238,7 +229,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
} catch (Exception e) {
log.error("获取文档列表响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取文档列表响应失败: " + e.getMessage());
throw new RenException(ErrorCode.RAG_API_ERROR, e.getMessage());
}
}
@@ -262,7 +253,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
long currentTime = System.currentTimeMillis();
// 调用RAGFlow API获取文档切片信息
Map<String, Object> ragConfig = getDefaultRAGConfig();
String datasetId = dto.getDatasetId();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -450,7 +442,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
@Override
public KnowledgeFilesDTO getByDocumentId(String documentId, String datasetId) {
if (StringUtils.isBlank(documentId) || StringUtils.isBlank(datasetId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "documentId和datasetId不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL);
}
log.info("=== 开始根据documentId获取文档 ===");
@@ -458,7 +450,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -480,8 +472,10 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
String responseBody = response.getBody();
throw new RenException(ErrorCode.RAG_API_ERROR,
response.getStatusCode() + (responseBody != null ? responseBody : "null"));
}
String responseBody = response.getBody();
@@ -502,32 +496,21 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
}
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
} else {
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败,响应码: " + code);
log.error("RAGFlow API调用失败,响应码: {}", code);
// 获取错误消息,如果存在的话
String apiMessage = (String) responseMap.get("message");
String errorDetail = apiMessage != null ? apiMessage : "无详细错误信息";
log.error("RAGFlow API调用失败详情: {}", errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
log.warn("文档不存在,documentId: {}, datasetId: {}", documentId, datasetId);
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
}
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString());
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString());
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("根据documentId获取文档失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取文档失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 根据documentId获取文档操作结束 ===");
}
@@ -537,7 +520,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
public PageData<KnowledgeFilesDTO> getPageListByStatus(String datasetId, Integer status, Integer page,
Integer limit) {
if (StringUtils.isBlank(datasetId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_NOT_NULL);
}
log.info("=== 开始根据状态查询文档列表 ===");
@@ -545,7 +528,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -583,8 +566,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode().toString());
}
String responseBody = response.getBody();
@@ -615,28 +598,13 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
datasetId, status, pageData.getList().size());
return pageData;
} else {
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败,响应码: " + code);
log.error("RAGFlow API调用失败,响应码: {}", code);
throw new RenException(ErrorCode.RAG_API_ERROR, code.toString());
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString());
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString());
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "获取RAGFlow文档列表失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("根据状态查询文档列表失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "查询文档列表失败: " + e.getMessage());
throw new RenException(ErrorCode.RAG_API_ERROR, e.getMessage());
} finally {
log.info("=== 根据状态查询文档列表操作结束 ===");
}
@@ -666,12 +634,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
// 检查文件基本信息
if (StringUtils.isBlank(fileName)) {
log.error("文件名为空");
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "文件名不能为空");
throw new RenException(ErrorCode.RAG_FILE_NAME_NOT_NULL);
}
if (fileSize == 0) {
log.error("文件大小为0");
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "文件内容为空");
throw new RenException(ErrorCode.RAG_FILE_CONTENT_EMPTY);
}
log.info("2. 开始流式上传到RAGFlow");
@@ -707,7 +675,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
@Override
public void deleteByDocumentId(String documentId, String datasetId) {
if (StringUtils.isBlank(documentId) || StringUtils.isBlank(datasetId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "documentId和datasetId不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL);
}
log.info("=== 开始根据documentId删除文档 ===");
@@ -722,7 +690,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
} catch (Exception e) {
log.error("删除文档失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "删除文档失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 根据documentId删除文档操作结束 ===");
}
@@ -776,58 +748,6 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
}
}
@Override
public Map<String, Object> getRAGConfig(String ragModelId) {
if (StringUtils.isBlank(ragModelId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR);
}
// 从缓存获取模型配置
ModelConfigEntity modelConfig = modelConfigService.getModelByIdFromCache(ragModelId);
if (modelConfig == null || modelConfig.getConfigJson() == null) {
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND);
}
// 验证是否为RAG类型配置
if (!Constant.RAG_CONFIG_TYPE.equals(modelConfig.getModelType().toUpperCase())) {
throw new RenException(ErrorCode.RAG_CONFIG_TYPE_ERROR);
}
Map<String, Object> config = modelConfig.getConfigJson();
// 验证必要的配置参数
validateRagConfig(config);
// 返回配置信息
return config;
}
@Override
public Map<String, Object> getDefaultRAGConfig() {
// 获取默认RAG模型配置
QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", Constant.RAG_CONFIG_TYPE)
.eq("is_default", 1)
.eq("is_enabled", 1);
List<ModelConfigEntity> modelConfigs = modelConfigDao.selectList(queryWrapper);
if (modelConfigs == null || modelConfigs.isEmpty()) {
throw new RenException(ErrorCode.RAG_DEFAULT_CONFIG_NOT_FOUND);
}
ModelConfigEntity defaultConfig = modelConfigs.get(0);
if (defaultConfig.getConfigJson() == null) {
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND);
}
Map<String, Object> config = defaultConfig.getConfigJson();
// 验证必要的配置参数
validateRagConfig(config);
return config;
}
/**
* 验证RAG配置中是否包含必要的参数
*/
@@ -842,7 +762,22 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
// 验证base_url是否存在且非空
if (StringUtils.isBlank(baseUrl)) {
throw new RenException(ErrorCode.RAG_API_ERROR);
throw new RenException(ErrorCode.RAG_API_ERROR_URL_NULL);
}
// 验证api_key是否存在且非空
if (StringUtils.isBlank(apiKey)) {
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_NULL);
}
// 检查api_key是否包含占位符
if (apiKey.contains("")) {
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_INVALID);
}
// 验证base_url格式
if (!baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")) {
throw new RenException(ErrorCode.RAG_API_ERROR_URL_INVALID);
}
}
@@ -854,7 +789,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
Map<String, Object> parserConfig) {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -939,44 +874,39 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("文档上传成功,documentId: {}", documentId);
} else {
// 如果响应码不为0,说明API调用失败
log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败,响应码: " + code);
log.error("RAGFlow API调用失败,响应码: {}", code);
// 获取错误消息,如果存在的话
String apiMessage = (String) responseMap.get("message");
String errorDetail = apiMessage != null ? apiMessage : "无详细错误信息";
log.error("RAGFlow API调用失败详情: {}", errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
log.info("从RAGFlow API响应中解析出documentId: {}", documentId);
log.debug("完整响应内容: {}", responseBody);
} catch (Exception e) {
log.error("解析RAGFlow API响应失败: {}, 响应内容: {}", e.getMessage(), responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow响应失败: " + e.getMessage());
log.error("解析RAGFlow API响应失败: {}", e.getMessage());
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} else {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR);
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode().toString());
}
if (StringUtils.isBlank(documentId)) {
log.error("无法从RAGFlow API响应中获取documentId,响应内容: {}", responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API响应中未包含documentId");
log.error("无法从RAGFlow API响应中获取documentId");
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
log.info("RAGFlow文档上传成功,documentId: {},文档已开始自动解析切片", documentId);
return documentId;
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "上传RAGFlow文档失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("RAGFlow API调用失败 - 未知错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "上传RAGFlow文档失败: " + e.getMessage());
log.error("RAGFlow API调用失败: {}", e.getMessage(), e);
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
}
@@ -1048,7 +978,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
private void deleteDocumentInRAGFlow(String documentId, String datasetId) {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -1093,8 +1023,9 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
return;
} else {
String message = (String) responseMap.get("message");
log.error("RAGFlow API调用失败,响应码: {}, 消息: {}", code, message);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败: " + message);
log.error("RAGFlow API调用失败,响应码: {}", code);
String errorDetail = message != null ? message : "无详细错误信息";
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (Exception e) {
log.warn("解析RAGFlow响应失败,但HTTP状态码成功,视为删除成功: {}", e.getMessage());
@@ -1106,26 +1037,18 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
return;
}
} else {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR);
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
throw new RenException(ErrorCode.RAG_API_ERROR,
response.getStatusCode() + (responseBody != null ? responseBody : "null"));
}
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR,
"删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "删除RAGFlow文档失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("RAGFlow API调用失败 - 未知错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "删除RAGFlow文档失败: " + e.getMessage());
log.error("RAGFlow API调用失败: {}", e.getMessage(), e);
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
}
}
@@ -1170,7 +1093,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
@Override
public boolean parseDocuments(String datasetId, List<String> documentIds) {
if (StringUtils.isBlank(datasetId) || documentIds == null || documentIds.isEmpty()) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId和documentIds不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL);
}
log.info("=== 开始解析文档(切块) ===");
@@ -1178,7 +1101,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -1204,14 +1127,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
}
String responseBody = response.getBody();
log.debug("RAGFlow API响应内容: {}", responseBody);
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
String errorDetail = responseBody != null ? responseBody : "无响应内容";
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode() + errorDetail);
}
// 解析响应
Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
Integer code = (Integer) responseMap.get("code");
@@ -1220,28 +1144,20 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("文档解析成功,datasetId: {}, documentIds: {}", datasetId, documentIds);
return true;
} else {
// 获取错误消息,如果存在的话
String message = (String) responseMap.get("message");
log.error("RAGFlow API调用失败,响应码: {}, 消息: {}, 响应内容: {}", code, message, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode().toString());
String errorDetail = message != null ? message : "无详细错误信息";
log.error("RAGFlow API调用失败,响应码: {}, 错误信息: {}", code, errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow文档失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow文档失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow文档失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("解析文档失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析文档失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 解析文档操作结束 ===");
}
@@ -1251,7 +1167,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
public Map<String, Object> listChunks(String datasetId, String documentId, String keywords,
Integer page, Integer pageSize, String chunkId) {
if (StringUtils.isBlank(datasetId) || StringUtils.isBlank(documentId)) {
throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId和documentId不能为空");
throw new RenException(ErrorCode.RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL);
}
log.info("=== 开始列出切片 ===");
@@ -1260,7 +1176,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -1308,14 +1224,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR, "列出切片失败");
}
String responseBody = response.getBody();
log.debug("RAGFlow API响应内容: {}", responseBody);
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
String errorDetail = responseBody != null ? responseBody : "无响应内容";
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode() + errorDetail);
}
// 解析响应
Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
Integer code = (Integer) responseMap.get("code");
@@ -1326,28 +1243,24 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
// 解析切片数据并格式化返回
return parseChunkListResponse(responseMap);
} else {
// 获取错误消息,如果存在的话
String message = (String) responseMap.get("message");
log.error("RAGFlow API调用失败,响应码: {}, 消息: {}, 响应内容: {}", code, message, responseBody);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败: " + message);
String errorDetail = message != null ? message : "无详细错误信息";
log.error("RAGFlow API调用失败,响应码: {}, 错误信息: {}", code, errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "列出切片失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "列出切片失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "列出切片失败: 网络连接错误 - " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} catch (Exception e) {
log.error("列出切片失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "列出切片失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 列出切片操作结束 ===");
}
@@ -1661,7 +1574,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
try {
// 获取RAG配置
Map<String, Object> ragConfig = getDefaultRAGConfig();
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetIds.get(0));
String baseUrl = (String) ragConfig.get("base_url");
String apiKey = (String) ragConfig.get("api_key");
@@ -1736,14 +1649,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("RAGFlow API响应状态码: {}", response.getStatusCode());
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody());
throw new RenException(ErrorCode.RAG_API_ERROR);
}
String responseBody = response.getBody();
log.debug("RAGFlow API响应内容: {}", responseBody);
if (!response.getStatusCode().is2xxSuccessful()) {
log.error("RAGFlow API调用失败,状态码: {}", response.getStatusCode());
String errorDetail = responseBody != null ? responseBody : "无响应内容";
throw new RenException(ErrorCode.RAG_API_ERROR, response.getStatusCode() + errorDetail);
}
// 解析响应
Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
Integer code = (Integer) responseMap.get("code");
@@ -1755,32 +1669,24 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService {
log.info("召回测试成功,返回 {} 条切片", result.get("total"));
return result;
} else {
log.error("RAGFlow API响应格式错误,data字段不是Map类型: {}", dataObj);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API响应格式错误");
log.error("RAGFlow API响应格式错误,data字段不是Map类型");
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} else {
// 获取错误消息,如果存在的话
String message = (String) responseMap.get("message");
log.error("RAGFlow API调用失败,响应码: {}, 错误信息: {}", code, message);
throw new RenException(ErrorCode.RAG_API_ERROR, "RAGFlow API调用失败: " + message);
String errorDetail = message != null ? message : "无详细错误信息";
log.error("RAGFlow API调用失败,响应码: {}, 错误信息: {}", code, errorDetail);
throw new RenException(ErrorCode.RAG_API_ERROR, responseBody);
}
} catch (IOException e) {
log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "解析RAGFlow响应失败: " + e.getMessage());
} catch (HttpClientErrorException e) {
log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "召回测试失败: " + e.getMessage());
} catch (HttpServerErrorException e) {
log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}",
e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "召回测试失败: " + e.getMessage());
} catch (ResourceAccessException e) {
log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "召回测试失败: 网络连接错误 - " + e.getMessage());
} catch (Exception e) {
log.error("召回测试失败: {}", e.getMessage(), e);
throw new RenException(ErrorCode.RAG_API_ERROR, "召回测试失败: " + e.getMessage());
String errorMessage = e.getMessage() != null ? e.getMessage() : "null";
if (e instanceof RenException) {
throw (RenException) e;
}
throw new RenException(ErrorCode.RAG_API_ERROR, errorMessage);
} finally {
log.info("=== 召回测试操作结束 ===");
}
@@ -100,7 +100,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
converter.setObjectMapper(mapper);
return converter;
}
/**
* 国际化配置 - 根据请求头中的Accept-Language设置语言环境
*/
@@ -113,14 +113,14 @@ public class WebMvcConfig implements WebMvcConfigurer {
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;
@@ -128,15 +128,25 @@ public class WebMvcConfig implements WebMvcConfigurer {
return Locale.TRADITIONAL_CHINESE;
} else if (primaryLanguage.equals("en-US")) {
return Locale.US;
} else if (primaryLanguage.equals("de-DE")) {
return Locale.GERMANY;
} else if (primaryLanguage.equals("vi-VN")) {
return Locale.forLanguageTag("vi-VN");
} else if (primaryLanguage.startsWith("zh")) {
// 对于其他中文变体,默认使用简体中文
return Locale.SIMPLIFIED_CHINESE;
} else if (primaryLanguage.startsWith("en")) {
// 对于其他英文变体,默认使用美式英语
return Locale.US;
} else if (primaryLanguage.startsWith("de")) {
// 对于其他德语变体,默认使用德语
return Locale.GERMANY;
} else if (primaryLanguage.startsWith("vi")) {
// 对于其他越南语变体,默认使用越南语
return Locale.forLanguageTag("vi-VN");
}
}
// 如果没有匹配的语言,使用默认语言
return Locale.getDefault();
}
@@ -107,10 +107,10 @@ public class VoiceCloneController {
String name = params.get("name");
if (id == null || id.isEmpty()) {
return new Result<String>().error(ErrorCode.IDENTIFIER_NOT_NULL, "唯一标识不能为空");
return new Result<String>().error(ErrorCode.IDENTIFIER_NOT_NULL);
}
if (name == null) {
return new Result<String>().error(ErrorCode.NOT_NULL, "名称不能为空");
if (name == null || name.isEmpty()) {
return new Result<String>().error(ErrorCode.VOICE_CLONE_NAME_NOT_NULL);
}
// 检查权限
checkPermission(id);
@@ -119,7 +119,7 @@ public class VoiceCloneController {
redisUtils.delete(RedisKeys.getTimbreNameById(id));
return new Result<String>();
} catch (Exception e) {
return new Result<String>().error(ErrorCode.UPDATE_DATA_FAILED, "更新失败: " + e.getMessage());
return new Result<String>().error(ErrorCode.UPDATE_DATA_FAILED, e.getMessage());
}
}
@@ -131,7 +131,7 @@ public class VoiceCloneController {
checkPermission(id);
byte[] audioData = voiceCloneService.getVoiceData(id);
if (audioData == null) {
return new Result<String>().error(ErrorCode.RESOURCE_NOT_FOUND, "音频不存在");
return new Result<String>().error(ErrorCode.VOICE_CLONE_AUDIO_NOT_FOUND);
}
String uuid = UUID.randomUUID().toString();
redisUtils.set(RedisKeys.getVoiceCloneAudioIdKey(uuid), id);
@@ -100,7 +100,7 @@ public class VoiceCloneServiceImpl extends BaseServiceImpl<VoiceCloneDao, VoiceC
wrapper.eq("model_id", dto.getModelId());
Long count = baseDao.selectCount(wrapper);
if (count > 0) {
throw new RenException(ErrorCode.VOICE_ID_ALREADY_EXISTS, "音色ID " + voiceId + " 已存在");
throw new RenException(ErrorCode.VOICE_ID_ALREADY_EXISTS);
}
}
@@ -0,0 +1,62 @@
UPDATE `ai_model_config` SET
`doc_link` = 'https://github.com/infiniflow/ragflow/blob/main/README_zh.md',
`remark` = '详细部署教程参考:https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/ragflow-integration.md
部署成功,注冊登录后,点击右上角头像,获得RAGFlow的API KEY和API服务器地址。使用RAGFlow前请在Model Provider中添加模型和设置默认模型。' WHERE `id` = 'RAG_RAGFlow';
update `ai_model_config` set `model_name` = '外挂的大模型意图识别' where `id` = 'Intent_intent_llm';
update `ai_model_config` set `model_name` = '大模型自主函数调用' where `id` = 'Intent_function_call';
update `ai_model_config` set `model_name` = '百炼智能体应用' where `id` = 'LLM_AliAppLLM';
update `ai_model_provider` set `name` = '外挂的大模型意图识别' , `fields` = '[{"key":"llm","label":"引用的LLM模型","type":"string"}]' where id = 'SYSTEM_Intent_intent_llm';
update `ai_model_provider` set `name` = '大模型自主函数调用' where id = 'SYSTEM_Intent_function_call';
UPDATE ai_model_config set model_name = 'Linkerai(流式)' where id = 'TTS_LinkeraiTTS';
UPDATE ai_model_config set model_name = '火山引擎(流式)' where id = 'TTS_HuoshanDoubleStreamTTS';
UPDATE ai_model_config set model_name = '阿里百炼(流式)' where id = 'TTS_AliBLStreamTTS';
UPDATE ai_model_config set model_name = '科大讯飞(流式)' where id = 'TTS_XunFeiStreamTTS';
UPDATE ai_model_config set model_name = 'Minimax(流式)' where id = 'TTS_MinimaxStreamTTS';
UPDATE ai_model_config set model_name = '阿里云(流式)' where id = 'TTS_AliyunStreamTTS';
UPDATE ai_model_config set model_name = 'PaddleSpeech(流式)' where id = 'TTS_PaddleSpeechTTS';
UPDATE ai_model_config set model_name = 'IndexTTS(流式)' where id = 'TTS_IndexStreamTTS';
update ai_model_config SET sort = 2 where id = 'TTS_LinkeraiTTS';
update ai_model_config SET sort = 3 where id = 'TTS_HuoshanDoubleStreamTTS';
update ai_model_config SET sort = 4 where id = 'TTS_AliBLStreamTTS';
update ai_model_config SET sort = 5 where id = 'TTS_XunFeiStreamTTS';
update ai_model_config SET sort = 6 where id = 'TTS_MinimaxStreamTTS';
update ai_model_config SET sort = 7 where id = 'TTS_AliyunStreamTTS';
update ai_model_config SET sort = 8 where id = 'TTS_IndexStreamTTS';
update ai_model_config SET sort = 9 where id = 'TTS_PaddleSpeechTTS';
update ai_model_config SET sort = 10 where id = 'TTS_DoubaoTTS';
update ai_model_config SET sort = 11 where id = 'TTS_TencentTTS';
update ai_model_config SET sort = 12 where id = 'TTS_AliyunTTS';
update ai_model_config SET sort = 13 where id = 'TTS_OpenAITTS';
update ai_model_config SET sort = 14 where id = 'TTS_CosyVoiceSiliconflow';
update ai_model_config SET sort = 15 where id = 'TTS_CozeCnTTS';
update ai_model_config SET sort = 16 where id = 'TTS_FishSpeech';
update ai_model_config SET sort = 17 where id = 'TTS_GPT_SOVITS_V3';
update ai_model_config SET sort = 18 where id = 'TTS_GPT_SOVITS_V2';
update ai_model_config SET sort = 19 where id = 'TTS_TTS302AI';
update ai_model_config SET sort = 20 where id = 'TTS_GizwitsTTS';
update ai_model_config SET sort = 21 where id = 'TTS_VolcesAiGatewayTTS';
update ai_model_config SET sort = 22 where id = 'TTS_ACGNTTS';
update ai_model_config SET sort = 23 where id = 'TTS_CustomTTS';
UPDATE ai_model_config set model_name = '讯飞语音识别(流式)' where id = 'ASR_XunfeiStream';
UPDATE ai_model_config set model_name = 'Qwen3Flash语音识别' where id = 'ASR_Qwen3Flash';
update ai_model_config SET sort = 2 where id = 'ASR_FunASRServer';
update ai_model_config SET sort = 3 where id = 'ASR_XunfeiStream';
update ai_model_config SET sort = 4 where id = 'ASR_AliyunStreamASR';
update ai_model_config SET sort = 5 where id = 'ASR_DoubaoStreamASR';
update ai_model_config SET sort = 6 where id = 'ASR_TencentASR';
update ai_model_config SET sort = 7 where id = 'ASR_BaiduASR';
update ai_model_config SET sort = 8 where id = 'ASR_DoubaoASR';
update ai_model_config SET sort = 9 where id = 'ASR_AliyunASR';
update ai_model_config SET sort = 10 where id = 'ASR_SherpaASR';
update ai_model_config SET sort = 11 where id = 'ASR_OpenaiASR';
update ai_model_config SET sort = 12 where id = 'ASR_GroqASR';
update ai_model_config SET sort = 13 where id = 'ASR_VoskASR';
update ai_model_config SET sort = 14 where id = 'ASR_Qwen3Flash';
UPDATE ai_model_config SET config_json='{\"type\": \"openai\", \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\", \"model_name\": \"doubao-1-5-pro-32k-250115\", \"api_key\": \"你的api_key\"}' where id = 'LLM_DoubaoLLM' AND config_json LIKE '%你的api_key"%';
@@ -415,4 +415,11 @@ databaseChangeLog:
changes:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202510251150.sql
path: classpath:db/changelog/202510251150.sql
- changeSet:
id: 202511131023
author: hrz
changes:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202511131023.sql
@@ -160,11 +160,11 @@
10151=\u8BF7\u5148\u4E0A\u4F20\u97F3\u9891\u6587\u4EF6
10152=\u6A21\u578B\u914D\u7F6E\u672A\u627E\u5230
10153=\u6A21\u578B\u7C7B\u578B\u672A\u627E\u5230
10154=\u8BAD\u7EC3\u5931\u8D25
10154=\u8BAD\u7EC3\u5931\u8D25: {0}
10155=\u706B\u5C71\u5F15\u64CE\u7F3A\u5C11\u914D\u7F6E
10156=\u54CD\u5E94\u683C\u5F0F\u9519\u8BEF\uFF0C\u7F3A\u5C11BaseResp\u5B57\u6BB5
10157=\u8BF7\u6C42\u5931\u8D25
10158=\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801{0}
10158=\u514B\u9686\u97F3\u8272:
10159=\u97F3\u8272ID\u5DF2\u5B58\u5728
10160=\u706B\u5C71\u5F15\u64CE\u97F3\u8272ID\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5S_\u5F00\u5934
10161=Mac\u5730\u5740\u5DF2\u5B58\u5728
@@ -173,7 +173,20 @@
10164=RAG\u914D\u7F6E\u672A\u627E\u5230
10165=RAG\u914D\u7F6E\u7C7B\u578B\u9519\u8BEF
10166=\u9ED8\u8BA4RAG\u914D\u7F6E\u672A\u627E\u5230
10167=RAG\u63A5\u53E3\u9519\u8BEF\uFF0C{0}
10167=RAG\u8C03\u7528\u5931\u8D25\uFF0C{0}
10168=\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25
10169=\u60A8\u6CA1\u6709\u6743\u9650\u64CD\u4F5C\u8BE5\u8BB0\u5F55
10170=\u77E5\u8BC6\u5E93\u540D\u79F0\u91CD\u590D
10170=\u77E5\u8BC6\u5E93\u540D\u79F0\u91CD\u590D
10171=RAG\u914D\u7F6E\u4F53\u7684base_url\u4E0D\u80FD\u4E3A\u7A7A
10172=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A
10173=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u66F4\u6362\u4E3A\u5728\u53D6\u7684API\u53C2\u6570
10174=RAG\u914D\u7F6E\u4F53\u7684base_url\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934
10175=mac\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A
10176=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u4E0D\u80FD\u4E3A\u7A7A
10177=RAG\u914D\u7F6E\u4F53\u7684model_id\u4E0D\u80FD\u4E3A\u7A7A
10178=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u548Cmodel_id\u4E0D\u80FD\u4E3A\u7A7A
10179=\u6587\u4EF6\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
10180=\u6587\u4EF6\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A
10181=\u97F3\u8272\u514B\u9686\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
10182=\u97F3\u8272\u514B\u9686\u97F3\u9891\u4E0D\u5B58\u5728
10183=\u9ED8\u8BA4\u667A\u80FD\u4F53\u672A\u627E\u5230
@@ -0,0 +1,192 @@
#Deutsch
500=Server interne Ausnahme
401=Nicht autorisiert
403=Zugriff verweigert, keine Berechtigungen
10001={0} darf nicht leer sein
10002=Der Datensatz existiert bereits in der Datenbank
10003=Parameter abrufen fehlgeschlagen
10004=Die Kontonummer oder das Passwort ist falsch
10005=Konto wurde deaktiviert
10006=Eindeutige ID darf nicht leer sein
10007=Der Bestätigungscode ist falsch
10008=Zuerst Untermenü oder Schaltfläche löschen
10009=Das ursprüngliche Passwort ist falsch
10010=Das Konto oder Passwort ist falsch, Sie können es noch {0} Mal versuchen
10011=Die übergeordnete Abteilung hat eine falsche Wahl getroffen
10012=Oberes Menü kann nicht sich selbst sein
10013=Datenberechtigungsschnittstelle, die nur ein Map-Typ-Parameter sein kann
10014=Bitte löschen Sie zuerst die untergeordnete Abteilung
10015=Bitte löschen Sie zuerst den Benutzer unter der Abteilung
10016=Bereitstellung fehlgeschlagen, kein Prozess
10017=Das ModellDiagramm ist falsch, bitte überprüfen
10018=Export fehlgeschlagen, Modell-ID ist {0}
10019=Bitte laden Sie eine Datei hoch
10020=Token darf nicht leer sein
10021=Token ist ungültig, bitte melden Sie sich erneut an
10022=Das Konto wurde gesperrt
10023=Bitte laden Sie Dateien im Format zip, bar, bpmn, bpmn20.xml hoch
10024=Datei-Upload fehlgeschlagen {0}
10025=SMS-Sendung fehlgeschlagen {0}
10026=E-Mail-Vorlage existiert nicht
10027=Redis-Dienstausnahme
10028=Zeitgesteuerte Aufgabe fehlgeschlagen
10029=Darf keine illegalen Zeichen enthalten
10030=Das Passwort hat weniger als {0} Ziffern
10031=Das Passwort muss gleichzeitig aus Zahlen, Groß- und Kleinbuchstaben sowie Sonderzeichen bestehen
10032=Ausnahme beim Löschen dieser Daten
10033=Gerätebestätigungscode Fehler
10034=Parameterwert darf nicht leer sein
10035=Parametertyp darf nicht leer sein
10036=Nicht unterstützter Parametertyp
10037=Parameterwert muss eine gültige Zahl sein
10038=Parameterwert muss true oder false sein
10039=Parameterwert muss ein gültiges JSON-Array-Format sein
10040=Parameterwert muss ein gültiges JSON-Format sein
10041=Gerät nicht gefunden
10042={0}
10043=Löschen der Daten fehlgeschlagen
10044=Benutzer nicht angemeldet
10045=WebSocket-Verbindung fehlgeschlagen oder Zeitüberschreitung
10046=Stimmabdruck speichern fehlgeschlagen, bitte Administrator kontaktieren
10047=Tägliches SendeLimit erreicht
10048=Altes Passwort ist falsch
10049=Das eingestellte LLM ist nicht openai oder ollama
10050=Token-Generierung fehlgeschlagen
10051=Ressource nicht gefunden
10052=Standard-Agent nicht gefunden
10053=Agent nicht gefunden
10054=Stimmabdruck-Schnittstelle nicht konfiguriert, bitte konfigurieren Sie zuerst die Stimmabdruck-Schnittstellenadresse (server.voice_print) in der Parameterkonfiguration
10055=SMS-Sendung fehlgeschlagen
10056=SMS-Verbindung konnte nicht hergestellt werden
10057=Stimmabdruck für Agent konnte nicht erstellt werden
10058=Stimmabdruck für Agent konnte nicht aktualisiert werden
10059=Stimmabdruck für Agent konnte nicht gelöscht werden
10060=Sendung zu häufig, bitte versuchen Sie es nach {0} Sekunden erneut
10061=Aktivierungscode darf nicht leer sein
10062=Aktivierungscode Fehler
10063=Gerät bereits aktiviert
10064=Dieses Modell ist das Standardmodell, bitte setzen Sie zuerst ein anderes Modell als Standard
10065=Hinzufügen der Daten fehlgeschlagen
10066=Aktualisieren der Daten fehlgeschlagen
10067=Grafischer Bestätigungscode Fehler
10068=Mobilregistrierung nicht aktiviert, SMS-Bestätigungscode-Funktion kann nicht verwendet werden
10069=Benutzername ist keine Handynummer, bitte erneut eingeben
10070=Diese Handynummer wurde bereits registriert
10071=Die eingegebene Handynummer ist nicht registriert
10072=Normale Benutzerregistrierung derzeit nicht erlaubt
10073=Mobilregistrierung nicht aktiviert, Passwort-Wiederherstellungsfunktion kann nicht verwendet werden
10074=Das Format der eingegebenen Handynummer ist falsch
10075=Der eingegebene SMS-Bestätigungscode ist falsch
10076=Wörterbuchtyp existiert nicht
10077=Wörterbuchtypcode ist dupliziert
10078=Lesen der Ressource fehlgeschlagen
10079=LLM-Modell und Absichtserkennung, Parameterauswahl stimmt nicht überein
10080=Dieser Stimmabdruck gehört zu {0}, der bereits registriert ist, bitte wählen Sie eine andere Stimme
10081=Fehler beim Löschen des Stimmabdrucks aufgetreten
10082=Änderung nicht erlaubt, diese Stimme wurde bereits als Stimmabdruck registriert ({0})
10083=Fehler beim Ändern des Stimmabdrucks, bitte Administrator kontaktieren
10084=Stimmabdruck-Schnittstellenadresse Fehler, bitte gehen Sie zur Parameterverwaltung, um die Stimmabdruck-Schnittstellenadresse zu ändern
10085=Audiodaten gehören nicht zu diesem Agent
10086=Audiodaten sind leer, bitte überprüfen Sie hochgeladene Daten
10087=Stimmabdruck-Registrierung fehlgeschlagen, Anfrage nicht erfolgreich
10088=Stimmabdruck-Registrierung fehlgeschlagen, Anfrageverarbeitung fehlgeschlagen
10089=Stimmabdruck-Stornierung fehlgeschlagen, Anfrage nicht erfolgreich
10090=Stimmabdruck-Stornierung fehlgeschlagen, Anfrageverarbeitung fehlgeschlagen
10091=Modellanbieter existiert nicht
10092=Das konfigurierte LLM existiert nicht
10093=Diese Modellkonfiguration wird von Agent {0} referenziert und kann nicht gelöscht werden
10094=Dieses LLM-Modell wird von der Absichtserkennungskonfiguration referenziert und kann nicht gelöscht werden
10095=Ungültige Serveroperation
10096=Server WebSocket-Adresse nicht konfiguriert
10097=Ziel-WebSocket-Adresse existiert nicht
10098=WebSocket-Adressliste darf nicht leer sein
10099=WebSocket-Adresse darf nicht localhost oder 127.0.0.1 verwenden
10100=WebSocket-Adressformat ist falsch
10101=WebSocket-Verbindungstest fehlgeschlagen
10102=OTA-Adresse darf nicht leer sein
10103=OTA-Adresse darf nicht localhost oder 127.0.0.1 verwenden
10104=OTA-Adresse muss mit http oder https beginnen
10105=OTA-Adresse muss mit /ota/ enden
10106=OTA-Schnittstellenzugriff fehlgeschlagen
10107=OTA-Schnittstelle Rückgabeinhaltformat ist falsch
10108=OTA-Schnittstellenvalidierung fehlgeschlagen
10109=MCP-Adresse darf nicht leer sein
10110=MCP-Adresse darf nicht localhost oder 127.0.0.1 verwenden
10111=Keine gültige MCP-Adresse
10112=MCP-Schnittstellenzugriff fehlgeschlagen
10113=MCP-Schnittstelle Rückgabeinhaltformat ist falsch
10114=MCP-Schnittstellenvalidierung fehlgeschlagen
10115=Stimmabdruck-Schnittstellenadresse darf nicht leer sein
10116=Stimmabdruck-Schnittstellenadresse darf nicht localhost oder 127.0.0.1 verwenden
10117=Keine gültige Stimmabdruck-Schnittstellenadresse
10118=Stimmabdruck-Schnittstellenadresse muss mit http oder https beginnen
10119=Stimmabdruck-Schnittstellenzugriff fehlgeschlagen
10120=Stimmabdruck-Schnittstelle Rückgabeinhaltformat ist falsch
10121=Stimmabdruck-Schnittstellenvalidierung fehlgeschlagen
10122=MQTT-Geheimnis darf nicht leer sein
10123=Ihr MQTT-Geheimnis ist nicht sicher, es muss mindestens 8 Zeichen lang sein und muss sowohl Groß- als auch Kleinbuchstaben enthalten
10124=Ihr MQTT-Geheimnis ist nicht sicher, MQTT-Geheimnis muss sowohl Groß- als auch Kleinbuchstaben enthalten
10125=Ihr MQTT-Geheimnis enthält schwaches Passwort
10128=Wörterbuchlabel ist dupliziert
10129=SM2-Schlüssel nicht konfiguriert
10130=SM2-Entschlüsselung fehlgeschlagen
10131=modelType und provideCode dürfen nicht leer sein
10132=Keine Berechtigung, den Chat-Verlauf dieses Agents anzuzeigen
10133=Sitzungs-ID darf nicht leer sein
10134=Agent-ID darf nicht leer sein
10135=Chat-Verlauf-Download fehlgeschlagen
10136=Download-Link abgelaufen oder ungültig
10137=Download-Link ungültig
10138=Benutzer
10139=Agent
10140=Audio-Datei darf nicht leer sein
10141=Nur Audio-Dateien werden unterstützt
10142=Audio-Dateigröße darf 10MB nicht überschreiten
10143=Upload fehlgeschlagen
10144=Stimmenklon-Datensatz existiert nicht
10145=Stimmressourceninformationen dürfen nicht leer sein
10146=TTS-Plattformname darf nicht leer sein
10147=Stimmen-ID darf nicht leer sein
10148=Kontoinhaber darf nicht leer sein
10149=Zu löschende Stimmressourcen-ID darf nicht leer sein
10150=Sie haben keine Berechtigung, diesen Datensatz zu bearbeiten
10151=Bitte laden Sie zuerst eine Audio-Datei hoch
10152=Modellkonfiguration nicht gefunden
10153=Modelltyp nicht gefunden
10154=Training fehlgeschlagen: {0}
10155=Huoshan Engine-Konfiguration fehlt
10156=Antwortformat Fehler, BaseResp-Feld fehlt
10157=Anfrage fehlgeschlagen
10158=Stimme klonen:
10159=Stimmen-ID existiert bereits
10160=Huoshan Engine-Stimmen-ID-Formatfehler, muss mit S_ beginnen
10161=Mac-Adresse existiert bereits
10162=Modellanbieter existiert nicht
10163=Wissensbasis-Datensatz existiert nicht
10164=RAG-Konfiguration nicht gefunden
10165=RAG-Konfigurationstyp Fehler
10166=Standard-RAG-Konfiguration nicht gefunden
10167=RAG-API-Aufruf fehlgeschlagen: {0}
10168=Datei-Upload fehlgeschlagen
10169=Keine Berechtigung, diese Wissensbasis zu bearbeiten
10170=Wissensbasis-Name existiert bereits
10171=RAG-Konfiguration base_url darf nicht leer sein
10172=RAG-Konfiguration api_key darf nicht leer sein
10173=RAG-Konfiguration api_key darf keinen Platzhalter enthalten, bitte ersetzen Sie mit tatsächlichem API-Schlüssel
10174=RAG-Konfiguration base_url-Formatfehler, muss mit http oder https beginnen
10175=Mac-Adresse darf nicht leer sein
10176=RAG-Konfiguration dataset_id darf nicht leer sein
10177=RAG-Konfiguration model_id darf nicht leer sein
10178=RAG-Konfiguration dataset_id und model_id dürfen nicht leer sein
10179=Dateiname darf nicht leer sein
10180=Dateiinhalt darf nicht leer sein
10181=Stimmenklon-Name darf nicht leer sein
10182=Stimmenklon-Audio nicht gefunden
10183=Standard-Agent-Vorlage nicht gefunden
@@ -173,7 +173,20 @@
10164=RAG configuration not found
10165=RAG configuration type error
10166=Default RAG configuration not found
10167=RAG API interface error: {0}
10167=RAG API call failed: {0}
10168=Upload file failed
10169=No permission to operate this knowledge base
10170=Knowledge base name already exists
10170=Knowledge base name already exists
10171=RAG configuration base_url cannot be empty
10172=RAG configuration api_key cannot be empty
10173=RAG configuration api_key cannot contain placeholder, please replace with actual API key
10174=RAG configuration base_url format error, must start with http or https
10175=Mac address cannot be empty
10176=RAG configuration dataset_id cannot be empty
10177=RAG configuration model_id cannot be empty
10178=RAG configuration dataset_id and model_id cannot be empty
10179=File name cannot be empty
10180=File content cannot be empty
10181=Voice clone name cannot be empty
10182=Voice clone audio not found
10183=Default agent template not found
@@ -0,0 +1,192 @@
#Tiếng Việt
500=Ngoại lệ nội bộ máy chủ
401=Không được ủy quyền
403=Truy cập bị từ chối, không có quyền
10001={0} không thể để trống
10002=Bản ghi đã tồn tại trong cơ sở dữ liệu
10003=Không thể lấy tham số
10004=Số tài khoản hoặc mật khẩu không chính xác
10005=Tài khoản đã bị vô hiệu hóa
10006=ID duy nhất không thể để trống
10007=Mã xác minh không chính xác
10008=Trước tiên hãy xóa menu con hoặc nút
10009=Mật khẩu gốc không chính xác
10010=Tài khoản hoặc mật khẩu không chính xác, bạn có thể thử thêm {0} lần nữa
10011=Phòng ban cấp trên đã lựa chọn sai
10012=Menu trên không thể là chính nó
10013=Giao diện quyền dữ liệu, chỉ có thể là tham số kiểu Map
10014=Vui lòng xóa phòng ban cấp dưới trước
10015=Vui lòng xóa người dùng thuộc phòng ban trước
10016=Triển khai thất bại, không có quy trình
10017=Biểu đồ mô hình không chính xác, vui lòng kiểm tra
10018=Xuất thất bại, ID mô hình là {0}
10019=Vui lòng tải lên tệp
10020=Token không thể để trống
10021=Token không hợp lệ, vui lòng đăng nhập lại
10022=Tài khoản đã bị khóa
10023=Vui lòng tải lên tệp ở định dạng zip, bar, bpmn, bpmn20.xml
10024=Tải lên tệp {0} thất bại
10025=Gửi SMS {0} thất bại
10026=Mẫu email không tồn tại
10027=Ngoại lệ dịch vụ Redis
10028=Tác vụ hẹn giờ thất bại
10029=Không thể chứa ký tự không hợp lệ
10030=Mật khẩu ít hơn {0} chữ số
10031=Mật khẩu phải bao gồm số, chữ hoa, chữ thường và ký tự đặc biệt cùng một lúc
10032=Ngoại lệ khi xóa dữ liệu này
10033=Lỗi mã xác minh thiết bị
10034=Giá trị tham số không thể để trống
10035=Loại tham số không thể để trống
10036=Loại tham số không được hỗ trợ
10037=Giá trị tham số phải là số hợp lệ
10038=Giá trị tham số phải là true hoặc false
10039=Giá trị tham số phải là định dạng mảng JSON hợp lệ
10040=Giá trị tham số phải là định dạng JSON hợp lệ
10041=Không tìm thấy thiết bị
10042={0}
10043=Xóa dữ liệu thất bại
10044=Người dùng chưa đăng nhập
10045=Kết nối WebSocket thất bại hoặc hết thời gian chờ
10046=Không thể lưu dấu giọng nói, vui lòng liên hệ quản trị viên
10047=Đạt đến giới hạn gửi hàng ngày
10048=Mật khẩu cũ không chính xác
10049=LLM được đặt không phải là openai hoặc ollama
10050=Không thể tạo token
10051=Không tìm thấy tài nguyên
10052=Không tìm thấy agent mặc định
10053=Không tìm thấy agent
10054=Giao diện dấu giọng nói chưa được cấu hình, vui lòng cấu hình địa chỉ giao diện dấu giọng nói (server.voice_print) trong cấu hình tham số trước
10055=Gửi SMS thất bại
10056=Không thể thiết lập kết nối SMS
10057=Không thể tạo dấu giọng nói cho agent
10058=Không thể cập nhật dấu giọng nói cho agent
10059=Không thể xóa dấu giọng nói cho agent
10060=Gửi quá thường xuyên, vui lòng thử lại sau {0} giây
10061=Mã kích hoạt không thể để trống
10062=Lỗi mã kích hoạt
10063=Thiết bị đã được kích hoạt
10064=Mô hình này là mô hình mặc định, vui lòng đặt mô hình khác làm mặc định trước
10065=Thêm dữ liệu thất bại
10066=Cập nhật dữ liệu thất bại
10067=Lỗi mã xác minh đồ họa
10068=Đăng ký di động không được bật, không thể sử dụng chức năng mã xác minh SMS
10069=Tên người dùng không phải là số điện thoại di động, vui lòng nhập lại
10070=Số điện thoại di động này đã được đăng ký
10071=Số điện thoại di động đã nhập không được đăng ký
10072=Hiện không cho phép đăng ký người dùng thông thường
10073=Đăng ký di động không được bật, không thể sử dụng chức năng truy xuất mật khẩu
10074=Định dạng số điện thoại di động đã nhập không chính xác
10075=Mã xác minh SMS đã nhập không chính xác
10076=Loại từ điển không tồn tại
10077=Mã loại từ điển bị trùng lặp
10078=Đọc tài nguyên thất bại
10079=Mô hình LLM và nhận dạng ý định, lựa chọn tham số không khớp
10080=Dấu giọng nói này thuộc về {0} đã đăng ký, vui lòng chọn giọng nói khác
10081=Đã xảy ra lỗi khi xóa dấu giọng nói
10082=Không cho phép sửa đổi, giọng nói này đã được đăng ký làm dấu giọng nói ({0})
10083=Lỗi sửa đổi dấu giọng nói, vui lòng liên hệ quản trị viên
10084=Lỗi địa chỉ giao diện dấu giọng nói, vui lòng vào quản lý tham số để sửa đổi địa chỉ giao diện dấu giọng nói
10085=Dữ liệu âm thanh không thuộc về agent này
10086=Dữ liệu âm thanh trống, vui lòng kiểm tra dữ liệu đã tải lên
10087=Đăng ký dấu giọng nói thất bại, yêu cầu không thành công
10088=Đăng ký dấu giọng nói thất bại, xử lý yêu cầu thất bại
10089=Hủy dấu giọng nói thất bại, yêu cầu không thành công
10090=Hủy dấu giọng nói thất bại, xử lý yêu cầu thất bại
10091=Nhà cung cấp mô hình không tồn tại
10092=LLM được cấu hình không tồn tại
10093=Cấu hình mô hình này được tham chiếu bởi agent {0} và không thể xóa
10094=Mô hình LLM này được tham chiếu bởi cấu hình nhận dạng ý định và không thể xóa
10095=Thao tác máy chủ không hợp lệ
10096=Địa chỉ WebSocket máy chủ chưa được cấu hình
10097=Địa chỉ WebSocket mục tiêu không tồn tại
10098=Danh sách địa chỉ WebSocket không thể để trống
10099=Địa chỉ WebSocket không thể sử dụng localhost hoặc 127.0.0.1
10100=Định dạng địa chỉ WebSocket không chính xác
10101=Kiểm tra kết nối WebSocket thất bại
10102=Địa chỉ OTA không thể để trống
10103=Địa chỉ OTA không thể sử dụng localhost hoặc 127.0.0.1
10104=Địa chỉ OTA phải bắt đầu bằng http hoặc https
10105=Địa chỉ OTA phải kết thúc bằng /ota/
10106=Truy cập giao diện OTA thất bại
10107=Định dạng nội dung trả về giao diện OTA không chính xác
10108=Xác thực giao diện OTA thất bại
10109=Địa chỉ MCP không thể để trống
10110=Địa chỉ MCP không thể sử dụng localhost hoặc 127.0.0.1
10111=Không phải địa chỉ MCP hợp lệ
10112=Truy cập giao diện MCP thất bại
10113=Định dạng nội dung trả về giao diện MCP không chính xác
10114=Xác thực giao diện MCP thất bại
10115=Địa chỉ giao diện dấu giọng nói không thể để trống
10116=Địa chỉ giao diện dấu giọng nói không thể sử dụng localhost hoặc 127.0.0.1
10117=Không phải địa chỉ giao diện dấu giọng nói hợp lệ
10118=Địa chỉ giao diện dấu giọng nói phải bắt đầu bằng http hoặc https
10119=Truy cập giao diện dấu giọng nói thất bại
10120=Định dạng nội dung trả về giao diện dấu giọng nói không chính xác
10121=Xác thực giao diện dấu giọng nói thất bại
10122=Bí mật MQTT không thể để trống
10123=Bí mật MQTT của bạn không an toàn, cần ít nhất 8 ký tự và phải chứa cả chữ hoa và chữ thường
10124=Bí mật MQTT của bạn không an toàn, bí mật MQTT phải chứa cả chữ hoa và chữ thường
10125=Bí mật MQTT của bạn chứa mật khẩu yếu
10128=Nhãn từ điển bị trùng lặp
10129=Khóa SM2 chưa được cấu hình
10130=Giải mã SM2 thất bại
10131=modelType và provideCode không thể để trống
10132=Không có quyền xem lịch sử trò chuyện của agent này
10133=ID phiên không thể để trống
10134=ID agent không thể để trống
10135=Tải xuống lịch sử trò chuyện thất bại
10136=Liên kết tải xuống đã hết hạn hoặc không hợp lệ
10137=Liên kết tải xuống không hợp lệ
10138=Người dùng
10139=Agent
10140=Tệp âm thanh không thể để trống
10141=Chỉ hỗ trợ tệp âm thanh
10142=Kích thước tệp âm thanh không thể vượt quá 10MB
10143=Tải lên thất bại
10144=Bản ghi nhân bản giọng nói không tồn tại
10145=Thông tin tài nguyên giọng nói không thể để trống
10146=Tên nền tảng TTS không thể để trống
10147=ID giọng nói không thể để trống
10148=Tài khoản chủ sở hữu không thể để trống
10149=ID tài nguyên giọng nói cần xóa không thể để trống
10150=Bạn không có quyền thao tác bản ghi này
10151=Vui lòng tải lên tệp âm thanh trước
10152=Không tìm thấy cấu hình mô hình
10153=Không tìm thấy loại mô hình
10154=Đào tạo thất bại: {0}
10155=Thiếu cấu hình Huoshan Engine
10156=Lỗi định dạng phản hồi, thiếu trường BaseResp
10157=Yêu cầu thất bại
10158=Nhân bản giọng nói:
10159=ID giọng nói đã tồn tại
10160=Lỗi định dạng ID giọng nói Huoshan Engine, phải bắt đầu bằng S_
10161=Địa chỉ Mac đã tồn tại
10162=Nhà cung cấp mô hình không tồn tại
10163=Bản ghi cơ sở kiến thức không tồn tại
10164=Không tìm thấy cấu hình RAG
10165=Lỗi loại cấu hình RAG
10166=Không tìm thấy cấu hình RAG mặc định
10167=Gọi API RAG thất bại: {0}
10168=Tải lên tệp thất bại
10169=Không có quyền thao tác cơ sở kiến thức này
10170=Tên cơ sở kiến thức đã tồn tại
10171=Cấu hình RAG base_url không thể để trống
10172=Cấu hình RAG api_key không thể để trống
10173=Cấu hình RAG api_key không thể chứa trình giữ chỗ, vui lòng thay thế bằng khóa API thực tế
10174=Lỗi định dạng cấu hình RAG base_url, phải bắt đầu bằng http hoặc https
10175=Địa chỉ Mac không thể để trống
10176=Cấu hình RAG dataset_id không thể để trống
10177=Cấu hình RAG model_id không thể để trống
10178=Cấu hình RAG dataset_id và model_id không thể để trống
10179=Tên tệp không thể để trống
10180=Nội dung tệp không thể để trống
10181=Tên nhân bản giọng nói không thể để trống
10182=Không tìm thấy âm thanh nhân bản giọng nói
10183=Không tìm thấy mẫu agent mặc định
@@ -160,11 +160,11 @@
10151=\u8BF7\u5148\u4E0A\u4F20\u97F3\u9891\u6587\u4EF6
10152=\u6A21\u578B\u914D\u7F6E\u672A\u627E\u5230
10153=\u6A21\u578B\u7C7B\u578B\u672A\u627E\u5230
10154=\u8BAD\u7EC3\u5931\u8D25
10154=\u8BAD\u7EC3\u5931\u8D25: {0}
10155=\u706B\u5C71\u5F15\u64CE\u7F3A\u5C11\u914D\u7F6E
10156=\u54CD\u5E94\u683C\u5F0F\u9519\u8BEF\uFF0C\u7F3A\u5C11BaseResp\u5B57\u6BB5
10157=\u8BF7\u6C42\u5931\u8D25
10158=\u514B\u9686\u8272\u97F3:
10158=\u514B\u9686\u97F3\u8272:
10159=\u97F3\u8272ID\u5DF2\u5B58\u5728
10160=\u706B\u5C71\u5F15\u64CE\u97F3\u8272ID\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5S_\u5F00\u5934
10161=Mac\u5730\u5740\u5DF2\u5B58\u5728
@@ -173,7 +173,20 @@
10164=RAG\u914D\u7F6E\u672A\u627E\u5230
10165=RAG\u914D\u7F6E\u7C7B\u578B\u9519\u8BEF
10166=\u9ED8\u8BA4RAG\u914D\u7F6E\u672A\u627E\u5230
10167=RAG\u63A5\u53E3\u9519\u8BEF\uFF0C{0}
10167=RAG\u8C03\u7528\u5931\u8D25\uFF0C{0}
10168=\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25
10169=\u60A8\u6CA1\u6709\u6743\u9650\u64CD\u4F5C\u8BE5\u8BB0\u5F55
10170=\u77E5\u8BC6\u5E93\u540D\u79F0\u91CD\u590D
10170=\u77E5\u8BC6\u5E93\u540D\u79F0\u91CD\u590D
10171=RAG\u914D\u7F6E\u4F53\u7684base_url\u4E0D\u80FD\u4E3A\u7A7A
10172=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A
10173=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u66F4\u6362\u4E3A\u5728\u53D6\u7684API\u53C2\u6570
10174=RAG\u914D\u7F6E\u4F53\u7684base_url\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934
10175=mac\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A
10176=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u4E0D\u80FD\u4E3A\u7A7A
10177=RAG\u914D\u7F6E\u4F53\u7684model_id\u4E0D\u80FD\u4E3A\u7A7A
10178=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u548Cmodel_id\u4E0D\u80FD\u4E3A\u7A7A
10179=\u6587\u4EF6\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
10180=\u6587\u4EF6\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A
10181=\u97F3\u8272\u514B\u9686\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
10182=\u97F3\u8272\u514B\u9686\u97F3\u9891\u4E0D\u5B58\u5728
10183=\u9ED8\u8BA4\u667A\u80FD\u4F53\u672A\u627E\u5230
@@ -164,7 +164,7 @@
10155=\u706B\u5C71\u5F15\u64CE\u7F3A\u5C11appid\u6216access_token
10156=\u97FF\u61C9\u683C\u5F0F\u932F\u8AA4\uFF0C\u7F3A\u5C11BaseResp\u5B57\u6BB5
10157=\u8ACB\u6C42\u5931\u6557
10158=\u514B\u9686\u8A9E\u97F3:
10158=\u514b\u9686\u97f3\u8272:
10159=\u97F3\u8272ID\u5DF2\u5B58\u5728
10160=\u706B\u5C71\u5F15\u64CE\u97F3\u8272ID\u683C\u5F0F\u932F\u8AA4\uFF0C\u5FC5\u9808\u4EE5S_\u958B\u982D
10161=Mac\u5730\u5740\u5DF2\u5B58\u5728
@@ -173,7 +173,20 @@
10164=RAG\u914D\u7F6E\u672A\u627E\u5230
10165=RAG\u914D\u7F6E\u985E\u578B\u932F\u8AA4
10166=\u9810\u8A2DRAG\u914D\u7F6E\u672A\u627E\u5230
10167=RAG\u63A5\u53E3\u932F\u8AA4\uFF0C{0}
10167=\u0052\u0041\u0047\u8abf\u7528\u5931\u6557\uFF0C{0}
10168=\u4E0A\u50B3\u6587\u4EF6\u5931\u6557
10169=\u60A8\u6C92\u6709\u6B0A\u9650\u64CD\u4F5C\u8A72\u8A18\u9304
10170=\u77E5\u8B58\u5EAB\u540D\u7A31\u91CD\u8907
10171=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684base_url\u4E0D\u80FD\u4E3A\u7A7A
10172=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A
10173=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u66F4\u6362\u4E3A\u5728\u53D6\u7684API\u53C2\u6570
10174=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684base_url\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934
10175=mac\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A
10176=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684dataset_id\u4E0D\u80FD\u4E3A\u7A7A
10177=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684model_id\u4E0D\u80FD\u4E3A\u7A7A
10178=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684dataset_id\u548Cmodel_id\u4E0D\u80FD\u4E3A\u7A7A
10179=\u6587\u4ef6\u540d\u7a31\u4e0d\u80fd\u70ba\u7a7a
10180=\u6587\u4ef6\u5185\u5bb9\u4e0d\u80fd\u70ba\u7a7a
10181=\u97f3\u8272\u514b\u9686\u540d\u7a31\u4e0d\u80fd\u70ba\u7a7a
10182=\u97f3\u8272\u514b\u9686\u97f3\u983b\u4e0d\u5b58\u5728
10183=\u9ed8\u8ba4\u667a\u80fd\u4f53\u672a\u627e\u5230
@@ -0,0 +1,34 @@
#Deutsch
id.require=ID darf nicht leer sein
id.null=ID muss leer sein
sort.number=Der Sortierwert darf nicht kleiner als 0 sein
page.number=Der Seitenwert darf nicht kleiner als 0 sein
limit.number=Der Limit-Wert darf nicht kleiner als 0 sein
sysdict.type.require=Der Wörterbuchtyp darf nicht leer sein
sysdict.name.require=Der Wörterbuchname darf nicht leer sein
sysdict.label.require=Wörterbuch-Label darf nicht leer sein
sysparams.paramcode.require=Parameter-Code darf nicht leer sein
sysparams.paramvalue.require=Parameter-Werte dürfen nicht leer sein
sysparams.valuetype.require=Werttyp darf nicht leer sein
sysparams.valuetype.pattern=Werttyp muss string, number, boolean oder array sein
sysuser.username.require=Der Benutzername darf nicht leer sein
sysuser.password.require=Das Passwort darf nicht leer sein
sysuser.realname.require=Der echte Name darf nicht leer sein
sysuser.gender.range=Geschlecht liegt im Bereich von 0 bis 2
sysuser.email.error=Falsches E-Mail-Format
sysuser.deptId.require=Abteilungen dürfen nicht leer sein
sysuser.status.range=Status liegt im Bereich von 0 bis 1
sysuser.captcha.require=Das Captcha darf nicht leer sein
sysuser.uuid.require=Der eindeutige Identifikator darf nicht leer sein
timbre.languages.require=Die Sprache des Klangs darf nicht leer sein
timbre.name.require=Der Name des Klangs darf nicht leer sein
timbre.ttsModelId.require=Die TTS-Modell-ID des Klangs darf nicht leer sein
timbre.ttsVoice.require=Die TTS-Stimme des Klangs darf nicht leer sein
ota.device.not.found=Gerät nicht gefunden
ota.device.need.bind={0}
@@ -0,0 +1,34 @@
# Tiếng Việt
id.require=ID không được để trống
id.null=ID phải để trống
sort.number=Giá trị sắp xếp không thể nhỏ hơn 0
page.number=Giá trị trang không thể nhỏ hơn 0
limit.number=Giá trị giới hạn không thể nhỏ hơn 0
sysdict.type.require=Loại từ điển không được để trống
sysdict.name.require=Tên từ điển không được để trống
sysdict.label.require=Thẻ từ điển không được để trống
sysparams.paramcode.require=Mã tham số không được để trống
sysparams.paramvalue.require=Giá trị tham số không được để trống
sysparams.valuetype.require=Loại giá trị không được để trống
sysparams.valuetype.pattern=Loại giá trị phải là chuỗi, số, boolean hoặc mảng
sysuser.username.require=Tên người dùng không được để trống
sysuser.password.require=Mật khẩu không được để trống
sysuser.realname.require=Tên thật không được để trống
sysuser.gender.range=Giới tính phải từ 0 đến 2
sysuser.email.error=Định dạng email không chính xác
sysuser.deptId.require=Phòng ban không được để trống
sysuser.status.range=Trạng thái phải từ 0 đến 1
sysuser.captcha.require=Mã xác thực không được để trống
sysuser.uuid.require=Định danh duy nhất không được để trống
timbre.languages.require=Ngôn ngữ của âm sắc không được để trống
timbre.name.require=Tên âm sắc không được để trống
timbre.ttsModelId.require=ID mô hình TTS của âm sắc không được để trống
timbre.ttsVoice.require=Giọng TTS của âm sắc không được để trống
ota.device.not.found=Không tìm thấy thiết bị
ota.device.need.bind={0}
@@ -3,8 +3,8 @@ id.require=ID\u4E0D\u80FD\u4E3A\u7A7A
id.null=ID\u5FC5\u987B\u4E3A\u7A7A
sort.number=\u6392\u5E8F\u503C\u4E0D\u80FD\u5C0F\u4E8E0
page.number=\u9801\u6578\u4E0D\u80FD\u5C0F\u4E8E0
limit.number=\u5217\u6578\u4E0D\u80FD\u5C0F\u4E8E0
page.number=\u9875\u6570\u4E0D\u80FD\u5C0F\u4E8E0
limit.number=\u5217\u6570\u4E0D\u80FD\u5C0F\u4E8E0
sysdict.type.require=\u5B57\u5178\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
sysdict.name.require=\u5B57\u5178\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
@@ -25,10 +25,10 @@ sysuser.status.range=\u72B6\u6001\u53D6\u503C\u8303\u56F40~1
sysuser.captcha.require=\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysuser.uuid.require=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
timbre.languages.require=\u97F3\u8272\u7684\u8A9E\u8A00\u4E0D\u53EF\u4EE5\u70BA\u7A7A
timbre.name.require=\u97F3\u8272\u7684\u540D\u7A31\u4E0D\u53EF\u4EE5\u70BA\u7A7A
timbre.ttsModelId.require=\u97F3\u8272\u7684tts\u4E3B\u9375\u4E0D\u53EF\u4EE5\u70BA\u7A7A
timbre.ttsVoice.require=\u97F3\u8272\u7684\u7DE8\u78BC\u4E0D\u53EF\u4EE5\u70BA\u7A7A
timbre.languages.require=\u97F3\u8272\u7684\u8BED\u8A00\u4E0D\u80FD\u4E3A\u7A7A
timbre.name.require=\u97F3\u8272\u7684\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
timbre.ttsModelId.require=\u97F3\u8272\u7684tts\u4E3B\u952E\u4E0D\u80FD\u4E3A\u7A7A
timbre.ttsVoice.require=\u97F3\u8272\u7684\u7F16\u7801\u4E0D\u80FD\u4E3A\u7A7A
ota.device.not.found=\u8A2D\u5099\u672A\u627E\u5230
ota.device.not.found=\u8BBE\u5907\u672A\u627E\u5230
ota.device.need.bind={0}
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.knowledge.dao.KnowledgeBaseDao">
<resultMap id="BaseResultMap" type="xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="datasetId" column="dataset_id" jdbcType="VARCHAR"/>
<result property="ragModelId" column="rag_model_id" jdbcType="VARCHAR"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="description" column="description" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="TINYINT"/>
<result property="creator" column="creator" jdbcType="BIGINT"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updater" column="updater" jdbcType="BIGINT"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 根据知识库ID删除相关的插件映射记录 -->
<delete id="deletePluginMappingByKnowledgeBaseId">
DELETE FROM ai_agent_plugin_mapping
WHERE plugin_id = #{knowledgeBaseId}
</delete>
</mapper>