zhou zhou
18 小时以前 82624affb0251b75b62b35567d3eb260c06efe78
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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.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, 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);
        }
        return aiPrompt;
    }
 
    @Override
    public void validateBeforeSave(AiPrompt aiPrompt, Long tenantId) {
        ensureTenantId(tenantId);
        aiPrompt.setTenantId(tenantId);
        ensureRequiredFields(aiPrompt);
        ensureUniqueCode(aiPrompt.getCode(), tenantId, null);
    }
 
    @Override
    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(), 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) {
        if (!StringUtils.hasText(aiPrompt.getName())) {
            throw new CoolException("Prompt 名称不能为空");
        }
        if (!StringUtils.hasText(aiPrompt.getCode())) {
            throw new CoolException("Prompt 编码不能为空");
        }
        if (!StringUtils.hasText(aiPrompt.getSystemPrompt())) {
            throw new CoolException("系统 Prompt 不能为空");
        }
        if (aiPrompt.getStatus() == null) {
            aiPrompt.setStatus(StatusType.ENABLE.val);
        }
    }
 
    private void ensureUniqueCode(String code, Long tenantId, Long selfId) {
        LambdaQueryWrapper<AiPrompt> wrapper = new LambdaQueryWrapper<AiPrompt>()
                .eq(AiPrompt::getTenantId, tenantId)
                .eq(AiPrompt::getCode, code)
                .eq(AiPrompt::getDeleted, 0);
        if (selfId != null) {
            wrapper.ne(AiPrompt::getId, selfId);
        }
        if (this.count(wrapper) > 0) {
            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("当前租户不存在");
        }
    }
}