package com.vincent.rsf.server.ai.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.ai.config.AiDefaults; import com.vincent.rsf.server.ai.entity.AiParam; import com.vincent.rsf.server.ai.mapper.AiParamMapper; import com.vincent.rsf.server.ai.service.AiParamService; import com.vincent.rsf.server.system.enums.StatusType; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @Service("aiParamService") public class AiParamServiceImpl extends ServiceImpl implements AiParamService { @Override public AiParam getActiveParam(Long tenantId) { ensureTenantId(tenantId); AiParam aiParam = this.getOne(new LambdaQueryWrapper() .eq(AiParam::getTenantId, tenantId) .eq(AiParam::getStatus, StatusType.ENABLE.val) .eq(AiParam::getDeleted, 0) .last("limit 1")); if (aiParam == null) { throw new CoolException("未找到启用中的 AI 参数配置"); } return aiParam; } @Override public void validateBeforeSave(AiParam aiParam, Long tenantId) { ensureTenantId(tenantId); aiParam.setTenantId(tenantId); fillDefaults(aiParam); ensureBaseFields(aiParam); ensureSingleActive(tenantId, null, aiParam.getStatus()); } @Override public void validateBeforeUpdate(AiParam aiParam, Long tenantId) { ensureTenantId(tenantId); fillDefaults(aiParam); if (aiParam.getId() == null) { throw new CoolException("AI 参数 ID 不能为空"); } AiParam current = requireOwnedRecord(aiParam.getId(), tenantId); aiParam.setTenantId(current.getTenantId()); ensureBaseFields(aiParam); ensureSingleActive(tenantId, aiParam.getId(), aiParam.getStatus()); } private void ensureBaseFields(AiParam aiParam) { if (!StringUtils.hasText(aiParam.getName())) { throw new CoolException("AI 参数名称不能为空"); } if (!StringUtils.hasText(aiParam.getProviderType())) { aiParam.setProviderType(AiDefaults.PROVIDER_OPENAI_COMPATIBLE); } if (!StringUtils.hasText(aiParam.getBaseUrl())) { throw new CoolException("AI Base URL 不能为空"); } if (!StringUtils.hasText(aiParam.getApiKey())) { throw new CoolException("AI API Key 不能为空"); } if (!StringUtils.hasText(aiParam.getModel())) { throw new CoolException("AI 模型不能为空"); } } private void ensureSingleActive(Long tenantId, Long selfId, Integer status) { if (status == null || status != StatusType.ENABLE.val) { return; } LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(AiParam::getTenantId, tenantId) .eq(AiParam::getStatus, StatusType.ENABLE.val) .eq(AiParam::getDeleted, 0); if (selfId != null) { wrapper.ne(AiParam::getId, selfId); } if (this.count(wrapper) > 0) { throw new CoolException("同一租户仅允许一条启用中的 AI 参数配置"); } } private AiParam requireOwnedRecord(Long id, Long tenantId) { AiParam aiParam = this.getOne(new LambdaQueryWrapper() .eq(AiParam::getId, id) .eq(AiParam::getTenantId, tenantId) .eq(AiParam::getDeleted, 0) .last("limit 1")); if (aiParam == null) { throw new CoolException("AI 参数不存在或无权访问"); } return aiParam; } private void ensureTenantId(Long tenantId) { if (tenantId == null) { throw new CoolException("当前租户不存在"); } } private void fillDefaults(AiParam aiParam) { if (!StringUtils.hasText(aiParam.getProviderType())) { aiParam.setProviderType(AiDefaults.PROVIDER_OPENAI_COMPATIBLE); } if (aiParam.getTemperature() == null) { aiParam.setTemperature(AiDefaults.DEFAULT_TEMPERATURE); } if (aiParam.getTopP() == null) { aiParam.setTopP(AiDefaults.DEFAULT_TOP_P); } if (aiParam.getTimeoutMs() == null) { aiParam.setTimeoutMs(AiDefaults.DEFAULT_TIMEOUT_MS); } if (aiParam.getStreamingEnabled() == null) { aiParam.setStreamingEnabled(Boolean.TRUE); } if (aiParam.getStatus() == null) { aiParam.setStatus(StatusType.ENABLE.val); } } }