|
|
|
@ -42,39 +42,45 @@ public class AiModelConfigService { |
|
|
|
* @return 分页结果 |
|
|
|
*/ |
|
|
|
public Map<String, Object> listConfigs(String appType, int page, int size) { |
|
|
|
// 构建查询条件 |
|
|
|
StringBuilder whereClause = new StringBuilder("WHERE is_delete = false "); |
|
|
|
List<Object> params = new ArrayList<>(); |
|
|
|
|
|
|
|
// 构建查询条件(共用基础条件) |
|
|
|
LambdaQueryWrapper<AiModelConfig> baseCondition = new LambdaQueryWrapper<>(); |
|
|
|
if (appType != null && !appType.isEmpty()) { |
|
|
|
whereClause.append(" AND app_type = ? "); |
|
|
|
params.add(appType); |
|
|
|
baseCondition.eq(AiModelConfig::getAppType, appType); |
|
|
|
} |
|
|
|
|
|
|
|
// 查询总数 |
|
|
|
String countSql = "SELECT COUNT(*) FROM ai_model_config " + whereClause; |
|
|
|
Long total = jdbcTemplate.queryForObject(countSql, Long.class, params.toArray()); |
|
|
|
// 查询总数(不含排序和分页) |
|
|
|
Long total = aiModelConfigMapper.selectCount(baseCondition); |
|
|
|
if (total == null) total = 0L; |
|
|
|
|
|
|
|
// 查询列表(按 priority 降序、create_time 降序) |
|
|
|
String listSql = "SELECT * FROM ai_model_config " + whereClause + |
|
|
|
" ORDER BY priority DESC, create_time DESC LIMIT ? OFFSET ?"; |
|
|
|
|
|
|
|
List<Object> queryParams = new ArrayList<>(params); |
|
|
|
queryParams.add(size); |
|
|
|
queryParams.add((page - 1) * size); |
|
|
|
|
|
|
|
List<Map<String, Object>> records = jdbcTemplate.queryForList(listSql, queryParams.toArray()); |
|
|
|
// 查询列表(带排序和分页) |
|
|
|
LambdaQueryWrapper<AiModelConfig> listWrapper = new LambdaQueryWrapper<>(); |
|
|
|
if (appType != null && !appType.isEmpty()) { |
|
|
|
listWrapper.eq(AiModelConfig::getAppType, appType); |
|
|
|
} |
|
|
|
listWrapper.orderByDesc(AiModelConfig::getPriority) |
|
|
|
.orderByDesc(AiModelConfig::getCreateTime); |
|
|
|
listWrapper.last("LIMIT " + size + " OFFSET " + ((page - 1) * size)); |
|
|
|
List<AiModelConfig> records = aiModelConfigMapper.selectList(listWrapper); |
|
|
|
|
|
|
|
// 脱敏 API Key 并格式化结果 |
|
|
|
// 脱敏 API Key |
|
|
|
List<Map<String, Object>> formattedRecords = new ArrayList<>(); |
|
|
|
for (Map<String, Object> record : records) { |
|
|
|
Map<String, Object> formatted = new LinkedHashMap<>(record); |
|
|
|
// API Key 脱敏 |
|
|
|
String apiKey = (String) record.get("api_key"); |
|
|
|
if (apiKey != null) { |
|
|
|
formatted.put("api_key", maskApiKey(apiKey)); |
|
|
|
} |
|
|
|
for (AiModelConfig record : records) { |
|
|
|
Map<String, Object> formatted = new LinkedHashMap<>(); |
|
|
|
formatted.put("id", record.getId()); |
|
|
|
formatted.put("name", record.getName()); |
|
|
|
formatted.put("app_type", record.getAppType()); |
|
|
|
formatted.put("provider", record.getProvider()); |
|
|
|
formatted.put("model_name", record.getModelName()); |
|
|
|
formatted.put("temperature", record.getTemperature()); |
|
|
|
formatted.put("max_tokens", record.getMaxTokens()); |
|
|
|
formatted.put("base_url", record.getBaseUrl()); |
|
|
|
formatted.put("api_key", maskApiKey(record.getApiKey())); |
|
|
|
formatted.put("extra_config", record.getExtraConfig()); |
|
|
|
formatted.put("is_active", record.getIsActive()); |
|
|
|
formatted.put("priority", record.getPriority()); |
|
|
|
formatted.put("description", record.getDescription()); |
|
|
|
formatted.put("create_time", record.getCreateTime()); |
|
|
|
formatted.put("update_time", record.getUpdateTime()); |
|
|
|
formattedRecords.add(formatted); |
|
|
|
} |
|
|
|
|
|
|
|
@ -98,9 +104,27 @@ public class AiModelConfigService { |
|
|
|
public AiModelConfig getConfigDetail(Long id) { |
|
|
|
AiModelConfig config = aiModelConfigMapper.selectById(id); |
|
|
|
if (config != null) { |
|
|
|
config.setApiKey(maskApiKey(config.getApiKey())); |
|
|
|
// 防御性拷贝:不直接修改 MyBatis 一级缓存中的实体对象,避免污染后续查询 |
|
|
|
AiModelConfig masked = AiModelConfig.builder() |
|
|
|
.id(config.getId()) |
|
|
|
.name(config.getName()) |
|
|
|
.appType(config.getAppType()) |
|
|
|
.provider(config.getProvider()) |
|
|
|
.apiKey(maskApiKey(config.getApiKey())) |
|
|
|
.modelName(config.getModelName()) |
|
|
|
.temperature(config.getTemperature()) |
|
|
|
.maxTokens(config.getMaxTokens()) |
|
|
|
.baseUrl(config.getBaseUrl()) |
|
|
|
.extraConfig(config.getExtraConfig()) |
|
|
|
.isActive(config.getIsActive()) |
|
|
|
.priority(config.getPriority()) |
|
|
|
.description(config.getDescription()) |
|
|
|
.createTime(config.getCreateTime()) |
|
|
|
.updateTime(config.getUpdateTime()) |
|
|
|
.build(); |
|
|
|
return masked; |
|
|
|
} |
|
|
|
return config; |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
// ==================== 获取活跃配置 ==================== |
|
|
|
@ -197,22 +221,21 @@ public class AiModelConfigService { |
|
|
|
.build(); |
|
|
|
validateModelTypeMatch(merged); |
|
|
|
|
|
|
|
// 如果要激活此配置,先禁用同类型的其他配置 |
|
|
|
// 如果要激活此配置,先禁用目标类型的其他配置 |
|
|
|
// 目标类型 = 新 appType(如有修改)或原 appType |
|
|
|
if (Boolean.TRUE.equals(config.getIsActive())) { |
|
|
|
deactivateByAppType(existing.getAppType()); |
|
|
|
} |
|
|
|
|
|
|
|
// 如果 app_type 被修改且新配置为活跃,需要禁用新类型的其他配置 |
|
|
|
if (config.getAppType() != null && !config.getAppType().equals(existing.getAppType()) |
|
|
|
&& Boolean.TRUE.equals(config.getIsActive())) { |
|
|
|
deactivateByAppType(config.getAppType()); |
|
|
|
String targetAppType = config.getAppType() != null ? config.getAppType() : existing.getAppType(); |
|
|
|
deactivateByAppType(targetAppType); |
|
|
|
} |
|
|
|
|
|
|
|
// 设置 ID 确保更新正确 |
|
|
|
config.setId(id); |
|
|
|
// 防御:trim API Key 前后空白 |
|
|
|
// 防御:trim API Key 前后空白,空字符串置为 null 避免覆盖已有值 |
|
|
|
if (config.getApiKey() != null) { |
|
|
|
config.setApiKey(config.getApiKey().trim()); |
|
|
|
if (config.getApiKey().isEmpty()) { |
|
|
|
config.setApiKey(null); |
|
|
|
} |
|
|
|
} |
|
|
|
aiModelConfigMapper.updateById(config); |
|
|
|
// JSONB 字段 MyBatis Plus typeHandler 可能不触发,用 JdbcTemplate 显式写入保证可靠 |
|
|
|
@ -278,6 +301,7 @@ public class AiModelConfigService { |
|
|
|
* |
|
|
|
* @param id 配置ID |
|
|
|
*/ |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
public void deleteConfig(Long id) { |
|
|
|
AiModelConfig config = aiModelConfigMapper.selectById(id); |
|
|
|
if (config == null) { |
|
|
|
@ -362,7 +386,8 @@ public class AiModelConfigService { |
|
|
|
json, id); |
|
|
|
log.debug("持久化 extraConfig: id={}, extraConfig={}", id, json); |
|
|
|
} catch (Exception e) { |
|
|
|
log.warn("持久化 extraConfig 失败: id={}, error={}", id, e.getMessage()); |
|
|
|
log.error("持久化 extraConfig 失败: id={}, error={}", id, e.getMessage()); |
|
|
|
throw new RuntimeException("持久化扩展配置失败: " + e.getMessage(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -450,6 +475,10 @@ public class AiModelConfigService { |
|
|
|
* @param priority 新优先级值 |
|
|
|
*/ |
|
|
|
public void updatePriority(Long id, Integer priority) { |
|
|
|
AiModelConfig config = aiModelConfigMapper.selectById(id); |
|
|
|
if (config == null) { |
|
|
|
throw new RuntimeException("配置不存在"); |
|
|
|
} |
|
|
|
LambdaUpdateWrapper<AiModelConfig> updateWrapper = new LambdaUpdateWrapper<>(); |
|
|
|
updateWrapper.eq(AiModelConfig::getId, id) |
|
|
|
.set(AiModelConfig::getPriority, priority); |
|
|
|
|