Skip to content

Commit 010c7b0

Browse files
author
wuayee
committed
[app-builder] 增加节点配置项更新的功能
1 parent f388e5d commit 010c7b0

File tree

10 files changed

+337
-5
lines changed

10 files changed

+337
-5
lines changed

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/controller/AppBuilderAppController.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import modelengine.fit.jober.aipp.dto.AppBuilderAppDto;
4242
import modelengine.fit.jober.aipp.dto.AppBuilderAppMetadataDto;
4343
import modelengine.fit.jober.aipp.dto.AppBuilderFlowGraphDto;
44+
import modelengine.fit.jober.aipp.dto.AppBuilderNodeConfigsDto;
4445
import modelengine.fit.jober.aipp.dto.AppBuilderSaveConfigDto;
4546
import modelengine.fit.jober.aipp.dto.PublishedAppResDto;
4647
import modelengine.fit.jober.aipp.dto.check.AppCheckDto;
@@ -280,6 +281,21 @@ public Rsp<AppBuilderAppDto> updateByGraph(HttpClassicServerRequest httpRequest,
280281
return this.appService.updateFlowGraph(appId, flowGraphDto, this.contextOf(httpRequest, tenantId));
281282
}
282283

284+
/**
285+
* 修改节点的配置项。
286+
*
287+
* @param httpRequest 请求。
288+
* @param tenantId 租户Id。
289+
* @param nodeConfigs 节点的配置项的 dto。
290+
*/
291+
@CarverSpan(value = "operation.appBuilderApp.update.node.config")
292+
@PutMapping(value = "/node/config", description = "修改节点的配置项")
293+
@AppValidation
294+
public void updateNodeConfig(HttpClassicServerRequest httpRequest, @PathVariable("tenant_id") String tenantId,
295+
@RequestBody @Validated AppBuilderNodeConfigsDto nodeConfigs) {
296+
this.appService.updateNodeConfigs(nodeConfigs, this.contextOf(httpRequest, tenantId));
297+
}
298+
283299
/**
284300
* 更新app的基本信息。
285301
*

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/AppVersionService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ public interface AppVersionService {
186186
*/
187187
AppVersion update(String appId, AppBuilderFlowGraphDto graphDto, OperationContext context);
188188

189+
/**
190+
* 根据传入的 {@link AppVersion} 数据更新流程.
191+
*
192+
* @param appVersion 应用版本.
193+
* @param graphDto 待修改数据.
194+
* @param context 操作人上下文信息.
195+
*/
196+
void updateGraph(AppVersion appVersion, AppBuilderFlowGraphDto graphDto, OperationContext context);
197+
189198
/**
190199
* 根据传入的 {@link AppBuilderSaveConfigDto} 数据进行修改.
191200
*

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/domains/appversion/service/impl/AppVersionServiceImpl.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,12 @@ public AppVersion update(String appId, AppBuilderFlowGraphDto graphDto, Operatio
372372
if (appVersion.isPublished()) {
373373
throw new AippException(AippErrCode.APP_HAS_ALREADY);
374374
}
375+
this.updateGraph(appVersion, graphDto, context);
376+
return appVersion;
377+
}
378+
379+
@Override
380+
public void updateGraph(AppVersion appVersion, AppBuilderFlowGraphDto graphDto, OperationContext context) {
375381
Span.current().setAttribute("name", appVersion.getData().getName());
376382
LocalDateTime operateTime = LocalDateTime.now();
377383
appVersion.getFlowGraph().setUpdateAt(operateTime);
@@ -389,7 +395,6 @@ public AppVersion update(String appId, AppBuilderFlowGraphDto graphDto, Operatio
389395
appVersion.getData().setUpdateBy(context.getOperator());
390396
appVersion.putAttributes(new HashMap<>());
391397
this.repository.update(appVersion);
392-
return appVersion;
393398
}
394399

395400
@Override

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/AppBuilderAppService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import modelengine.fit.jober.aipp.dto.AppBuilderConfigDto;
1717
import modelengine.fit.jober.aipp.dto.AppBuilderConfigFormPropertyDto;
1818
import modelengine.fit.jober.aipp.dto.AppBuilderFlowGraphDto;
19+
import modelengine.fit.jober.aipp.dto.AppBuilderNodeConfigsDto;
1920
import modelengine.fit.jober.aipp.dto.AppBuilderSaveConfigDto;
2021
import modelengine.fit.jober.aipp.dto.PublishedAppResDto;
2122
import modelengine.fit.jober.aipp.dto.check.AppCheckDto;
@@ -104,6 +105,15 @@ Rsp<AppBuilderAppDto> saveConfig(String appId, AppBuilderSaveConfigDto appBuilde
104105
@Genericable(id = "modelengine.fit.jober.aipp.service.flow.graph.update")
105106
Rsp<AppBuilderAppDto> updateFlowGraph(String appId, AppBuilderFlowGraphDto graphDto, OperationContext context);
106107

108+
/**
109+
* 更新节点的配置项。
110+
*
111+
* @param nodeConfigs 节点配置项的 {@link AppBuilderNodeConfigsDto}。
112+
* @param context 表示操作上下文的 {@link OperationContext}。
113+
*/
114+
@Genericable(id = "modelengine.fit.jober.aipp.service.update.node.configs")
115+
void updateNodeConfigs(AppBuilderNodeConfigsDto nodeConfigs, OperationContext context);
116+
107117
/**
108118
* 发布应用。
109119
*

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AppBuilderAppServiceImpl.java

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import modelengine.fit.jober.aipp.dto.AppBuilderConfigDto;
3939
import modelengine.fit.jober.aipp.dto.AppBuilderConfigFormPropertyDto;
4040
import modelengine.fit.jober.aipp.dto.AppBuilderFlowGraphDto;
41+
import modelengine.fit.jober.aipp.dto.AppBuilderNodeConfigsDto;
4142
import modelengine.fit.jober.aipp.dto.AppBuilderSaveConfigDto;
4243
import modelengine.fit.jober.aipp.dto.PublishedAppResDto;
4344
import modelengine.fit.jober.aipp.dto.check.AppCheckDto;
@@ -52,13 +53,15 @@
5253
import modelengine.fit.jober.aipp.service.Checker;
5354
import modelengine.fit.jober.aipp.service.UploadedFileManageService;
5455
import modelengine.fit.jober.aipp.util.ConvertUtils;
56+
import modelengine.fit.jober.aipp.util.JsonUtils;
5557
import modelengine.fit.jober.aipp.util.RandomPathUtils;
5658
import modelengine.fit.jober.common.RangedResultSet;
5759
import modelengine.fitframework.annotation.Component;
5860
import modelengine.fitframework.annotation.Fitable;
5961
import modelengine.fitframework.annotation.Value;
6062
import modelengine.fitframework.log.Logger;
6163
import modelengine.fitframework.transaction.Transactional;
64+
import modelengine.fitframework.util.ObjectUtils;
6265
import modelengine.fitframework.util.StringUtils;
6366
import modelengine.jade.knowledge.KnowledgeCenterService;
6467

@@ -189,7 +192,11 @@ public void updateFlow(String appId, OperationContext contextOf) {
189192
@Override
190193
public AppBuilderAppDto queryLatestOrchestration(String appId, OperationContext context) {
191194
AppVersion appVersion = this.appVersionService.retrieval(appId);
192-
App app = this.appDomainFactory.create(appVersion.getData().getAppSuiteId());
195+
return this.queryLatestOrchestrationBySuiteId(appVersion.getData().getAppSuiteId(), context);
196+
}
197+
198+
private AppBuilderAppDto queryLatestOrchestrationBySuiteId(String appSuiteId, OperationContext context) {
199+
App app = this.appDomainFactory.create(appSuiteId);
193200
AppVersion latestVersion = app.getLatestVersion()
194201
.orElseThrow(() -> new AippException(OBTAIN_APP_ORCHESTRATION_INFO_FAILED));
195202
if (latestVersion.isPublished()) {
@@ -309,6 +316,169 @@ public Rsp<AppBuilderAppDto> updateFlowGraph(String appId, AppBuilderFlowGraphDt
309316
return Rsp.ok(this.converterFactory.convert(appVersion, AppBuilderAppDto.class));
310317
}
311318

319+
@Override
320+
public void updateNodeConfigs(AppBuilderNodeConfigsDto nodeConfigs, OperationContext context) {
321+
if (StringUtils.isBlank(nodeConfigs.getAppSuiteId())) {
322+
throw new IllegalArgumentException("Id is not exist");
323+
}
324+
AppVersion latestVersion = this.appVersionService.getLatestCreatedByAppSuiteId(nodeConfigs.getAppSuiteId())
325+
.orElseThrow(() -> new AippException(AippErrCode.APP_NOT_FOUND));
326+
boolean isPublished = latestVersion.isPublished();
327+
if (isPublished) {
328+
// 如果是发布状态,则创建一个草稿态
329+
this.queryLatestOrchestrationBySuiteId(nodeConfigs.getAppSuiteId(), context);
330+
latestVersion = this.appVersionService.getLatestCreatedByAppSuiteId(nodeConfigs.getAppSuiteId())
331+
.orElseThrow(() -> new AippException(AippErrCode.APP_NOT_FOUND));
332+
}
333+
Map<String, Object> appearances = JsonUtils.parseObject(latestVersion.getFlowGraph().getAppearance());
334+
List<?> shapes = this.getShapes(appearances);
335+
for(Map.Entry<String, Object> nodeConfig: nodeConfigs.getNodeConfigs().entrySet()) {
336+
Map<String, Object> oldShape = this.getNodeShape(shapes, ObjectUtils.cast(nodeConfig.getKey()));
337+
Map<String, Object> params = this.getParams(oldShape);
338+
List<Map<String, Object>> inputParams = ObjectUtils.cast(params.get("inputParams"));
339+
Map<String, Object> newConfig = ObjectUtils.cast(nodeConfig.getValue());
340+
this.updateValueParams(inputParams, ObjectUtils.cast(newConfig.get("valueParams")));
341+
}
342+
AppBuilderFlowGraphDto flowGraphDto = this.buildAppBuilderFlowGraphDto(latestVersion, appearances);
343+
this.appVersionService.updateGraph(latestVersion, flowGraphDto, context);
344+
if (isPublished) {
345+
AppBuilderAppDto appDto = this.converterFactory.convert(latestVersion, AppBuilderAppDto.class);
346+
this.publish(appDto, context);
347+
}
348+
}
349+
350+
private AppBuilderFlowGraphDto buildAppBuilderFlowGraphDto(AppVersion appVersion, Map<String, Object> appearances) {
351+
return AppBuilderFlowGraphDto.builder()
352+
.name(appVersion.getFlowGraph().getName())
353+
.appearance(appearances)
354+
.build();
355+
}
356+
357+
private void updateValueParams(List<Map<String, Object>> inputParams, Map<String, Object> newConfig) {
358+
if (inputParams == null || newConfig == null || newConfig.isEmpty()) {
359+
return;
360+
}
361+
for (Map.Entry<String, Object> entry : newConfig.entrySet()) {
362+
this.updateInputParam(inputParams, entry);
363+
}
364+
}
365+
366+
private void updateInputParam(List<Map<String, Object>> inputParams, Map.Entry<String, Object> entry) {
367+
String key = entry.getKey();
368+
Object value = entry.getValue();
369+
String[] pathParts = key.split("\\.");
370+
if (pathParts.length == 0) {
371+
return;
372+
}
373+
374+
// 从顶层inputParams开始查找目标节点
375+
List<Map<String, Object>> currentLevel = inputParams;
376+
Map<String, Object> targetNode = null;
377+
for (int i = 0; i < pathParts.length; i++) {
378+
String part = pathParts[i];
379+
380+
// 在当前层级查找name匹配的节点
381+
Map<String, Object> found = this.findConfigByName(currentLevel, part);
382+
if (found == null) {
383+
break;
384+
}
385+
386+
// 如果是最后一层,找到目标节点
387+
if (i == pathParts.length - 1) {
388+
targetNode = found;
389+
break;
390+
}
391+
392+
// 非最后一层,进入下一层(value字段)
393+
Object nextLevelObj = found.get("value");
394+
if (!(nextLevelObj instanceof List)) {
395+
// 下一层不是List,路径无效,跳过
396+
break;
397+
}
398+
currentLevel = ObjectUtils.cast(nextLevelObj);
399+
}
400+
401+
// 更新目标节点的value
402+
if (targetNode != null) {
403+
targetNode.put("value", value);
404+
}
405+
}
406+
407+
private Map<String, Object> findConfigByName(List<Map<String, Object>> configs, String name) {
408+
if (configs == null) {
409+
return null;
410+
}
411+
for (Map<String, Object> config : configs) {
412+
Object nodeName = config.get("name");
413+
if (nodeName != null && StringUtils.equals(name, ObjectUtils.cast(nodeName))) {
414+
return config;
415+
}
416+
}
417+
return null;
418+
}
419+
420+
private Map<String, Object> getParams(Map<String, Object> config) {
421+
Map<String, Object> flowMetaMap =
422+
this.mapSearch(config, "flowMeta", "FlowMeta is not map.", "FlowMeta is empty.");
423+
Map<String, Object> joberMap = this.mapSearch(flowMetaMap, "jober", "Jober is not map.", "Jober is empty.");
424+
Map<String, Object> converterMap =
425+
this.mapSearch(joberMap, "converter", "Converter is not map.", "Converter is empty.");
426+
return this.mapSearch(converterMap, "entity", "entity is not map.", "Entity is empty.");
427+
}
428+
429+
private Map<String, Object> mapSearch(Map<String, Object> config, String key, String typeErrorMsg,
430+
String emptyErrorMsg) {
431+
Object value = config.get(key);
432+
if (!(value instanceof Map)) {
433+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, typeErrorMsg);
434+
}
435+
Map<String, Object> newMap = ObjectUtils.cast(value);
436+
if (newMap.isEmpty()) {
437+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, emptyErrorMsg);
438+
}
439+
return newMap;
440+
}
441+
442+
private Map<String, Object> getNodeShape(List<?> shapes, String targetId) {
443+
for (Object shape : shapes) {
444+
if (!(shape instanceof Map)) {
445+
continue;
446+
}
447+
Map<String, Object> shapeMap = ObjectUtils.cast(shape);
448+
String idObj = ObjectUtils.cast(shapeMap.get("id"));
449+
if (StringUtils.equals(idObj, targetId)) {
450+
return ObjectUtils.cast(shape);
451+
}
452+
}
453+
return new HashMap<>();
454+
}
455+
456+
private List<?> getShapes(Map<String, Object> appearances) {
457+
Object pagesObj = appearances.get("pages");
458+
if (!(pagesObj instanceof List)) {
459+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Pages is not list.");
460+
}
461+
List<?> pages = ObjectUtils.cast(pagesObj);
462+
if (pages.isEmpty()) {
463+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Pages is empty.");
464+
}
465+
Object pageConfig = pages.get(0);
466+
if (!(pageConfig instanceof Map)) {
467+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED,
468+
"The first element of pages is not of Map type.");
469+
}
470+
Map<String, Object> pageConfigMap = ObjectUtils.cast(pageConfig);
471+
Object shapesObj = pageConfigMap.get("shapes");
472+
if (!(shapesObj instanceof List)) {
473+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Shapes is not an array type.");
474+
}
475+
List<?> shapes = ObjectUtils.cast(shapesObj);
476+
if (shapes.isEmpty()) {
477+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "shapes array is empty.");
478+
}
479+
return shapes;
480+
}
481+
312482
@Override
313483
@Fitable(id = "default")
314484
public void delete(String appId, OperationContext context) {

app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_en.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,5 @@
147147
90002143=No permission to operate this form.
148148
90002144=The app is not in guest mode.
149149
90002145=The large model call timed out. Please try changing the default model.
150+
90002146=Node config update failed. Reason for failure: {0}.
150151
90003000=The application template does not exist.

app-builder/plugins/aipp-plugin/src/main/resources/i18n/messages_zh.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,5 @@
148148
90002143=没有权限操作该表单。
149149
90002144=应用未打开游客模式。
150150
90002145=大模型调用超时,请尝试更换默认模型。
151+
90002146=节点配置更新失败,失败原因:{1}。
151152
90003000=应用模板不存在。

0 commit comments

Comments
 (0)