From 83af5944a32527fd8aa83537dd840d428af7f577 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 16 三月 2026 13:25:15 +0800
Subject: [PATCH] #
---
src/main/java/com/zy/ai/service/impl/AiPromptTemplateServiceImpl.java | 286 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 243 insertions(+), 43 deletions(-)
diff --git a/src/main/java/com/zy/ai/service/impl/AiPromptTemplateServiceImpl.java b/src/main/java/com/zy/ai/service/impl/AiPromptTemplateServiceImpl.java
index 004d3fb..10780e6 100644
--- a/src/main/java/com/zy/ai/service/impl/AiPromptTemplateServiceImpl.java
+++ b/src/main/java/com/zy/ai/service/impl/AiPromptTemplateServiceImpl.java
@@ -3,9 +3,13 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.ai.entity.AiPromptBlock;
import com.zy.ai.entity.AiPromptTemplate;
+import com.zy.ai.enums.AiPromptBlockType;
import com.zy.ai.enums.AiPromptScene;
+import com.zy.ai.mapper.AiPromptBlockMapper;
import com.zy.ai.mapper.AiPromptTemplateMapper;
+import com.zy.ai.service.AiPromptComposerService;
import com.zy.ai.service.AiPromptTemplateService;
import com.zy.ai.utils.AiPromptUtils;
import lombok.RequiredArgsConstructor;
@@ -14,8 +18,10 @@
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
-import java.util.Date;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -24,7 +30,20 @@
@RequiredArgsConstructor
public class AiPromptTemplateServiceImpl extends ServiceImpl<AiPromptTemplateMapper, AiPromptTemplate> implements AiPromptTemplateService {
+ private static final Comparator<AiPromptBlock> BLOCK_SORT = (a, b) -> {
+ int sa = a != null && a.getSortNo() != null ? a.getSortNo() : Integer.MAX_VALUE;
+ int sb = b != null && b.getSortNo() != null ? b.getSortNo() : Integer.MAX_VALUE;
+ if (sa != sb) {
+ return sa - sb;
+ }
+ long ia = a != null && a.getId() != null ? a.getId() : Long.MAX_VALUE;
+ long ib = b != null && b.getId() != null ? b.getId() : Long.MAX_VALUE;
+ return Long.compare(ia, ib);
+ };
+
private final AiPromptUtils aiPromptUtils;
+ private final AiPromptBlockMapper aiPromptBlockMapper;
+ private final AiPromptComposerService aiPromptComposerService;
@Override
public AiPromptTemplate resolvePublished(String sceneCode) {
@@ -33,18 +52,15 @@
if (prompt == null) {
synchronized (("ai_prompt_scene_init_" + scene.getCode()).intern()) {
prompt = findPublished(scene.getCode());
- if (prompt == null) {
- if (findLatest(scene.getCode()) == null) {
- prompt = ensurePublishedScene(scene);
- }
+ if (prompt == null && findLatest(scene.getCode()) == null) {
+ prompt = ensurePublishedScene(scene);
}
}
}
-
if (prompt == null) {
throw new IllegalStateException("褰撳墠鍦烘櫙娌℃湁宸插彂甯� Prompt锛宻ceneCode=" + scene.getCode());
}
- return prompt;
+ return enrichTemplate(prompt);
}
@Override
@@ -54,9 +70,9 @@
throw new IllegalArgumentException("Prompt 涓嶈兘涓虹┖");
}
AiPromptScene scene = requireScene(template.getSceneCode());
- String content = template.getContent();
- if (content == null || content.trim().isEmpty()) {
- throw new IllegalArgumentException("Prompt 鍐呭涓嶈兘涓虹┖");
+ String compiled = buildCompiledPrompt(template);
+ if (compiled.isEmpty()) {
+ throw new IllegalArgumentException("Prompt 鍒嗘鍐呭涓嶈兘涓虹┖");
}
if (template.getId() == null) {
@@ -65,12 +81,13 @@
entity.setName(defaultName(scene, version, template.getName()));
entity.setSceneCode(scene.getCode());
entity.setVersion(version);
- entity.setContent(content);
+ entity.setContent(compiled);
entity.setStatus(normalizeStatus(template.getStatus()));
entity.setPublished((short) 0);
entity.setCreatedBy(operatorUserId);
entity.setMemo(trim(template.getMemo()));
this.save(entity);
+ upsertBlocks(entity.getId(), extractBlockContentMap(template));
return entity;
}
@@ -82,14 +99,15 @@
throw new IllegalArgumentException("涓嶅厑璁镐慨鏀� Prompt 鎵�灞炲満鏅�");
}
if (Short.valueOf((short) 1).equals(db.getPublished())) {
- throw new IllegalArgumentException("宸插彂甯� Prompt 涓嶅厑璁哥洿鎺ヤ慨鏀癸紝璇锋柊寤虹増鏈悗鍐嶅彂甯�");
+ throw new IllegalArgumentException("宸插彂甯� Prompt 涓嶅厑璁哥洿鎺ヤ慨鏀癸紝璇峰厛鍙栨秷鍙戝竷鍚庡啀淇濆瓨");
}
db.setName(defaultName(scene, db.getVersion() == null ? 1 : db.getVersion(), template.getName()));
- db.setContent(content);
+ db.setContent(compiled);
db.setStatus(normalizeStatus(template.getStatus()));
db.setMemo(trim(template.getMemo()));
this.updateById(db);
+ upsertBlocks(db.getId(), extractBlockContentMap(template));
return db;
}
@@ -103,7 +121,9 @@
if (db == null) {
throw new IllegalArgumentException("Prompt 涓嶅瓨鍦�");
}
- if (db.getContent() == null || db.getContent().trim().isEmpty()) {
+ db = enrichTemplate(db);
+ String compiled = buildCompiledPrompt(db);
+ if (compiled.isEmpty()) {
throw new IllegalArgumentException("Prompt 鍐呭涓嶈兘涓虹┖");
}
@@ -114,10 +134,8 @@
db.setPublished((short) 1);
db.setStatus((short) 1);
db.setPublishedBy(operatorUserId);
- db.setPublishedTime(new Date());
- if (db.getVersion() == null || db.getVersion() <= 0) {
- db.setVersion(nextVersion(db.getSceneCode()));
- }
+ db.setPublishedTime(new java.util.Date());
+ db.setContent(compiled);
if (db.getName() == null || db.getName().trim().isEmpty()) {
AiPromptScene scene = requireScene(db.getSceneCode());
db.setName(defaultName(scene, db.getVersion(), null));
@@ -147,6 +165,65 @@
}
@Override
+ public AiPromptTemplate enrichTemplate(AiPromptTemplate template) {
+ if (template == null) {
+ return null;
+ }
+ if (template.getId() == null) {
+ template.setContent(buildCompiledPrompt(template));
+ return template;
+ }
+
+ List<AiPromptBlock> blocks = loadBlocks(template.getId());
+ if (blocks.isEmpty()) {
+ migrateLegacyTemplateBlocks(template);
+ blocks = loadBlocks(template.getId());
+ }
+ applyBlocks(template, blocks);
+ return template;
+ }
+
+ @Override
+ public List<AiPromptTemplate> enrichTemplates(List<AiPromptTemplate> templates) {
+ if (templates == null || templates.isEmpty()) {
+ return templates == null ? Collections.emptyList() : templates;
+ }
+
+ List<Long> templateIds = new ArrayList<>();
+ for (AiPromptTemplate template : templates) {
+ if (template != null && template.getId() != null) {
+ templateIds.add(template.getId());
+ }
+ }
+ Map<Long, List<AiPromptBlock>> blockMap = groupBlocks(loadBlocks(templateIds));
+ boolean migrated = false;
+ for (AiPromptTemplate template : templates) {
+ if (template == null || template.getId() == null) {
+ continue;
+ }
+ List<AiPromptBlock> blocks = blockMap.get(template.getId());
+ if (blocks == null || blocks.isEmpty()) {
+ migrateLegacyTemplateBlocks(template);
+ migrated = true;
+ }
+ }
+ if (migrated) {
+ blockMap = groupBlocks(loadBlocks(templateIds));
+ }
+ for (AiPromptTemplate template : templates) {
+ if (template == null) {
+ continue;
+ }
+ if (template.getId() == null) {
+ template.setContent(buildCompiledPrompt(template));
+ continue;
+ }
+ applyBlocks(template, blockMap.get(template.getId()));
+ }
+ return templates;
+ }
+
+ @Override
@Transactional(rollbackFor = Exception.class)
public boolean deletePrompt(Long id) {
if (id == null) {
@@ -157,8 +234,9 @@
return false;
}
if (Short.valueOf((short) 1).equals(db.getPublished())) {
- throw new IllegalArgumentException("宸插彂甯� Prompt 涓嶅厑璁稿垹闄わ紝璇峰厛鍙戝竷鍏朵粬鐗堟湰");
+ throw new IllegalArgumentException("宸插彂甯� Prompt 涓嶅厑璁稿垹闄わ紝璇峰厛鍙栨秷鍙戝竷");
}
+ aiPromptBlockMapper.delete(new QueryWrapper<AiPromptBlock>().eq("template_id", id));
return this.removeById(id);
}
@@ -170,6 +248,12 @@
AiPromptTemplate latest = findLatest(scene.getCode());
if (latest == null) {
ensurePublishedScene(scene);
+ changed++;
+ continue;
+ }
+ List<AiPromptBlock> blocks = loadBlocks(latest.getId());
+ if (blocks.isEmpty()) {
+ migrateLegacyTemplateBlocks(latest);
changed++;
}
}
@@ -189,33 +273,145 @@
}
private AiPromptTemplate ensurePublishedScene(AiPromptScene scene) {
- AiPromptTemplate latest = findLatest(scene.getCode());
- if (latest == null) {
- AiPromptTemplate seed = new AiPromptTemplate();
- seed.setName(defaultName(scene, 1, null));
- seed.setSceneCode(scene.getCode());
- seed.setVersion(1);
- seed.setContent(aiPromptUtils.getDefaultPrompt(scene.getCode()));
- seed.setStatus((short) 1);
- seed.setPublished((short) 1);
- seed.setPublishedTime(new Date());
- seed.setMemo("绯荤粺鍒濆鍖栭粯璁� Prompt");
- this.save(seed);
- log.info("Initialized default AI prompt, sceneCode={}, version={}", scene.getCode(), seed.getVersion());
- return seed;
+ LinkedHashMap<AiPromptBlockType, String> blocks = aiPromptUtils.getDefaultPromptBlocks(scene);
+ AiPromptTemplate seed = new AiPromptTemplate();
+ seed.setName(defaultName(scene, 1, null));
+ seed.setSceneCode(scene.getCode());
+ seed.setVersion(1);
+ seed.setStatus((short) 1);
+ seed.setPublished((short) 1);
+ seed.setPublishedTime(new java.util.Date());
+ seed.setMemo("绯荤粺鍒濆鍖栭粯璁� Prompt");
+ applyBlockFields(seed, blocks);
+ seed.setContent(buildCompiledPrompt(seed));
+ this.save(seed);
+ upsertBlocks(seed.getId(), blocks);
+ log.info("Initialized default AI prompt blocks, sceneCode={}, version={}", scene.getCode(), seed.getVersion());
+ return seed;
+ }
+
+ private void migrateLegacyTemplateBlocks(AiPromptTemplate template) {
+ if (template == null || template.getId() == null) {
+ return;
+ }
+ AiPromptScene scene = requireScene(template.getSceneCode());
+ LinkedHashMap<AiPromptBlockType, String> blocks = aiPromptUtils.resolveStoredOrDefaultBlocks(scene, template.getContent());
+ upsertBlocks(template.getId(), blocks);
+ applyBlockFields(template, blocks);
+ template.setContent(buildCompiledPrompt(template));
+ this.updateById(template);
+ }
+
+ private void applyBlocks(AiPromptTemplate template, List<AiPromptBlock> blocks) {
+ List<AiPromptBlock> ordered = blocks == null ? new ArrayList<>() : new ArrayList<>(blocks);
+ ordered.sort(BLOCK_SORT);
+ template.setBlocks(ordered);
+
+ LinkedHashMap<AiPromptBlockType, String> blockContent = new LinkedHashMap<>();
+ for (AiPromptBlockType type : AiPromptBlockType.values()) {
+ blockContent.put(type, "");
+ }
+ for (AiPromptBlock block : ordered) {
+ AiPromptBlockType type = AiPromptBlockType.ofCode(block.getBlockType());
+ if (type == null) {
+ continue;
+ }
+ blockContent.put(type, block.getContent());
+ }
+ applyBlockFields(template, blockContent);
+ template.setContent(buildCompiledPrompt(template));
+ }
+
+ private void applyBlockFields(AiPromptTemplate template, LinkedHashMap<AiPromptBlockType, String> blockContent) {
+ template.setBasePolicy(valueOf(blockContent, AiPromptBlockType.BASE_POLICY));
+ template.setToolPolicy(valueOf(blockContent, AiPromptBlockType.TOOL_POLICY));
+ template.setOutputContract(valueOf(blockContent, AiPromptBlockType.OUTPUT_CONTRACT));
+ template.setScenePlaybook(valueOf(blockContent, AiPromptBlockType.SCENE_PLAYBOOK));
+ }
+
+ private String valueOf(LinkedHashMap<AiPromptBlockType, String> blockContent, AiPromptBlockType type) {
+ if (blockContent == null) {
+ return "";
+ }
+ String value = blockContent.get(type);
+ return value == null ? "" : value;
+ }
+
+ private String buildCompiledPrompt(AiPromptTemplate template) {
+ String compiled = aiPromptComposerService.compose(template);
+ return compiled == null ? "" : compiled.trim();
+ }
+
+ private LinkedHashMap<AiPromptBlockType, String> extractBlockContentMap(AiPromptTemplate template) {
+ LinkedHashMap<AiPromptBlockType, String> blocks = new LinkedHashMap<>();
+ blocks.put(AiPromptBlockType.BASE_POLICY, defaultString(template.getBasePolicy()));
+ blocks.put(AiPromptBlockType.TOOL_POLICY, defaultString(template.getToolPolicy()));
+ blocks.put(AiPromptBlockType.OUTPUT_CONTRACT, defaultString(template.getOutputContract()));
+ blocks.put(AiPromptBlockType.SCENE_PLAYBOOK, defaultString(template.getScenePlaybook()));
+ return blocks;
+ }
+
+ private void upsertBlocks(Long templateId, LinkedHashMap<AiPromptBlockType, String> blockContent) {
+ List<AiPromptBlock> existingBlocks = loadBlocks(templateId);
+ HashMap<String, AiPromptBlock> existingMap = new HashMap<>();
+ for (AiPromptBlock block : existingBlocks) {
+ existingMap.put(block.getBlockType(), block);
}
- UpdateWrapper<AiPromptTemplate> clearWrapper = new UpdateWrapper<>();
- clearWrapper.eq("scene_code", scene.getCode()).set("published", 0);
- this.update(clearWrapper);
-
- latest.setStatus((short) 1);
- latest.setPublished((short) 1);
- if (latest.getPublishedTime() == null) {
- latest.setPublishedTime(new Date());
+ for (AiPromptBlockType type : AiPromptBlockType.values()) {
+ AiPromptBlock block = existingMap.get(type.getCode());
+ if (block == null) {
+ block = new AiPromptBlock();
+ block.setTemplateId(templateId);
+ block.setBlockType(type.getCode());
+ block.setSortNo(type.getSort());
+ block.setStatus((short) 1);
+ block.setContent(defaultString(blockContent.get(type)));
+ aiPromptBlockMapper.insert(block);
+ continue;
+ }
+ block.setSortNo(type.getSort());
+ block.setStatus((short) 1);
+ block.setContent(defaultString(blockContent.get(type)));
+ aiPromptBlockMapper.updateById(block);
}
- this.updateById(latest);
- return latest;
+ }
+
+ private List<AiPromptBlock> loadBlocks(Long templateId) {
+ if (templateId == null) {
+ return Collections.emptyList();
+ }
+ return aiPromptBlockMapper.selectList(new QueryWrapper<AiPromptBlock>()
+ .eq("template_id", templateId)
+ .orderByAsc("sort_no")
+ .orderByAsc("id"));
+ }
+
+ private List<AiPromptBlock> loadBlocks(List<Long> templateIds) {
+ if (templateIds == null || templateIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return aiPromptBlockMapper.selectList(new QueryWrapper<AiPromptBlock>()
+ .in("template_id", templateIds)
+ .orderByAsc("sort_no")
+ .orderByAsc("id"));
+ }
+
+ private Map<Long, List<AiPromptBlock>> groupBlocks(List<AiPromptBlock> blocks) {
+ HashMap<Long, List<AiPromptBlock>> result = new HashMap<>();
+ if (blocks == null) {
+ return result;
+ }
+ for (AiPromptBlock block : blocks) {
+ if (block == null || block.getTemplateId() == null) {
+ continue;
+ }
+ result.computeIfAbsent(block.getTemplateId(), k -> new ArrayList<>()).add(block);
+ }
+ for (List<AiPromptBlock> list : result.values()) {
+ list.sort(BLOCK_SORT);
+ }
+ return result;
}
private AiPromptTemplate findPublished(String sceneCode) {
@@ -281,4 +477,8 @@
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
+
+ private String defaultString(String value) {
+ return value == null ? "" : value;
+ }
}
--
Gitblit v1.9.1