Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app-builder/plugins/aipp-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@
<groupId>modelengine.fit.jade.service</groupId>
<artifactId>knowledge-service</artifactId>
</dependency>
<dependency>
<groupId>modelengine.jade.service</groupId>
<artifactId>aipp-template-render-service</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private Object invokeMethod(Method method, Object[] args, Object current)
else {
msg = localeService.localize(UI_WORD_KEY);
}
this.aippLogService.insertLogWithInterception(AippInstLogType.ERROR.name(),
this.aippLogService.insertLog(AippInstLogType.ERROR.name(),
AippLogData.builder().msg(msg).build(), ctx.getBusinessData());
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ private Object wrapException(AppTaskInstanceService instanceService, AippLogServ
.setStatus(MetaInstStatusEnum.ERROR.name())
.build(), ctx.getOperationContext());
// 更新日志类型为HIDDEN_FORM
logService.insertLogWithInterception(AippInstLogType.ERROR.name(), AippLogData.builder().msg(e.getMessage()).build(),
logService.insertLog(AippInstLogType.ERROR.name(), AippLogData.builder().msg(e.getMessage()).build(),
ctx.getBusinessData());
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private String saveFormToLog(String appId, Map<String, Object> businessData, Str
logData.setFormAppearance(JsonUtils.toJsonString(formDataMap.get(AippConst.FORM_APPEARANCE_KEY)));
logData.setFormData(JsonUtils.toJsonString(formDataMap.get(AippConst.FORM_DATA_KEY)));
// 子应用/工作流的结束节点表单不需要在历史记录展示
return this.aippLogService.insertLogWithInterception((this.isExistParent(businessData)
return this.aippLogService.insertLog((this.isExistParent(businessData)
? AippInstLogType.HIDDEN_FORM
: AippInstLogType.FORM).name(), logData, businessData);
}
Expand All @@ -211,7 +211,7 @@ private void logFinalOutput(Map<String, Object> businessData, String aippInstId)
if (!checkEnableLog(businessData)) {
logType = AippInstLogType.HIDDEN_MSG;
}
this.aippLogService.insertLogWithInterception(logType.name(), AippLogData.builder().msg(logMsg).build(), businessData);
this.aippLogService.insertLog(logType.name(), AippLogData.builder().msg(logMsg).build(), businessData);
this.beanContainer.all(AppFlowFinishObserver.class)
.stream()
.<AppFlowFinishObserver>map(BeanFactory::get)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private String insertFormLog(List<AppBuilderFormProperty> formProperties, String
Object appearance = formDataMap.get(AippConst.FORM_APPEARANCE_KEY);
logData.setFormAppearance(ObjectUtils.cast(JsonUtils.toJsonString(appearance)));
logData.setFormData(ObjectUtils.cast(JsonUtils.toJsonString(formDataMap.get(AippConst.FORM_DATA_KEY))));
return this.aippLogService.insertLogWithInterception(AippInstLogType.FORM.name(), logData, businessData);
return this.aippLogService.insertLog(AippInstLogType.FORM.name(), logData, businessData);
}

private void updateInstance(String sheetId, String nodeId, Map<String, Object> businessData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private void addAnswer(AippLlmMeta llmMeta, String answer, Map<String, Object> p
llmOutput.put("output", output);
Optional<ResponsibilityResult> formatOutput = this.formatterChain.handle(llmOutput);
String logMsg = formatOutput.map(ResponsibilityResult::text).orElse(answer);
this.aippLogService.insertLogWithInterception(AippInstLogType.META_MSG.name(),
this.aippLogService.insertLog(AippInstLogType.META_MSG.name(),
AippLogData.builder().msg(logMsg).build(),
businessData);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
* This file is a part of the ModelEngine Project.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

package modelengine.fit.jober.aipp.fitable;

import modelengine.fit.jade.aipp.template.render.TemplateService;
import modelengine.fit.jober.aipp.entity.AippLogData;
import modelengine.fit.jober.aipp.enums.AippInstLogType;
import modelengine.fit.jober.aipp.service.AippLogService;
import modelengine.fit.jober.aipp.util.DataUtils;
import modelengine.fit.waterflow.spi.FlowableService;
import modelengine.fitframework.annotation.Component;
import modelengine.fitframework.annotation.Fitable;
import modelengine.fitframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;

/**
* 直接回复节点实现
*
* @author 孙怡菲
* @since 2025-09-11
*/
@Component
public class ReplyNode implements FlowableService {
private final static String TEMPLATE_KEY = "template";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image static的属性放到最上方


private final static String VARIABLES_KEY = "variables";

private final AippLogService aippLogService;

private final TemplateService templateService;

public ReplyNode(AippLogService aippLogService, TemplateService templateService) {
this.aippLogService = aippLogService;
this.templateService = templateService;
}

@Override
@Fitable("modelengine.fit.jober.aipp.fitable.ReplyNodeComponent")
public List<Map<String, Object>> handleTask(List<Map<String, Object>> flowData) {
Map<String, Object> businessData = DataUtils.getBusiness(flowData);
String template = ObjectUtils.cast(businessData.get(TEMPLATE_KEY));
Map<String, Object> args = ObjectUtils.cast(businessData.get(VARIABLES_KEY));
String msg = this.templateService.renderTemplate(template, args);
this.sendMsg(msg, businessData);
return flowData;
}

private void sendMsg(String msg, Map<String, Object> businessData) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image 这里不应该基于技术语义体现在业务语义上,如果出现外界需要显式感知是否触发AOP的场景,则说明该业务场景已经不太适合使用AOP实现了。另外发现这里已经没有这种区分了,所以还是修改为insertLog的命名,然后保留会触发AOP的实现就行了

this.aippLogService.insertLog(AippInstLogType.MSG.name(),
AippLogData.builder().msg(msg).build(),
businessData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public interface AippLogService {
* @param businessData 业务数据
* @return 返回插入的日志id
*/
String insertLogWithInterception(String logType, AippLogData logData, Map<String, Object> businessData);
String insertLog(String logType, AippLogData logData, Map<String, Object> businessData);

/**
* 插入ERROR类型的历史记录
Expand Down Expand Up @@ -185,13 +185,4 @@ List<AippInstLogDataDto> queryAippRecentInstLogAfterSplice(String aippId, String
* @param logIds 表示指定的日志 id 列表的 {@link List}{@code <}{@link Long}{@code >}。
*/
void deleteLogs(List<Long> logIds);

/**
* 插入一条日志记录,但不触发发送逻辑。
*
* @param logType 表示日志类型的 {@link String}。
* @param logData 表示日志主体数据的 {@link AippLogData} 实例。
* @param businessData 表示业务数据的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。
*/
void insertLog(String logType, AippLogData logData, Map<String, Object> businessData);
}
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public void deleteAippPreviewLog(String previewAippId, OperationContext context)
* @return 日志id
*/
@Override
public String insertLogWithInterception(String logType, AippLogData logData, Map<String, Object> businessData) {
public String insertLog(String logType, AippLogData logData, Map<String, Object> businessData) {
AippLogCreateDto logCreateDto = this.buildAippLogCreateDto(logType, logData, businessData);
if (logCreateDto == null) {
return null;
Expand Down Expand Up @@ -416,7 +416,7 @@ private Boolean isEnableLog(Map<String, Object> businessData) {
@Override
public void insertErrorLog(String msg, List<Map<String, Object>> flowData) {
AippLogData logData = AippLogData.builder().msg(msg).build();
insertLogWithInterception(AippInstLogType.ERROR.name(), logData, DataUtils.getBusiness(flowData));
this.insertLog(AippInstLogType.ERROR.name(), logData, DataUtils.getBusiness(flowData));
}

/**
Expand Down Expand Up @@ -512,13 +512,4 @@ public void deleteLogs(List<Long> logIds) {
}
this.aippLogMapper.deleteInstanceLogs(logIds);
}

@Override
public void insertLog(String logType, AippLogData logData, Map<String, Object> businessData) {
AippLogCreateDto logCreateDto = this.buildAippLogCreateDto(logType, logData, businessData);
if (logCreateDto == null) {
return;
}
this.aippLogMapper.insertOne(logCreateDto);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,10 @@
"type": "textConcatenateNodeState",
"name": "Text Joiner",
"uniqueName": ""
},
{
"type": "replyNodeState",
"name": "Reply",
"uniqueName": ""
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,10 @@
"type": "textConcatenateNodeState",
"name": "文本拼接",
"uniqueName": ""
},
{
"type": "replyNodeState",
"name": "直接回复",
"uniqueName": ""
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void testException() {

doNothing().when(this.appTaskInstanceService).update(any(), any());
when(this.localeService.localize(any())).thenReturn("xxxxxxx");
when(this.aippLogService.insertLogWithInterception(any(), any(), any())).thenReturn("xxxxxx");
when(this.aippLogService.insertLog(any(), any(), any())).thenReturn("xxxxxx");

// when.
RunContext runContext = new RunContext(businessData, new OperationContext());
Expand All @@ -84,6 +84,6 @@ public void testException() {
Assertions.assertEquals(MetaInstStatusEnum.ERROR.name(), instance.getEntity().getStatus().get());

verify(this.localeService, times(1)).localize(eq("aipp.service.impl.AippRunTimeServiceImpl"));
verify(this.aippLogService, times(1)).insertLogWithInterception(eq(AippInstLogType.ERROR.name()), any(), any());
verify(this.aippLogService, times(1)).insertLog(eq(AippInstLogType.ERROR.name()), any(), any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void testExceptionLogWhenThrowException() {
.exceptionLog(this.appTaskInstanceService, this.logService)
.run(runContext, null);
verify(this.appTaskInstanceService, times(1)).update(any(), any());
verify(this.logService, times(1)).insertLogWithInterception(any(), any(), any());
verify(this.logService, times(1)).insertLog(any(), any(), any());
}

@Test
Expand All @@ -126,6 +126,6 @@ public void testChatAndExceptionLog() {
verify(this.appChatSessionService, times(1)).addSession(any(), any());
verify(this.appChatSSEService, times(2)).send(any(), any());
verify(this.appTaskInstanceService, times(0)).update(any(), any());
verify(this.logService, times(0)).insertLogWithInterception(any(), any(), any());
verify(this.logService, times(0)).insertLog(any(), any(), any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void should_ok_when_callback_with_normal_formatter_chain() {
}).when(this.formatterChain).handle(any());

this.aippFlowEndCallback.callback(TestUtils.buildFlowDataWithExtraConfig(buildBusinessData(), null));
verify(this.aippLogService).insertLogWithInterception(eq(AippInstLogType.META_MSG.name()), any(), any());
verify(this.aippLogService).insertLog(eq(AippInstLogType.META_MSG.name()), any(), any());
}

@Test
Expand All @@ -179,7 +179,7 @@ void test_callback_should_ok_when_test_with_form_data() {

this.aippFlowEndCallback.callback(TestUtils.buildFlowDataWithExtraConfig(businessData, null));
verify(this.conversationRecordService).insertConversationRecord(any());
verify(this.aippLogService).insertLogWithInterception(eq(AippInstLogType.FORM.name()), any(), any());
verify(this.aippLogService).insertLog(eq(AippInstLogType.FORM.name()), any(), any());
}

static class MessageItemStub implements MessageItem {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
* This file is a part of the ModelEngine Project.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

package modelengine.fit.jober.aipp.fitable;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image 缺少版权头


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import modelengine.fit.jade.aipp.template.render.TemplateService;
import modelengine.fit.jober.aipp.entity.AippLogData;
import modelengine.fit.jober.aipp.enums.AippInstLogType;
import modelengine.fit.jober.aipp.service.AippLogService;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* {@link ReplyNode}的测试用例。
*
* @author 孙怡菲
* @since 2025-09-17
*/
class ReplyNodeTest {
private AippLogService aippLogService;
private TemplateService templateService;
private ReplyNode replyNode;

@BeforeEach
void setUp() {
this.aippLogService = mock(AippLogService.class);
this.templateService = mock(TemplateService.class);
this.replyNode = new ReplyNode(this.aippLogService, this.templateService);
}

@Test
void shouldOkAndInsertLog() {
Map<String, Object> businessData = new HashMap<>();
String template = "你好,{{name}},欢迎回来!";
String expectedMsg = "你好,小明,欢迎回来";
businessData.put("template", template);
Map<String, Object> variables = new HashMap<>();
variables.put("name", "小明");
businessData.put("variables", variables);

List<Map<String, Object>> flowData = new ArrayList<>();
Map<String, Object> flowItem = new HashMap<>();
flowItem.put("businessData", businessData);
flowData.add(flowItem);

when(templateService.renderTemplate(template, variables)).thenReturn(expectedMsg);

List<Map<String, Object>> result = this.replyNode.handleTask(flowData);

assertEquals(flowData, result);

ArgumentCaptor<AippLogData> logCaptor = ArgumentCaptor.forClass(AippLogData.class);
verify(this.aippLogService, times(1)).insertLog(
eq(AippInstLogType.MSG.name()),
logCaptor.capture(),
eq(businessData)
);

AippLogData logData = logCaptor.getValue();
assertNotNull(logData);
assertEquals(expectedMsg, logData.getMsg());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ void shouldReturnNullWhenCallInsertLogWithInvalidFormData() {
Map<String, Object> businessData = MapBuilder.get(() -> new HashMap<String, Object>())
.put(AippConst.BS_HTTP_CONTEXT_KEY, "{\"account\":\"123\"}")
.build();
Assertions.assertNull(this.aippLogService.insertLogWithInterception(AippInstLogType.FORM.name(), aippLogData, businessData));
Assertions.assertNull(this.aippLogService.insertLog(AippInstLogType.FORM.name(), aippLogData, businessData));
}

@Test
Expand All @@ -433,7 +433,7 @@ void shouldThrowWhenCallInsertLogWithInvalidMsgData() {
Map<String, Object> businessData = MapBuilder.get(() -> new HashMap<String, Object>())
.put(AippConst.BS_HTTP_CONTEXT_KEY, "{\"account\":\"123\"}").build();
Assertions.assertThrows(NullPointerException.class,
() -> this.aippLogService.insertLogWithInterception(AippInstLogType.MSG.name(), aippLogData, businessData));
() -> this.aippLogService.insertLog(AippInstLogType.MSG.name(), aippLogData, businessData));
}

@Test
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/assets/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const FileExtractionIcon = (props) => <Icon component={() => (<BaseIcons.FileExt
const LoopIcon = (props) => <Icon component={() => (<BaseIcons.Loop />)} {...props} />;
const PairingIcon = (props) => <Icon component={() => (<BaseIcons.Pairing />)} {...props} />;
const TextConcatenateIcon = (props) => <BaseIcons.TextConcatenate {...props} />;
const ReplyIcon = (props) => <BaseIcons.Reply {...props} />;

export {
LeftArrowIcon,
Expand Down Expand Up @@ -125,6 +126,7 @@ export {
FileExtractionIcon,
LoopIcon,
PairingIcon,
TextConcatenateIcon
TextConcatenateIcon,
ReplyIcon
}

12 changes: 12 additions & 0 deletions frontend/src/components/icons/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -985,5 +985,17 @@ export const BaseIcons = {
<rect id="矩形 483" width="4.266985" height="1.066746" x="8.716309" y="11.916016" rx="0.533373" fill="rgb(57,194,149)" />
</g>
</svg>
),
Reply:()=>(
<svg viewBox="0 0 28 28" width="28.000000" height="28.000000" fill="none" clip-path="url(#clipPath_1)" customFrame="url(#clipPath_1)">
<defs>
<clipPath id="clipPath_1">
<rect width="28.000000" height="28.000000" x="0.000000" y="0.000000" rx="14.000000" fill="rgb(255,255,255)" transform="matrix(-1,0,0,1,28,0)" />
</clipPath>
</defs>
<rect id="结束" width="28.000000" height="28.000000" x="0.000000" y="0.000000" rx="14.000000" fill="rgb(137,136,255)" transform="matrix(-1,0,0,1,28,0)" />
<rect id="结束" width="26.833334" height="26.833334" x="0.583333" y="0.583333" rx="13.416667" stroke="rgb(240,243,250)" stroke-opacity="0" stroke-width="1.16666663" transform="matrix(-1,0,0,1,28,0)" />
<path id="减去顶层" d="M8.16667 0C12.677 0 16.3333 3.13401 16.3333 7C16.3333 10.866 12.677 14 8.16667 14C6.80776 14 5.52637 13.7155 4.39914 13.2122C4.2316 13.1374 4.03897 13.1381 3.87564 13.2217L2.23882 14.0595C1.83909 14.2641 1.36778 13.9593 1.39046 13.5108L1.50283 11.289C1.50283 11.1426 1.46146 10.9995 1.37139 10.884C0.50509 9.77265 0 8.43689 0 7C0 3.13401 3.65634 0 8.16667 0ZM4.08333 5.83333C4.72767 5.83333 5.25 6.35567 5.25 7C5.25 7.64433 4.72767 8.16667 4.08333 8.16667C3.439 8.16667 2.91667 7.64433 2.91667 7C2.91667 6.35567 3.439 5.83333 4.08333 5.83333ZM7 7C7 7.64433 7.52233 8.16667 8.16667 8.16667C8.811 8.16667 9.33333 7.64433 9.33333 7C9.33333 6.35567 8.811 5.83333 8.16667 5.83333C7.52233 5.83333 7 6.35567 7 7ZM12.25 5.83333C12.8943 5.83333 13.4167 6.35567 13.4167 7C13.4167 7.64433 12.8943 8.16667 12.25 8.16667C11.6057 8.16667 11.0833 7.64433 11.0833 7C11.0833 6.35567 11.6057 5.83333 12.25 5.83333Z" fill="rgb(255,255,255)" fill-rule="evenodd" transform="matrix(-1,0,0,1,22.1665,6.41602)" />
</svg>
)
}
Loading