| | |
| | | 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.dto.AiPromptPreviewDto; |
| | | import com.vincent.rsf.server.ai.dto.AiPromptPreviewRequest; |
| | | import com.vincent.rsf.server.ai.entity.AiPrompt; |
| | | import com.vincent.rsf.server.ai.mapper.AiPromptMapper; |
| | | import com.vincent.rsf.server.ai.store.AiConfigCacheStore; |
| | | import com.vincent.rsf.server.ai.store.AiConversationCacheStore; |
| | | import com.vincent.rsf.server.ai.service.AiPromptService; |
| | | import com.vincent.rsf.server.system.enums.StatusType; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | @Service("aiPromptService") |
| | | @RequiredArgsConstructor |
| | | public class AiPromptServiceImpl extends ServiceImpl<AiPromptMapper, AiPrompt> implements AiPromptService { |
| | | |
| | | private final AiPromptRenderSupport aiPromptRenderSupport; |
| | | private final AiConfigCacheStore aiConfigCacheStore; |
| | | private final AiConversationCacheStore aiConversationCacheStore; |
| | | |
| | | @Override |
| | | public AiPrompt getActivePrompt(String code) { |
| | | public AiPrompt getActivePrompt(String code, Long tenantId) { |
| | | ensureTenantId(tenantId); |
| | | AiPrompt aiPrompt = this.getOne(new LambdaQueryWrapper<AiPrompt>() |
| | | .eq(AiPrompt::getTenantId, tenantId) |
| | | .eq(AiPrompt::getCode, code) |
| | | .eq(AiPrompt::getStatus, StatusType.ENABLE.val) |
| | | .eq(AiPrompt::getDeleted, 0) |
| | | .last("limit 1")); |
| | | if (aiPrompt == null) { |
| | | throw new CoolException("未找到启用中的 Prompt:" + code); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void validateBeforeSave(AiPrompt aiPrompt) { |
| | | public void validateBeforeSave(AiPrompt aiPrompt, Long tenantId) { |
| | | ensureTenantId(tenantId); |
| | | aiPrompt.setTenantId(tenantId); |
| | | ensureRequiredFields(aiPrompt); |
| | | ensureUniqueCode(aiPrompt.getCode(), null); |
| | | ensureUniqueCode(aiPrompt.getCode(), tenantId, null); |
| | | } |
| | | |
| | | @Override |
| | | public void validateBeforeUpdate(AiPrompt aiPrompt) { |
| | | public void validateBeforeUpdate(AiPrompt aiPrompt, Long tenantId) { |
| | | ensureTenantId(tenantId); |
| | | if (aiPrompt.getId() == null) { |
| | | throw new CoolException("Prompt ID 不能为空"); |
| | | } |
| | | AiPrompt current = requireOwnedRecord(aiPrompt.getId(), tenantId); |
| | | aiPrompt.setTenantId(current.getTenantId()); |
| | | ensureRequiredFields(aiPrompt); |
| | | ensureUniqueCode(aiPrompt.getCode(), aiPrompt.getId()); |
| | | ensureUniqueCode(aiPrompt.getCode(), tenantId, aiPrompt.getId()); |
| | | } |
| | | |
| | | @Override |
| | | public AiPromptPreviewDto renderPreview(AiPromptPreviewRequest request, Long tenantId) { |
| | | ensureTenantId(tenantId); |
| | | if (request == null) { |
| | | throw new CoolException("Prompt 预览参数不能为空"); |
| | | } |
| | | if (!StringUtils.hasText(request.getSystemPrompt())) { |
| | | throw new CoolException("系统 Prompt 不能为空"); |
| | | } |
| | | return aiPromptRenderSupport.render( |
| | | request.getSystemPrompt(), |
| | | request.getUserPromptTemplate(), |
| | | request.getInput(), |
| | | request.getMetadata() |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public boolean save(AiPrompt entity) { |
| | | boolean saved = super.save(entity); |
| | | if (saved && entity != null && entity.getTenantId() != null) { |
| | | aiConfigCacheStore.evictTenantConfigCaches(entity.getTenantId()); |
| | | aiConversationCacheStore.evictTenantRuntimeCaches(entity.getTenantId()); |
| | | } |
| | | return saved; |
| | | } |
| | | |
| | | @Override |
| | | public boolean updateById(AiPrompt entity) { |
| | | boolean updated = super.updateById(entity); |
| | | if (updated && entity != null && entity.getTenantId() != null) { |
| | | aiConfigCacheStore.evictTenantConfigCaches(entity.getTenantId()); |
| | | aiConversationCacheStore.evictTenantRuntimeCaches(entity.getTenantId()); |
| | | } |
| | | return updated; |
| | | } |
| | | |
| | | @Override |
| | | public boolean removeByIds(java.util.Collection<?> list) { |
| | | java.util.List<java.io.Serializable> ids = list == null ? java.util.List.of() : list.stream() |
| | | .filter(java.util.Objects::nonNull) |
| | | .map(item -> (java.io.Serializable) item) |
| | | .toList(); |
| | | java.util.List<AiPrompt> records = this.listByIds(ids); |
| | | boolean removed = super.removeByIds(list); |
| | | if (removed) { |
| | | records.stream() |
| | | .map(AiPrompt::getTenantId) |
| | | .filter(java.util.Objects::nonNull) |
| | | .distinct() |
| | | .forEach(tenantId -> { |
| | | aiConfigCacheStore.evictTenantConfigCaches(tenantId); |
| | | aiConversationCacheStore.evictTenantRuntimeCaches(tenantId); |
| | | }); |
| | | } |
| | | return removed; |
| | | } |
| | | |
| | | private void ensureRequiredFields(AiPrompt aiPrompt) { |
| | |
| | | } |
| | | } |
| | | |
| | | private void ensureUniqueCode(String code, Long selfId) { |
| | | private void ensureUniqueCode(String code, Long tenantId, Long selfId) { |
| | | LambdaQueryWrapper<AiPrompt> wrapper = new LambdaQueryWrapper<AiPrompt>() |
| | | .eq(AiPrompt::getCode, code); |
| | | .eq(AiPrompt::getTenantId, tenantId) |
| | | .eq(AiPrompt::getCode, code) |
| | | .eq(AiPrompt::getDeleted, 0); |
| | | if (selfId != null) { |
| | | wrapper.ne(AiPrompt::getId, selfId); |
| | | } |
| | |
| | | throw new CoolException("Prompt 编码已存在"); |
| | | } |
| | | } |
| | | |
| | | private AiPrompt requireOwnedRecord(Long id, Long tenantId) { |
| | | AiPrompt aiPrompt = this.getOne(new LambdaQueryWrapper<AiPrompt>() |
| | | .eq(AiPrompt::getId, id) |
| | | .eq(AiPrompt::getTenantId, tenantId) |
| | | .eq(AiPrompt::getDeleted, 0) |
| | | .last("limit 1")); |
| | | if (aiPrompt == null) { |
| | | throw new CoolException("Prompt 不存在或无权访问"); |
| | | } |
| | | return aiPrompt; |
| | | } |
| | | |
| | | private void ensureTenantId(Long tenantId) { |
| | | if (tenantId == null) { |
| | | throw new CoolException("当前租户不存在"); |
| | | } |
| | | } |
| | | } |