Skip to content

Commit 7fa643e

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

File tree

10 files changed

+548
-5
lines changed

10 files changed

+548
-5
lines changed

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

Lines changed: 31 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,36 @@ 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+
299+
/**
300+
* 发布最新版本。
301+
*
302+
* @param httpRequest 请求。
303+
* @param tenantId 租户Id。
304+
* @param appSuiteId 应用的版本id。
305+
*/
306+
@CarverSpan(value = "operation.appBuilderApp.publish.latest.version")
307+
@PostMapping(value = "/publish/latest_version/{app_suite_id}", description = "发布最新版本")
308+
@AppValidation
309+
public Rsp<AippCreateDto> publishLatestVersion(HttpClassicServerRequest httpRequest,
310+
@PathVariable("tenant_id") String tenantId, @PathVariable("app_suite_id") String appSuiteId) {
311+
return this.appService.publishLatestVersion(appSuiteId, this.contextOf(httpRequest, tenantId));
312+
}
313+
283314
/**
284315
* 更新app的基本信息。
285316
*

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: 19 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,24 @@ 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+
117+
/**
118+
* 更新节点的配置项。
119+
*
120+
* @param appSuiteId 应用的版本 id 的 {@link String}。
121+
* @param context 表示操作上下文的 {@link OperationContext}。
122+
*/
123+
@Genericable(id = "modelengine.fit.jober.aipp.service.app.publish.latest.version")
124+
Rsp<AippCreateDto> publishLatestVersion(String appSuiteId, OperationContext context);
125+
107126
/**
108127
* 发布应用。
109128
*

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

Lines changed: 178 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,176 @@ 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+
}
345+
346+
@Override
347+
public Rsp<AippCreateDto> publishLatestVersion(String appSuiteId, OperationContext context) {
348+
AppVersion latestVersion = this.appVersionService.getLatestCreatedByAppSuiteId(appSuiteId)
349+
.orElseThrow(() -> new AippException(AippErrCode.APP_NOT_FOUND));
350+
if (latestVersion.isPublished()) {
351+
throw new AippException(AippErrCode.APP_HAS_ALREADY);
352+
}
353+
AppBuilderAppDto appDto = this.converterFactory.convert(latestVersion, AppBuilderAppDto.class);
354+
return this.publish(appDto, context);
355+
}
356+
357+
private AppBuilderFlowGraphDto buildAppBuilderFlowGraphDto(AppVersion appVersion, Map<String, Object> appearances) {
358+
return AppBuilderFlowGraphDto.builder()
359+
.name(appVersion.getFlowGraph().getName())
360+
.appearance(appearances)
361+
.build();
362+
}
363+
364+
private void updateValueParams(List<Map<String, Object>> inputParams, Map<String, Object> newConfig) {
365+
if (inputParams == null || newConfig == null || newConfig.isEmpty()) {
366+
return;
367+
}
368+
for (Map.Entry<String, Object> entry : newConfig.entrySet()) {
369+
this.updateInputParam(inputParams, entry);
370+
}
371+
}
372+
373+
private void updateInputParam(List<Map<String, Object>> inputParams, Map.Entry<String, Object> entry) {
374+
String key = entry.getKey();
375+
Object value = entry.getValue();
376+
String[] pathParts = key.split("\\.");
377+
if (pathParts.length == 0) {
378+
return;
379+
}
380+
381+
// 从顶层inputParams开始查找目标节点
382+
List<Map<String, Object>> currentLevel = inputParams;
383+
Map<String, Object> targetNode = null;
384+
for (int i = 0; i < pathParts.length; i++) {
385+
String part = pathParts[i];
386+
387+
// 在当前层级查找name匹配的节点
388+
Map<String, Object> found = this.findConfigByName(currentLevel, part);
389+
if (found == null) {
390+
break;
391+
}
392+
393+
// 如果是最后一层,找到目标节点
394+
if (i == pathParts.length - 1) {
395+
targetNode = found;
396+
break;
397+
}
398+
399+
// 非最后一层,进入下一层(value字段)
400+
Object nextLevelObj = found.get("value");
401+
if (!(nextLevelObj instanceof List)) {
402+
// 下一层不是List,路径无效,跳过
403+
break;
404+
}
405+
currentLevel = ObjectUtils.cast(nextLevelObj);
406+
}
407+
408+
// 更新目标节点的value
409+
if (targetNode != null) {
410+
targetNode.put("value", value);
411+
}
412+
}
413+
414+
private Map<String, Object> findConfigByName(List<Map<String, Object>> configs, String name) {
415+
if (configs == null) {
416+
return null;
417+
}
418+
for (Map<String, Object> config : configs) {
419+
Object nodeName = config.get("name");
420+
if (nodeName != null && StringUtils.equals(name, ObjectUtils.cast(nodeName))) {
421+
return config;
422+
}
423+
}
424+
return null;
425+
}
426+
427+
private Map<String, Object> getParams(Map<String, Object> config) {
428+
Map<String, Object> flowMetaMap =
429+
this.mapSearch(config, "flowMeta", "FlowMeta is not map", "FlowMeta is empty");
430+
Map<String, Object> joberMap = this.mapSearch(flowMetaMap, "jober", "Jober is not map", "Jober is empty");
431+
Map<String, Object> converterMap =
432+
this.mapSearch(joberMap, "converter", "Converter is not map", "Converter is empty");
433+
return this.mapSearch(converterMap, "entity", "entity is not map", "Entity is empty");
434+
}
435+
436+
private Map<String, Object> mapSearch(Map<String, Object> config, String key, String typeErrorMsg,
437+
String emptyErrorMsg) {
438+
Object value = config.get(key);
439+
if (!(value instanceof Map)) {
440+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, typeErrorMsg);
441+
}
442+
Map<String, Object> newMap = ObjectUtils.cast(value);
443+
if (newMap.isEmpty()) {
444+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, emptyErrorMsg);
445+
}
446+
return newMap;
447+
}
448+
449+
private Map<String, Object> getNodeShape(List<?> shapes, String targetId) {
450+
for (Object shape : shapes) {
451+
if (!(shape instanceof Map)) {
452+
continue;
453+
}
454+
Map<String, Object> shapeMap = ObjectUtils.cast(shape);
455+
String idObj = ObjectUtils.cast(shapeMap.get("id"));
456+
if (StringUtils.equals(idObj, targetId)) {
457+
return ObjectUtils.cast(shape);
458+
}
459+
}
460+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Target node is not found");
461+
}
462+
463+
private List<?> getShapes(Map<String, Object> appearances) {
464+
Object pagesObj = appearances.get("pages");
465+
if (!(pagesObj instanceof List)) {
466+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Pages is not list");
467+
}
468+
List<?> pages = ObjectUtils.cast(pagesObj);
469+
if (pages.isEmpty()) {
470+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Pages is empty");
471+
}
472+
Object pageConfig = pages.get(0);
473+
if (!(pageConfig instanceof Map)) {
474+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED,
475+
"The first element of pages is not of map type");
476+
}
477+
Map<String, Object> pageConfigMap = ObjectUtils.cast(pageConfig);
478+
Object shapesObj = pageConfigMap.get("shapes");
479+
if (!(shapesObj instanceof List)) {
480+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Shapes is not an list type");
481+
}
482+
List<?> shapes = ObjectUtils.cast(shapesObj);
483+
if (shapes.isEmpty()) {
484+
throw new AippException(AippErrCode.NODE_CONFIG_UPDATE_FAILED, "Shapes list is empty");
485+
}
486+
return shapes;
487+
}
488+
312489
@Override
313490
@Fitable(id = "default")
314491
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=节点配置更新失败,失败原因:{0}。
151152
90003000=应用模板不存在。

0 commit comments

Comments
 (0)