RED-8825: general layoutparsing improvements

* fix tests
This commit is contained in:
Kilian Schuettler 2024-04-30 11:55:18 +02:00
parent f0a70a5242
commit ae46c5f1ca
5 changed files with 103 additions and 67 deletions

View File

@ -53,6 +53,7 @@ import com.knecon.fforesight.service.layoutparser.processor.services.classificat
import com.knecon.fforesight.service.layoutparser.processor.services.classification.DocuMineClassificationService; import com.knecon.fforesight.service.layoutparser.processor.services.classification.DocuMineClassificationService;
import com.knecon.fforesight.service.layoutparser.processor.services.classification.RedactManagerClassificationService; import com.knecon.fforesight.service.layoutparser.processor.services.classification.RedactManagerClassificationService;
import com.knecon.fforesight.service.layoutparser.processor.services.factory.DocumentGraphFactory; import com.knecon.fforesight.service.layoutparser.processor.services.factory.DocumentGraphFactory;
import com.knecon.fforesight.service.layoutparser.processor.services.graphics.Box;
import com.knecon.fforesight.service.layoutparser.processor.services.graphics.GraphicExtractorService; import com.knecon.fforesight.service.layoutparser.processor.services.graphics.GraphicExtractorService;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.DocumentDataMapper; import com.knecon.fforesight.service.layoutparser.processor.services.mapper.DocumentDataMapper;
import com.knecon.fforesight.service.layoutparser.processor.services.mapper.TaasDocumentDataMapper; import com.knecon.fforesight.service.layoutparser.processor.services.mapper.TaasDocumentDataMapper;
@ -268,7 +269,7 @@ public class LayoutParsingPipeline {
TextRulingsClassifier.classifyUnderlinedAndStrikethroughText(words, cleanRulings); TextRulingsClassifier.classifyUnderlinedAndStrikethroughText(words, cleanRulings);
var graphics = graphicExtractorService.extractPathElementGraphics(originDocument, pdPage, pageNumber, cleanRulings, stripper.getTextPositionSequences(), false); List<Box> graphics = graphicExtractorService.extractPathElementGraphics(originDocument, pdPage, pageNumber, cleanRulings, stripper.getTextPositionSequences(), false);
pdfImages.computeIfAbsent(pageNumber, x -> new ArrayList<>()) pdfImages.computeIfAbsent(pageNumber, x -> new ArrayList<>())
.addAll(graphics.stream() .addAll(graphics.stream()

View File

@ -164,10 +164,11 @@ public class RedactManagerBlockificationService {
previous = block; previous = block;
} }
if (!textPositions.isEmpty()) {
visualizations.addTextBlockVisualizations(chunkBlockList.stream() visualizations.addTextBlockVisualizations(chunkBlockList.stream()
.map(tb -> (TextPageBlock) tb) .map(tb -> (TextPageBlock) tb)
.toList(), textPositions.get(0).getPage()); .toList(), textPositions.get(0).getPage());
}
return new ClassificationPage(chunkBlockList); return new ClassificationPage(chunkBlockList);
} }

View File

@ -34,7 +34,7 @@ public class LayoutparserEnd2EndTest extends AbstractTest {
@Test @Test
public void testLayoutParserEndToEnd() { public void testLayoutParserEndToEnd() {
String filePath = "/home/kschuettler/Dokumente/TestFiles/RotateTextWithRulingsTestFile.pdf"; String filePath = "files/syngenta/CustomerFiles/54 Fludioxonil - EU AIR3 - Document E1 - Listing of Community and Member States MRLs.pdf";
runForFile(filePath); runForFile(filePath);
} }

View File

@ -52,28 +52,16 @@ public class PdfSegmentationServiceTest extends AbstractTest {
@Autowired @Autowired
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Autowired
private RedactManagerClassificationService redactManagerClassificationService;
@Autowired
private SectionsBuilderService sectionsBuilderService;
@SneakyThrows @SneakyThrows
public ClassificationDocument buildClassificationDocument(File originDocument, TableServiceResponse tableServiceResponse) { public ClassificationDocument buildClassificationDocument(File originDocument, TableServiceResponse tableServiceResponse) {
ClassificationDocument classificationDocument = layoutParsingPipeline.parseLayout(LayoutParsingType.REDACT_MANAGER, return layoutParsingPipeline.parseLayout(LayoutParsingType.REDACT_MANAGER,
originDocument, originDocument,
new ImageServiceResponse(), new ImageServiceResponse(),
tableServiceResponse, tableServiceResponse,
new VisualLayoutParsingResponse(), new VisualLayoutParsingResponse(),
Map.of("file","document")); Map.of("file", "document"));
redactManagerClassificationService.classifyDocument(classificationDocument);
sectionsBuilderService.buildSections(classificationDocument);
return classificationDocument;
} }
@ -127,13 +115,13 @@ public class PdfSegmentationServiceTest extends AbstractTest {
ClassificationDocument classificationDocument = buildClassificationDocument(pdfFileResource.getFile()); ClassificationDocument classificationDocument = buildClassificationDocument(pdfFileResource.getFile());
assertThat(classificationDocument.getHeaders() assertThat(classificationDocument.getHeaders()
.get(0).getTextBlocks().size()).isEqualTo(3); .get(0).getTextBlocks().size()).isEqualTo(1);
assertThat(classificationDocument.getHeaders() assertThat(classificationDocument.getHeaders()
.get(0).getTextBlocks() .get(0).getTextBlocks()
.get(0).getSequences().size()).isEqualTo(8); .get(0).getSequences().size()).isEqualTo(12);
assertThat(classificationDocument.getHeaders() assertThat(classificationDocument.getHeaders()
.get(0).getTextBlocks() .get(0).getTextBlocks()
.get(0).toString()).isEqualTo(textToSearch); .get(0).toString()).contains(textToSearch);
Document document = DocumentGraphFactory.buildDocumentGraph(LayoutParsingType.REDACT_MANAGER, classificationDocument); Document document = DocumentGraphFactory.buildDocumentGraph(LayoutParsingType.REDACT_MANAGER, classificationDocument);
@ -157,7 +145,11 @@ public class PdfSegmentationServiceTest extends AbstractTest {
.flatMap(paragraph -> paragraph.getTables() .flatMap(paragraph -> paragraph.getTables()
.stream()) .stream())
.collect(Collectors.toList())).isNotEmpty(); .collect(Collectors.toList())).isNotEmpty();
var tables = document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList(); var tables = document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList();
// Quality of the table parsing is not good, because the file is rotated at scanning. // Quality of the table parsing is not good, because the file is rotated at scanning.
// We only asset that the table border is not the page border. // We only asset that the table border is not the page border.
@ -179,12 +171,12 @@ public class PdfSegmentationServiceTest extends AbstractTest {
imageServiceResponse.getData() imageServiceResponse.getData()
.forEach(imageMetadata -> images.computeIfAbsent(imageMetadata.getPosition().getPageNumber(), x -> new ArrayList<>()) .forEach(imageMetadata -> images.computeIfAbsent(imageMetadata.getPosition().getPageNumber(), x -> new ArrayList<>())
.add(new ClassifiedImage(new Rectangle2D.Double(imageMetadata.getPosition().getX1(), .add(new ClassifiedImage(new Rectangle2D.Double(imageMetadata.getPosition().getX1(),
imageMetadata.getPosition().getY1(), imageMetadata.getPosition().getY1(),
imageMetadata.getGeometry().getWidth(), imageMetadata.getGeometry().getWidth(),
imageMetadata.getGeometry().getHeight()), imageMetadata.getGeometry().getHeight()),
ImageType.valueOf(imageMetadata.getClassification().getLabel().toUpperCase(Locale.ROOT)), ImageType.valueOf(imageMetadata.getClassification().getLabel().toUpperCase(Locale.ROOT)),
imageMetadata.isAlpha(), imageMetadata.isAlpha(),
imageMetadata.getPosition().getPageNumber()))); imageMetadata.getPosition().getPageNumber())));
System.out.println("object"); System.out.println("object");
} }
@ -196,11 +188,22 @@ public class PdfSegmentationServiceTest extends AbstractTest {
ClassPathResource pdfFileResource = new ClassPathResource("files/syngenta/CustomerFiles/SinglePages/Spanning Cells - Page131_S-Metolachlor_RAR_01_Volume_1_2018-09-06.pdf"); ClassPathResource pdfFileResource = new ClassPathResource("files/syngenta/CustomerFiles/SinglePages/Spanning Cells - Page131_S-Metolachlor_RAR_01_Volume_1_2018-09-06.pdf");
ClassificationDocument document = buildClassificationDocument(pdfFileResource.getFile()); ClassificationDocument document = buildClassificationDocument(pdfFileResource.getFile());
assertThat(document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).collect(Collectors.toList())).isNotEmpty(); assertThat(document.getSections()
TablePageBlock table = document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList().get(0); .stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.collect(Collectors.toList())).isNotEmpty();
TablePageBlock table = document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList()
.get(0);
assertThat(table.getColCount()).isEqualTo(6); assertThat(table.getColCount()).isEqualTo(6);
assertThat(table.getRowCount()).isEqualTo(13); assertThat(table.getRowCount()).isEqualTo(13);
assertThat(table.getRows().stream().mapToInt(List::size).sum()).isEqualTo(6 * 13); assertThat(table.getRows()
.stream()
.mapToInt(List::size).sum()).isEqualTo(6 * 13);
} }
@ -373,29 +376,30 @@ public class PdfSegmentationServiceTest extends AbstractTest {
validateTable(document, 0, 8, 8, 0, 0); validateTable(document, 0, 8, 8, 0, 0);
List<List<String>> values = Arrays.asList(Arrays.asList("Annex point Reference within DAR/RAR", List<List<String>> values = Arrays.asList(Arrays.asList("Annex point Reference within DAR/RAR",
"Author, date", "Author, date",
"Study title", "Study title",
"Analytical method Author, date, No.", "Analytical method Author, date, No.",
"Technique, LOQ of the method, validated working range", "Technique, LOQ of the method, validated working range",
"Method meets analytical validation criteria", "Method meets analytical validation criteria",
"Remarks (in case validation criteria are not met)", "Remarks (in case validation criteria are not met)",
"Acceptability of the method"), "Acceptability of the method"),
Arrays.asList("Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", Arrays.asList(
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
"Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies"), "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies",
Arrays.asList("CA 7.1.2.1.1 DAR (2009)", "Part (a) Methods in soil, water, sediment, air and any additional matrices used in support of environmental fate studies"),
"Evans P.G. 2001 TMJ4569B, VV-323245", Arrays.asList("CA 7.1.2.1.1 DAR (2009)",
"Azoxystrobin Laboratory Degradation Study in Three Soil Types, Sampled from Holland and the United Kingdom", "Evans P.G. 2001 TMJ4569B, VV-323245",
"Method: RAM 269 Johnson R.I., Tummon O.J., Earl M. 1995 RJ1864B, VV-377731 Johnson R.I., Tummon O.J., Earl M. 1998 RAM 269/02, VV-124072 Johnson R.I., Tummon O.J., Earl M. 2000 RAM 269/03, VV-123986 Validation: Robinson N.J. 2001 TMJ4617B, VV-895845", "Azoxystrobin Laboratory Degradation Study in Three Soil Types, Sampled from Holland and the United Kingdom",
"LC-MS/MS LOQ: 0.01 mg/kg (R401553 (SYN50165 7), R402173 (SYN501114 )) or 0.02mg/kg (azoxystrobin, R230310, R234886) Working range: 0.02-1.0 or 0.01-0.5 mg/kg (depending on analyte) Other supporting quantificati on methods: HPLC-UV GC-MSD", "Method: RAM 269 Johnson R.I., Tummon O.J., Earl M. 1995 RJ1864B, VV-377731 Johnson R.I., Tummon O.J., Earl M. 1998 RAM 269/02, VV-124072 Johnson R.I., Tummon O.J., Earl M. 2000 RAM 269/03, VV-123986 Validation: Robinson N.J. 2001 TMJ4617B, VV-895845",
"Y", "LC-MS/MS LOQ: 0.01 mg/kg (R401553 (SYN50165 7), R402173 (SYN501114 )) or 0.02mg/kg (azoxystrobin, R230310, R234886) Working range: 0.02-1.0 or 0.01-0.5 mg/kg (depending on analyte) Other supporting quantificati on methods: HPLC-UV GC-MSD",
"N/A", "Y",
"Y")); "N/A",
"Y"));
validateTable(document, 0, values); validateTable(document, 0, values);
@ -785,6 +789,7 @@ public class PdfSegmentationServiceTest extends AbstractTest {
} }
@Test @Test
public void testMergedEntities_Page26() throws IOException { public void testMergedEntities_Page26() throws IOException {
@ -802,7 +807,11 @@ public class PdfSegmentationServiceTest extends AbstractTest {
@SneakyThrows @SneakyThrows
private void toHtml(ClassificationDocument document, String filename) { private void toHtml(ClassificationDocument document, String filename) {
var tables = document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList(); var tables = document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int currentPage = 1; int currentPage = 1;
@ -823,9 +832,19 @@ public class PdfSegmentationServiceTest extends AbstractTest {
private void validateTable(ClassificationDocument document, int tableIndex, int colCount, int rowCount, int emptyCellsCountCorrect, int emptyCellsCountIncorrect) { private void validateTable(ClassificationDocument document, int tableIndex, int colCount, int rowCount, int emptyCellsCountCorrect, int emptyCellsCountIncorrect) {
TablePageBlock table = document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList().get(tableIndex); TablePageBlock table = document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList()
.get(tableIndex);
List<List<Cell>> rows = table.getRows(); List<List<Cell>> rows = table.getRows();
int emptyCellsFoundFound = rows.stream().flatMap(List::stream).toList().stream().filter(f -> f.toString().isEmpty()).toList().size(); int emptyCellsFoundFound = rows.stream()
.flatMap(List::stream)
.toList()
.stream()
.filter(f -> f.toString().isEmpty())
.toList().size();
for (List<Cell> row : table.getRows()) { for (List<Cell> row : table.getRows()) {
row.forEach(r -> System.out.println(r.toString())); row.forEach(r -> System.out.println(r.toString()));
@ -840,11 +859,20 @@ public class PdfSegmentationServiceTest extends AbstractTest {
private void validateTable(ClassificationDocument document, int tableIndex, List<List<String>> values) { private void validateTable(ClassificationDocument document, int tableIndex, List<List<String>> values) {
TablePageBlock table = document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList().get(tableIndex); TablePageBlock table = document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList()
.get(tableIndex);
List<List<Cell>> rows = table.getRows(); List<List<Cell>> rows = table.getRows();
List<Cell> rowsFlattened = rows.stream().flatMap(List::stream).toList(); List<Cell> rowsFlattened = rows.stream()
List<String> valuesFlattened = values.stream().flatMap(List::stream).toList(); .flatMap(List::stream)
.toList();
List<String> valuesFlattened = values.stream()
.flatMap(List::stream)
.toList();
for (int i = 0; i < valuesFlattened.size(); i++) { for (int i = 0; i < valuesFlattened.size(); i++) {
Cell cell = rowsFlattened.get(i); Cell cell = rowsFlattened.get(i);
@ -857,7 +885,11 @@ public class PdfSegmentationServiceTest extends AbstractTest {
private void validateTableSize(ClassificationDocument document, int tableSize) { private void validateTableSize(ClassificationDocument document, int tableSize) {
assertThat(document.getSections().stream().flatMap(paragraph -> paragraph.getTables().stream()).toList().size()).isEqualTo(tableSize); assertThat(document.getSections()
.stream()
.flatMap(paragraph -> paragraph.getTables()
.stream())
.toList().size()).isEqualTo(tableSize);
} }

View File

@ -81,6 +81,7 @@ public class RulingCleaningServiceTest extends BuildDocumentTest {
@Test @Test
@Disabled
@SneakyThrows @SneakyThrows
public void testTableExtraction() { public void testTableExtraction() {
@ -97,6 +98,7 @@ public class RulingCleaningServiceTest extends BuildDocumentTest {
} }
@SneakyThrows @SneakyThrows
private void writeJsons(Path filename) { private void writeJsons(Path filename) {