Skip to content

Commit 7dabc34

Browse files
authored
Merge pull request #12 from twj666/master
sf-chain框架对接日志能力
2 parents 6f82487 + 5d815ea commit 7dabc34

22 files changed

+3949
-729
lines changed

prompto-lab-app/src/main/java/io/github/timemachinelab/sfchain/constants/AIOperationConstant.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ public class AIOperationConstant {
1313
* JSON修复操作
1414
*/
1515
public static final String JSON_REPAIR_OP = "JSON_REPAIR_OP";
16-
17-
/**
18-
* 文本分类操作
19-
*/
20-
public static final String TEXT_CLASSIFICATION_OP = "TEXT_CLASSIFICATION";
2116

2217
/**
2318
* 模型验证操作

prompto-lab-app/src/main/java/io/github/timemachinelab/sfchain/controller/AICallLogController.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
import io.github.timemachinelab.sfchain.core.logging.AICallLog;
44
import io.github.timemachinelab.sfchain.core.logging.AICallLogManager;
5-
import org.springframework.beans.factory.annotation.Autowired;
5+
import io.github.timemachinelab.sfchain.core.logging.AICallLogSummary;
66
import org.springframework.http.ResponseEntity;
77
import org.springframework.web.bind.annotation.*;
88

9+
import javax.annotation.Resource;
910
import java.util.List;
1011
import java.util.Map;
1112

@@ -14,42 +15,43 @@
1415
*/
1516
@RestController
1617
@RequestMapping("/sf/api/ai-logs")
18+
@CrossOrigin(origins = "*")
1719
public class AICallLogController {
1820

19-
@Autowired
21+
@Resource
2022
private AICallLogManager logManager;
2123

2224
/**
23-
* 获取所有日志
25+
* 获取所有日志摘要(轻量级)
2426
*/
2527
@GetMapping
26-
public ResponseEntity<List<AICallLog>> getAllLogs() {
27-
return ResponseEntity.ok(logManager.getAllLogs());
28+
public ResponseEntity<List<AICallLogSummary>> getAllLogSummaries() {
29+
return ResponseEntity.ok(logManager.getAllLogSummaries());
2830
}
2931

3032
/**
31-
* 根据调用ID获取日志
33+
* 根据调用ID获取完整日志详情
3234
*/
3335
@GetMapping("/{callId}")
34-
public ResponseEntity<AICallLog> getLog(@PathVariable String callId) {
35-
AICallLog log = logManager.getLog(callId);
36+
public ResponseEntity<AICallLog> getFullLog(@PathVariable String callId) {
37+
AICallLog log = logManager.getFullLog(callId);
3638
return log != null ? ResponseEntity.ok(log) : ResponseEntity.notFound().build();
3739
}
3840

3941
/**
40-
* 根据操作类型获取日志
42+
* 根据操作类型获取日志摘要(轻量级)
4143
*/
4244
@GetMapping("/operation/{operationType}")
43-
public ResponseEntity<List<AICallLog>> getLogsByOperation(@PathVariable String operationType) {
44-
return ResponseEntity.ok(logManager.getLogsByOperation(operationType));
45+
public ResponseEntity<List<AICallLogSummary>> getLogSummariesByOperation(@PathVariable String operationType) {
46+
return ResponseEntity.ok(logManager.getLogSummariesByOperation(operationType));
4547
}
4648

4749
/**
48-
* 根据模型名称获取日志
50+
* 根据模型名称获取日志摘要(轻量级)
4951
*/
5052
@GetMapping("/model/{modelName}")
51-
public ResponseEntity<List<AICallLog>> getLogsByModel(@PathVariable String modelName) {
52-
return ResponseEntity.ok(logManager.getLogsByModel(modelName));
53+
public ResponseEntity<List<AICallLogSummary>> getLogSummariesByModel(@PathVariable String modelName) {
54+
return ResponseEntity.ok(logManager.getLogSummariesByModel(modelName));
5355
}
5456

5557
/**

prompto-lab-app/src/main/java/io/github/timemachinelab/sfchain/controller/AIModelController.java

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,19 @@ public ResponseEntity<Map<String, Object>> saveModel(
9393
Map<String, Object> result = new HashMap<>();
9494
String modelName = config.getModelName();
9595
try {
96-
// 验证模型配置
97-
boolean validationResult = validateModelConfig(modelName, config);
96+
// 检查模型是否已存在
97+
Map<String, ModelConfigData> existingModels = persistenceManager.getAllModelConfigs();
98+
boolean modelExists = existingModels.containsKey(modelName);
99+
100+
// 验证模型配置(临时验证,不影响现有模型)
101+
boolean validationResult = validateModelConfig(modelName, config, true);
98102

99103
if (!validationResult) {
100104
result.put("success", false);
101105
result.put("message", "模型验证失败,请检查配置参数");
102106
return ResponseEntity.badRequest().body(result);
103107
}
104108

105-
// 检查模型是否已存在
106-
Map<String, ModelConfigData> existingModels = persistenceManager.getAllModelConfigs();
107-
boolean modelExists = existingModels.containsKey(modelName);
108-
109109
// 根据模型是否存在选择添加或更新
110110
if (modelExists) {
111111
persistenceManager.updateModelConfig(modelName, config);
@@ -132,31 +132,12 @@ public ResponseEntity<Map<String, Object>> saveModel(
132132
}
133133
}
134134

135-
/**
136-
* 删除模型配置
137-
*/
138-
@DeleteMapping("/{modelName}")
139-
public ResponseEntity<Map<String, Object>> deleteModel(@PathVariable String modelName) {
140-
Map<String, Object> result = new HashMap<>();
141-
try {
142-
persistenceManager.deleteModelConfig(modelName);
143-
result.put("success", true);
144-
result.put("message", "模型配置删除成功");
145-
result.put("modelName", modelName);
146-
return ResponseEntity.ok(result);
147-
} catch (Exception e) {
148-
log.error("删除模型配置失败: {} - {}", modelName, e.getMessage());
149-
result.put("success", false);
150-
result.put("message", "删除失败: " + e.getMessage());
151-
return ResponseEntity.badRequest().body(result);
152-
}
153-
}
154-
155135
/**
156136
* 测试模型连接
157137
*/
158-
@PostMapping("/{modelName}/test")
159-
public ResponseEntity<Map<String, Object>> testModel(@PathVariable String modelName) {
138+
@PostMapping("/test")
139+
public ResponseEntity<Map<String, Object>> testModel(@RequestBody Map<String, String> request) {
140+
String modelName = request.get("modelName");
160141
Map<String, Object> result = new HashMap<>();
161142
try {
162143
Map<String, ModelConfigData> models = persistenceManager.getAllModelConfigs();
@@ -168,7 +149,8 @@ public ResponseEntity<Map<String, Object>> testModel(@PathVariable String modelN
168149
return ResponseEntity.notFound().build();
169150
}
170151

171-
boolean testResult = validateModelConfig(modelName, config);
152+
// 测试已存在的模型,不需要临时注册
153+
boolean testResult = validateModelConfig(modelName, config, false);
172154
result.put("success", testResult);
173155
result.put("message", testResult ? "模型连接测试成功" : "模型连接测试失败");
174156
result.put("modelName", modelName);
@@ -186,21 +168,27 @@ public ResponseEntity<Map<String, Object>> testModel(@PathVariable String modelN
186168

187169
/**
188170
* 验证模型配置是否可用
171+
* @param modelName 模型名称
172+
* @param config 模型配置
173+
* @param isTemporaryValidation 是否为临时验证(true: 验证后移除临时模型,false: 验证已存在的模型)
189174
*/
190-
private boolean validateModelConfig(String modelName, ModelConfigData config) {
175+
private boolean validateModelConfig(String modelName, ModelConfigData config, boolean isTemporaryValidation) {
191176
boolean tempRegistered = false;
192177
try {
193-
log.info("开始验证模型配置: {}", modelName);
178+
log.info("开始验证模型配置: {} (临时验证: {})", modelName, isTemporaryValidation);
194179

195180
ModelValidationOperation validationOp = (ModelValidationOperation) operationRegistry.getOperation(MODEL_VALIDATION_OP);
196181
if (validationOp == null) {
197182
log.warn("未找到模型验证操作,跳过验证");
198183
return true;
199184
}
200185

201-
OpenAIModelConfig tempConfig = convertToOpenAIConfig(config);
202-
modelFactory.registerModel(tempConfig);
203-
tempRegistered = true;
186+
// 如果是临时验证,需要临时注册模型
187+
if (isTemporaryValidation) {
188+
OpenAIModelConfig tempConfig = convertToOpenAIConfig(config);
189+
modelFactory.registerModel(tempConfig);
190+
tempRegistered = true;
191+
}
204192

205193
ModelValidationOperation.ValidationRequest request =
206194
new ModelValidationOperation.ValidationRequest("请回答:2+3等于几?");
@@ -213,15 +201,38 @@ private boolean validateModelConfig(String modelName, ModelConfigData config) {
213201
log.error("模型验证失败: {} - {}", modelName, e.getMessage());
214202
return false;
215203
} finally {
216-
if (tempRegistered) {
204+
// 只有在临时验证时才清理临时模型
205+
if (tempRegistered && isTemporaryValidation) {
217206
try {
218207
modelFactory.removeModel(modelName);
208+
log.debug("已清理临时模型配置: {}", modelName);
219209
} catch (Exception e) {
220210
log.warn("清理临时模型配置失败: {}", e.getMessage());
221211
}
222212
}
223213
}
224214
}
215+
216+
217+
/**
218+
* 删除模型配置
219+
*/
220+
@DeleteMapping("/{modelName}")
221+
public ResponseEntity<Map<String, Object>> deleteModel(@PathVariable String modelName) {
222+
Map<String, Object> result = new HashMap<>();
223+
try {
224+
persistenceManager.deleteModelConfig(modelName);
225+
result.put("success", true);
226+
result.put("message", "模型配置删除成功");
227+
result.put("modelName", modelName);
228+
return ResponseEntity.ok(result);
229+
} catch (Exception e) {
230+
log.error("删除模型配置失败: {} - {}", modelName, e.getMessage());
231+
result.put("success", false);
232+
result.put("message", "删除失败: " + e.getMessage());
233+
return ResponseEntity.badRequest().body(result);
234+
}
235+
}
225236

226237
/**
227238
* 转换配置格式

prompto-lab-app/src/main/java/io/github/timemachinelab/sfchain/core/AIOperationRegistry.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,7 @@ public void registerOperation(String operationType, BaseAIOperation<?, ?> operat
8686
*/
8787
public String getModelForOperation(String operationType) {
8888
// 优先从内存缓存获取
89-
String cachedModel = modelMapping.get(operationType);
90-
if (cachedModel != null) {
91-
return cachedModel;
92-
}
93-
94-
// 如果缓存中没有,可以从 PersistenceManager 获取操作配置中的模型名称
95-
return null; // 或者注入 PersistenceManager 来获取
89+
return modelMapping.get(operationType);
9690
}
9791

9892
/**
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package io.github.timemachinelab.sfchain.core;
2+
3+
import java.time.LocalDateTime;
4+
import java.time.ZoneId;
5+
import java.time.format.DateTimeFormatter;
6+
7+
/**
8+
* AI提示词构建器
9+
* 用于构建结构化的AI提示词,支持与AIResponseParser配合使用
10+
* @author suifeng
11+
* 日期: 2025/04/18
12+
*/
13+
public class AIPromptBuilder {
14+
15+
private final StringBuilder promptBuilder = new StringBuilder();
16+
private boolean hasJsonOutput = false;
17+
18+
/**
19+
* 创建一个提示词构建器
20+
* @param title 提示词标题
21+
*/
22+
public AIPromptBuilder(String title) {
23+
promptBuilder.append("# ").append(title).append("\n\n");
24+
}
25+
26+
/**
27+
* 添加角色描述
28+
* @param roleDescription 角色描述
29+
* @return 构建器实例
30+
*/
31+
public AIPromptBuilder addRole(String roleDescription) {
32+
// 获取当前北京时间
33+
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
34+
String formattedTime = now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"));
35+
promptBuilder.append("# 当前的时间是北京时间:").append(formattedTime).append("\n");
36+
promptBuilder.append(roleDescription).append("\n\n");
37+
return this;
38+
}
39+
40+
/**
41+
* 添加章节
42+
* @param sectionTitle 章节标题
43+
* @param content 章节内容
44+
* @return 构建器实例
45+
*/
46+
public AIPromptBuilder addSection(String sectionTitle, String content) {
47+
promptBuilder.append("## ").append(sectionTitle).append("\n");
48+
promptBuilder.append(content).append("\n\n");
49+
return this;
50+
}
51+
52+
/**
53+
* 添加子章节
54+
* @param subSectionTitle 子章节标题
55+
* @param content 子章节内容
56+
* @return 构建器实例
57+
*/
58+
public AIPromptBuilder addSubSection(String subSectionTitle, String content) {
59+
promptBuilder.append("### ").append(subSectionTitle).append("\n");
60+
promptBuilder.append(content).append("\n\n");
61+
return this;
62+
}
63+
64+
/**
65+
* 添加JSON输出格式
66+
* @param jsonExample JSON示例
67+
* @return 构建器实例
68+
*/
69+
public AIPromptBuilder addJsonOutput(String jsonExample) {
70+
promptBuilder.append("## 输出格式要求\n");
71+
promptBuilder.append("所有字符串中的引用部分只能用英文单引号 ' 包裹,内容中禁止出现英文双引号, 但是你要注意json格式规范是要加\"的,保证我能正常解析JSON 。\n");
72+
promptBuilder.append("```json\n");
73+
promptBuilder.append(jsonExample).append("\n");
74+
promptBuilder.append("```\n");
75+
promptBuilder.append("不需要给我任何额外的信息,我只需要最终的json结果,以保证生成和响应的速度\n");
76+
hasJsonOutput = true;
77+
return this;
78+
}
79+
80+
/**
81+
* 添加表格输出格式
82+
* @param headers 表头
83+
* @param example 示例行
84+
* @return 构建器实例
85+
*/
86+
public AIPromptBuilder addTableOutput(String[] headers, String[] example) {
87+
promptBuilder.append("## 输出格式要求\n");
88+
promptBuilder.append("你必须严格按照以下表格格式返回结果:\n");
89+
promptBuilder.append("```\n");
90+
91+
// 构建表头
92+
promptBuilder.append("| ");
93+
for (String header : headers) {
94+
promptBuilder.append(header).append(" | ");
95+
}
96+
promptBuilder.append("\n");
97+
98+
// 构建分隔行
99+
promptBuilder.append("| ");
100+
for (int i = 0; i < headers.length; i++) {
101+
promptBuilder.append("--- | ");
102+
}
103+
promptBuilder.append("\n");
104+
105+
// 构建示例行
106+
if (example != null) {
107+
promptBuilder.append("| ");
108+
for (String cell : example) {
109+
promptBuilder.append(cell).append(" | ");
110+
}
111+
promptBuilder.append("\n");
112+
}
113+
114+
promptBuilder.append("```\n\n");
115+
return this;
116+
}
117+
118+
/**
119+
* 添加自定义输出格式
120+
* @param formatDescription 格式描述
121+
* @param example 示例
122+
* @param formatType 格式类型(用于AIResponseParser识别)
123+
* @return 构建器实例
124+
*/
125+
public AIPromptBuilder addCustomOutput(String formatDescription, String example, String formatType) {
126+
promptBuilder.append("## 输出格式要求\n");
127+
promptBuilder.append(formatDescription).append("\n");
128+
promptBuilder.append("```").append(formatType).append("\n");
129+
promptBuilder.append(example).append("\n");
130+
promptBuilder.append("```\n\n");
131+
return this;
132+
}
133+
134+
/**
135+
* 添加原始文本(不添加任何格式)
136+
* @param text 原始文本
137+
* @return 构建器实例
138+
*/
139+
public AIPromptBuilder addRawText(String text) {
140+
promptBuilder.append(text).append("\n\n");
141+
return this;
142+
}
143+
144+
/**
145+
* 构建提示词
146+
* @return 完整的提示词字符串
147+
*/
148+
public String build() {
149+
if (!hasJsonOutput) {
150+
// 如果没有指定输出格式,添加默认提示
151+
promptBuilder.append("请确保你的回答简洁明了,直接提供所需信息。\n");
152+
}
153+
return promptBuilder.toString();
154+
}
155+
}

0 commit comments

Comments
 (0)