feat: 支持知识库导入 PPTX 与 XLSX 文档

- 打通 Office 文档桥接解析、解析进度承接与图片引用改写

- 落地 PPTX 按页分块、XLSX 行窗口分块以及预览与检索渲染闭环
This commit is contained in:
2026-04-18 13:01:17 +08:00
parent ad67ba85ad
commit 4130381658
28 changed files with 2876 additions and 120 deletions

View File

@@ -6,6 +6,9 @@ import com.easyagents.document.core.entity.ParseResponse;
import com.easyagents.document.core.entity.ParseResult;
import com.easyagents.document.core.entity.ParseTaskInfo;
import com.easyagents.document.core.entity.ParseTaskStatus;
import com.easyagents.document.pdf.PdfDocumentParseService;
import com.easyagents.document.pptx.PptxDocumentParseService;
import com.easyagents.document.xlsx.XlsxDocumentParseService;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.document.exception.DocumentParseBridgeException;
@@ -37,8 +40,8 @@ public class DocumentParseBridgeServiceImplTest {
*/
@Test
public void shouldParseSuccessfully() {
FakeDocumentParseService parseService = new FakeDocumentParseService();
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService);
FakePdfDocumentParseService parseService = new FakePdfDocumentParseService();
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService, null, null, parseService);
DocumentParsedResult document = bridgeService.parse(buildSource(), DocumentParseScenario.WORKFLOW_TEXT);
@@ -52,8 +55,8 @@ public class DocumentParseBridgeServiceImplTest {
*/
@Test
public void shouldSupportAsyncFlow() {
FakeDocumentParseService parseService = new FakeDocumentParseService();
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService);
FakePdfDocumentParseService parseService = new FakePdfDocumentParseService();
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService, null, null, parseService);
DocumentParseTaskStatus taskStatus = bridgeService.submit(buildSource(), DocumentParseScenario.KNOWLEDGE_IMPORT);
DocumentParseTaskStatus queriedStatus = bridgeService.queryTask("task-1");
@@ -69,9 +72,9 @@ public class DocumentParseBridgeServiceImplTest {
*/
@Test
public void shouldQueryTaskInfoSuccessfully() {
FakeDocumentParseService parseService = new FakeDocumentParseService();
FakePdfDocumentParseService parseService = new FakePdfDocumentParseService();
parseService.taskStatusValue = "completed";
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService);
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(parseService, null, null, parseService);
DocumentParseTaskInfo taskInfo = bridgeService.queryTaskInfo("task-1");
@@ -85,7 +88,7 @@ public class DocumentParseBridgeServiceImplTest {
*/
@Test
public void shouldThrowWhenServiceDisabled() {
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(null);
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(null, null, null, null);
try {
bridgeService.parse(buildSource(), DocumentParseScenario.WORKFLOW_TEXT);
@@ -95,9 +98,29 @@ public class DocumentParseBridgeServiceImplTest {
}
}
private DocumentParseBridgeServiceImpl buildBridgeService(DocumentParseService parseService) {
@Test
public void shouldRoutePptxToDedicatedService() {
FakePptxDocumentParseService pptxService = new FakePptxDocumentParseService();
FakePdfDocumentParseService defaultService = new FakePdfDocumentParseService();
DocumentParseBridgeServiceImpl bridgeService = buildBridgeService(null, pptxService, null, defaultService);
DocumentParsedResult result = bridgeService.parse(buildSource("slides.pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation"), DocumentParseScenario.KNOWLEDGE_IMPORT);
Assert.assertEquals("# pptx", result.getPreferredText());
Assert.assertEquals(1, pptxService.parseCallCount);
Assert.assertEquals(0, defaultService.parseCallCount);
}
private DocumentParseBridgeServiceImpl buildBridgeService(PdfDocumentParseService pdfDocumentParseService,
PptxDocumentParseService pptxDocumentParseService,
XlsxDocumentParseService xlsxDocumentParseService,
DocumentParseService parseService) {
return new DocumentParseBridgeServiceImpl(
parseService,
pdfDocumentParseService,
pptxDocumentParseService,
xlsxDocumentParseService,
new DocumentSourceLoader(new InMemoryFileStorageService()),
new DocumentParseRequestFactory(),
new DocumentParseResultMapper()
@@ -105,8 +128,12 @@ public class DocumentParseBridgeServiceImplTest {
}
private DocumentSourceRef buildSource() {
DocumentSourceRef sourceRef = DocumentSourceRef.ofBytes("demo.pdf", "pdf-data".getBytes(StandardCharsets.UTF_8));
sourceRef.setContentType("application/pdf");
return buildSource("demo.pdf", "application/pdf");
}
private DocumentSourceRef buildSource(String fileName, String contentType) {
DocumentSourceRef sourceRef = DocumentSourceRef.ofBytes(fileName, "pdf-data".getBytes(StandardCharsets.UTF_8));
sourceRef.setContentType(contentType);
sourceRef.setSize(8L);
return sourceRef;
}
@@ -133,13 +160,15 @@ public class DocumentParseBridgeServiceImplTest {
}
}
private static class FakeDocumentParseService implements DocumentParseService {
private static class FakePdfDocumentParseService implements PdfDocumentParseService {
private ParseRequest lastParseRequest;
private String taskStatusValue = "running";
private int parseCallCount;
@Override
public ParseResponse parse(ParseRequest request) {
parseCallCount++;
this.lastParseRequest = request;
return buildResponse();
}
@@ -187,4 +216,36 @@ public class DocumentParseBridgeServiceImplTest {
return response;
}
}
private static class FakePptxDocumentParseService implements PptxDocumentParseService {
private int parseCallCount;
@Override
public ParseResponse parse(ParseRequest request) {
parseCallCount++;
ParseResult result = new ParseResult();
result.setFileName("slides.pptx");
result.setMarkdown("# pptx");
result.setPlainText("pptx");
ParseResponse response = new ParseResponse();
response.setResults(Collections.singletonList(result));
return response;
}
@Override
public ParseTaskStatus submit(ParseRequest request) {
throw new UnsupportedOperationException();
}
@Override
public ParseTaskStatus queryTask(String taskId) {
throw new UnsupportedOperationException();
}
@Override
public ParseResponse queryResult(String taskId) {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -1,6 +1,9 @@
package tech.easyflow.ai.document.support;
import com.easyagents.document.core.entity.ParseRequest;
import com.easyagents.document.core.entity.PdfParseRequest;
import com.easyagents.document.core.entity.PptxParseRequest;
import com.easyagents.document.core.entity.XlsxParseRequest;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.document.model.DocumentParseScenario;
@@ -26,6 +29,7 @@ public class DocumentParseRequestFactoryTest {
Assert.assertFalse(request.getReturnMiddleJson());
Assert.assertFalse(request.getReturnContentList());
Assert.assertFalse(request.getReturnImages());
Assert.assertTrue(request instanceof PdfParseRequest);
}
/**
@@ -41,12 +45,33 @@ public class DocumentParseRequestFactoryTest {
Assert.assertTrue(request.getReturnMiddleJson());
Assert.assertTrue(request.getReturnContentList());
Assert.assertTrue(request.getReturnImages());
Assert.assertTrue(request instanceof PdfParseRequest);
}
/**
* 验证 PPTX / XLSX 会构建对应的强类型请求。
*/
@Test
public void shouldBuildOfficeTypedRequests() {
DocumentParseRequestFactory factory = new DocumentParseRequestFactory();
ParseRequest pptxRequest = factory.build(buildSource("slides.pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation"), DocumentParseScenario.KNOWLEDGE_IMPORT);
ParseRequest xlsxRequest = factory.build(buildSource("table.xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), DocumentParseScenario.KNOWLEDGE_IMPORT);
Assert.assertTrue(pptxRequest instanceof PptxParseRequest);
Assert.assertTrue(xlsxRequest instanceof XlsxParseRequest);
}
private LoadedDocumentSource buildSource() {
return buildSource("demo.pdf", "application/pdf");
}
private LoadedDocumentSource buildSource(String fileName, String contentType) {
LoadedDocumentSource source = new LoadedDocumentSource();
source.setFileName("demo.pdf");
source.setContentType("application/pdf");
source.setFileName(fileName);
source.setContentType(contentType);
source.setContentBytes("pdf-data".getBytes());
source.setSize(8L);
return source;

View File

@@ -4,6 +4,7 @@ import com.easyagents.document.core.entity.ParseArtifacts;
import com.easyagents.document.core.entity.ParseResult;
import com.easyagents.document.core.entity.ParseResponse;
import com.easyagents.document.core.entity.ParseTaskInfo;
import com.easyagents.document.core.entity.ParseTaskStatus;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.document.model.DocumentParseTaskInfo;
@@ -65,6 +66,8 @@ public class DocumentParseResultMapperTest {
ParseTaskInfo taskInfo = new ParseTaskInfo();
taskInfo.setTaskId("task-1");
taskInfo.setStatus("completed");
taskInfo.setProgressPercent(100);
taskInfo.setCurrentStage("completed");
ParseResult result = new ParseResult();
result.setFileName("demo.pdf");
@@ -76,7 +79,33 @@ public class DocumentParseResultMapperTest {
DocumentParseTaskInfo mapped = mapper.map(taskInfo);
Assert.assertEquals("task-1", mapped.getTaskId());
Assert.assertEquals(Integer.valueOf(100), mapped.getProgressPercent());
Assert.assertEquals("completed", mapped.getCurrentStage());
Assert.assertNotNull(mapped.getResult());
Assert.assertEquals("# title", mapped.getResult().getPreferredText());
}
/**
* 验证异步进度字段被完整透传。
*/
@Test
public void shouldMapTaskStatusProgressFields() {
DocumentParseResultMapper mapper = new DocumentParseResultMapper();
ParseTaskStatus status = new ParseTaskStatus();
status.setTaskId("task-2");
status.setStatus("running");
status.setProgressPercent(45);
status.setCurrentStage("ocr");
status.setProcessedItems(9);
status.setTotalItems(20);
status.setStatusMessage("正在识别图片");
tech.easyflow.ai.document.model.DocumentParseTaskStatus mapped = mapper.map(status);
Assert.assertEquals(Integer.valueOf(45), mapped.getProgressPercent());
Assert.assertEquals("ocr", mapped.getCurrentStage());
Assert.assertEquals(Integer.valueOf(9), mapped.getProcessedItems());
Assert.assertEquals(Integer.valueOf(20), mapped.getTotalItems());
Assert.assertEquals("正在识别图片", mapped.getStatusMessage());
}
}

View File

@@ -1,17 +1,33 @@
package tech.easyflow.ai.documentimport.task;
import com.easyagents.document.core.entity.DocumentBlock;
import com.easyagents.document.core.entity.DocumentImage;
import com.easyagents.document.core.entity.DocumentTable;
import com.easyagents.rag.ingestion.model.StrategyConfig;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.web.multipart.MultipartFile;
import tech.easyflow.ai.document.model.DocumentParseArtifacts;
import tech.easyflow.ai.document.model.DocumentParsedResult;
import tech.easyflow.ai.documentimport.DocumentImportKeys;
import tech.easyflow.ai.entity.DocumentChunk;
import tech.easyflow.ai.entity.DocumentImportTask;
import tech.easyflow.ai.enums.DocumentImportTaskStatus;
import tech.easyflow.ai.enums.DocumentProcessStatus;
import tech.easyflow.ai.mapper.DocumentMapper;
import tech.easyflow.ai.service.DocumentImportTaskService;
import tech.easyflow.common.filestorage.FileStorageService;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -84,6 +100,258 @@ public class KnowledgeDocumentImportTaskAppServiceTest {
Assert.assertEquals("新错误", updatedTask.getErrorSummary());
}
/**
* 验证知识库导入会把解析图片上传到对象存储,并同步改写 Markdown 与结构化引用。
*
* @throws Exception 反射调用异常
*/
@Test
public void normalizeParsedImagesForKnowledgeImportShouldUploadAndRewriteReferences() throws Exception {
KnowledgeDocumentImportTaskAppService service = new KnowledgeDocumentImportTaskAppService();
AtomicReference<String> savedPrePathRef = new AtomicReference<String>();
AtomicReference<String> savedFilenameRef = new AtomicReference<String>();
setField(service, "storageService", mockFileStorageService(savedPrePathRef, savedFilenameRef));
tech.easyflow.ai.entity.Document document = new tech.easyflow.ai.entity.Document();
document.setId(BigInteger.valueOf(88));
document.setTitle("产品说明书(终版).pdf");
DocumentParsedResult parsedResult = new DocumentParsedResult();
parsedResult.setMarkdown("图例如下:\n![](images/sample-image.png)");
parsedResult.setPreferredText(parsedResult.getMarkdown());
parsedResult.setPlainText(parsedResult.getMarkdown());
DocumentImage image = new DocumentImage();
image.setName("sample-image.png");
image.setSourcePath("images/sample-image.png");
image.setMimeType("image/png");
image.setDataUrl("data:image/png;base64," + Base64.getEncoder().encodeToString("demo".getBytes(StandardCharsets.UTF_8)));
parsedResult.setImages(new ArrayList<DocumentImage>(List.of(image)));
DocumentBlock block = new DocumentBlock();
block.setImagePath("images/sample-image.png");
parsedResult.setBlocks(new ArrayList<DocumentBlock>(List.of(block)));
DocumentTable table = new DocumentTable();
table.setImagePath("images/sample-image.png");
parsedResult.setTables(new ArrayList<DocumentTable>(List.of(table)));
DocumentParseArtifacts artifacts = new DocumentParseArtifacts();
List<Map<String, Object>> contentList = new ArrayList<Map<String, Object>>();
Map<String, Object> contentItem = new LinkedHashMap<String, Object>();
contentItem.put("img_path", "images/sample-image.png");
contentList.add(contentItem);
artifacts.setContentList(contentList);
Map<String, Object> xlsxArtifact = new LinkedHashMap<String, Object>();
List<Map<String, Object>> sheetImages = new ArrayList<Map<String, Object>>();
sheetImages.add(new LinkedHashMap<String, Object>() {{
put("sheetName", "Sheet1");
put("sourcePaths", new ArrayList<String>(List.of("images/sample-image.png")));
}});
xlsxArtifact.put("sheetImages", sheetImages);
artifacts.setExtraJsonArtifacts(new LinkedHashMap<String, Object>() {{
put("xlsx", xlsxArtifact);
}});
parsedResult.setArtifacts(artifacts);
Method method = KnowledgeDocumentImportTaskAppService.class.getDeclaredMethod(
"normalizeParsedImagesForKnowledgeImport",
tech.easyflow.ai.entity.Document.class,
DocumentParsedResult.class
);
method.setAccessible(true);
DocumentParsedResult normalized = (DocumentParsedResult) method.invoke(service, document, parsedResult);
Assert.assertNotNull(normalized);
Assert.assertEquals("knowledge-parse/88_产品说明书_终版/images", savedPrePathRef.get());
Assert.assertEquals("sample-image.png", savedFilenameRef.get());
String expectedUrl = "http://localhost:39000/easyflow/attachment/knowledge-parse/88_产品说明书_终版/images/sample-image.png";
Assert.assertTrue(normalized.getMarkdown().contains(expectedUrl));
Assert.assertEquals(expectedUrl, normalized.getBlocks().get(0).getImagePath());
Assert.assertEquals(expectedUrl, normalized.getTables().get(0).getImagePath());
Assert.assertEquals(expectedUrl, normalized.getImages().get(0).getSourcePath());
Assert.assertNull(normalized.getImages().get(0).getDataUrl());
Object rewrittenContentList = normalized.getArtifacts().getContentList();
Assert.assertTrue(rewrittenContentList instanceof List<?>);
Assert.assertEquals(expectedUrl, ((Map<?, ?>) ((List<?>) rewrittenContentList).get(0)).get("img_path"));
Object rewrittenSheetImages = ((Map<?, ?>) normalized.getArtifacts().getExtraJsonArtifacts().get("xlsx")).get("sheetImages");
Assert.assertTrue(rewrittenSheetImages instanceof List<?>);
Object sourcePaths = ((Map<?, ?>) ((List<?>) rewrittenSheetImages).get(0)).get("sourcePaths");
Assert.assertEquals(expectedUrl, ((List<?>) sourcePaths).get(0));
}
/**
* 验证 PPTX 会基于页级工件生成稳定的知识库分块。
*
* @throws Exception 反射调用异常
*/
@Test
public void buildOfficeDocumentChunksShouldSplitPptxBySlide() throws Exception {
KnowledgeDocumentImportTaskAppService service = new KnowledgeDocumentImportTaskAppService();
tech.easyflow.ai.entity.Document document = new tech.easyflow.ai.entity.Document();
document.setId(BigInteger.valueOf(101));
document.setCollectionId(BigInteger.valueOf(201));
document.setTitle("季度汇报.pptx");
Map<String, Object> parseArtifactSummary = new LinkedHashMap<String, Object>();
List<Map<String, Object>> slides = new ArrayList<Map<String, Object>>();
slides.add(new LinkedHashMap<String, Object>() {{
put("slideIndex", 0);
put("title", "封面");
put("ocrMarkdown", "本页介绍季度目标。");
put("imagePath", "https://example.com/slides/slide-001.png");
put("imageName", "slide-001-page");
}});
slides.add(new LinkedHashMap<String, Object>() {{
put("slideIndex", 1);
put("title", "经营分析");
put("ocrMarkdown", "收入同比增长 18%。");
put("imagePath", "https://example.com/slides/slide-002.png");
put("imageName", "slide-002-page");
}});
parseArtifactSummary.put("slides", slides);
Method method = KnowledgeDocumentImportTaskAppService.class.getDeclaredMethod(
"buildOfficeDocumentChunks",
tech.easyflow.ai.entity.Document.class,
String.class,
StrategyConfig.class,
Map.class
);
method.setAccessible(true);
@SuppressWarnings("unchecked")
List<DocumentChunk> chunks = (List<DocumentChunk>) method.invoke(
service,
document,
"pptx",
null,
parseArtifactSummary
);
Assert.assertEquals(2, chunks.size());
DocumentChunk firstChunk = chunks.get(0);
Assert.assertTrue(firstChunk.getContent().contains("Slide 1"));
Assert.assertTrue(firstChunk.getContent().contains("本页介绍季度目标"));
Assert.assertEquals("https://example.com/slides/slide-001.png",
((List<?>) firstChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_IMAGE_REFS)).get(0));
Assert.assertEquals(1, firstChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_PAGE_INDEX));
Assert.assertTrue(String.valueOf(firstChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_RENDER_MARKDOWN))
.contains("slide-001.png"));
}
/**
* 验证 XLSX 纯图片 Sheet 不会退化为空内容,并会输出稳定图片引用。
*
* @throws Exception 反射调用异常
*/
@Test
public void buildOfficeDocumentChunksShouldKeepImageOnlyXlsxSheetReferences() throws Exception {
KnowledgeDocumentImportTaskAppService service = new KnowledgeDocumentImportTaskAppService();
tech.easyflow.ai.entity.Document document = new tech.easyflow.ai.entity.Document();
document.setId(BigInteger.valueOf(102));
document.setCollectionId(BigInteger.valueOf(202));
document.setTitle("巡检记录.xlsx");
Map<String, Object> parseArtifactSummary = new LinkedHashMap<String, Object>();
List<Map<String, Object>> sheets = new ArrayList<Map<String, Object>>();
sheets.add(new LinkedHashMap<String, Object>() {{
put("sheetName", "图片页");
put("sheetIndex", 0);
put("rows", new ArrayList<Map<String, Object>>());
}});
parseArtifactSummary.put("sheets", sheets);
List<Map<String, Object>> cellImages = new ArrayList<Map<String, Object>>();
cellImages.add(new LinkedHashMap<String, Object>() {{
put("sheetName", "图片页");
put("referenceKey", "image-sheet-r2c2-001");
put("sourcePath", "https://example.com/xlsx/sheet/image-001.jpeg");
put("anchorCell", "B2");
put("ocrText", "设备状态正常");
put("fromRow", 1);
}});
parseArtifactSummary.put("cellImages", cellImages);
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setRowsPerChunk(10);
Method method = KnowledgeDocumentImportTaskAppService.class.getDeclaredMethod(
"buildOfficeDocumentChunks",
tech.easyflow.ai.entity.Document.class,
String.class,
StrategyConfig.class,
Map.class
);
method.setAccessible(true);
@SuppressWarnings("unchecked")
List<DocumentChunk> chunks = (List<DocumentChunk>) method.invoke(
service,
document,
"xlsx",
strategyConfig,
parseArtifactSummary
);
Assert.assertEquals(1, chunks.size());
DocumentChunk onlyChunk = chunks.get(0);
Assert.assertTrue(onlyChunk.getContent().contains("图片 OCR"));
Assert.assertTrue(onlyChunk.getContent().contains("设备状态正常"));
Assert.assertEquals("图片页", onlyChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_SHEET_NAME));
Assert.assertEquals("https://example.com/xlsx/sheet/image-001.jpeg",
((List<?>) onlyChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_IMAGE_REFS)).get(0));
String renderMarkdown = String.valueOf(onlyChunk.getOptions().get(DocumentImportKeys.KEY_DOCUMENT_RENDER_MARKDOWN));
Assert.assertTrue(renderMarkdown.contains("[IMG:image-sheet-r2c2-001]"));
Assert.assertTrue(renderMarkdown.contains("![image-sheet-r2c2-001](https://example.com/xlsx/sheet/image-001.jpeg)"));
}
/**
* 验证空白 Sheet 不会被误判成纯图片分块。
*
* @throws Exception 反射调用异常
*/
@Test
public void buildOfficeDocumentChunksShouldSkipBlankXlsxSheetWithoutImages() throws Exception {
KnowledgeDocumentImportTaskAppService service = new KnowledgeDocumentImportTaskAppService();
tech.easyflow.ai.entity.Document document = new tech.easyflow.ai.entity.Document();
document.setId(BigInteger.valueOf(103));
document.setCollectionId(BigInteger.valueOf(203));
document.setTitle("空白工作簿.xlsx");
Map<String, Object> parseArtifactSummary = new LinkedHashMap<String, Object>();
parseArtifactSummary.put("sheets", new ArrayList<Map<String, Object>>(List.of(new LinkedHashMap<String, Object>() {{
put("sheetName", "空白页");
put("sheetIndex", 0);
put("rows", new ArrayList<Map<String, Object>>());
}})));
parseArtifactSummary.put("cellImages", new ArrayList<Map<String, Object>>());
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setRowsPerChunk(10);
Method method = KnowledgeDocumentImportTaskAppService.class.getDeclaredMethod(
"buildOfficeDocumentChunks",
tech.easyflow.ai.entity.Document.class,
String.class,
StrategyConfig.class,
Map.class
);
method.setAccessible(true);
@SuppressWarnings("unchecked")
List<DocumentChunk> chunks = (List<DocumentChunk>) method.invoke(
service,
document,
"xlsx",
strategyConfig,
parseArtifactSummary
);
Assert.assertTrue(chunks.isEmpty());
}
private static DocumentMapper mockDocumentMapper(tech.easyflow.ai.entity.Document persistedDocument,
AtomicReference<tech.easyflow.ai.entity.Document> updatedDocumentRef) {
return (DocumentMapper) Proxy.newProxyInstance(
@@ -116,6 +384,22 @@ public class KnowledgeDocumentImportTaskAppServiceTest {
);
}
private static FileStorageService mockFileStorageService(AtomicReference<String> savedPrePathRef,
AtomicReference<String> savedFilenameRef) {
return (FileStorageService) Proxy.newProxyInstance(
FileStorageService.class.getClassLoader(),
new Class<?>[]{FileStorageService.class},
(proxy, method, args) -> {
if ("save".equals(method.getName()) && args != null && args.length == 2 && args[0] instanceof MultipartFile file) {
savedPrePathRef.set((String) args[1]);
savedFilenameRef.set(file.getOriginalFilename());
return "http://localhost:39000/easyflow/attachment/" + args[1] + "/" + file.getOriginalFilename();
}
return defaultValue(method.getReturnType());
}
);
}
private static void setField(Object target, String fieldName, Object value) throws Exception {
Field field = KnowledgeDocumentImportTaskAppService.class.getDeclaredField(fieldName);
field.setAccessible(true);