RED-7784 - Apply unprocessed manual changes in reports and redactions
* Add endpoint used to calculate information aboout unprocessed manual entities like textBefore/textAfter/offsets etc.
This commit is contained in:
parent
db2b663547
commit
6930d94274
@ -0,0 +1,24 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class UnprocessedManualEntity {
|
||||||
|
|
||||||
|
private String annotationId;
|
||||||
|
private String textBefore;
|
||||||
|
private String textAfter;
|
||||||
|
private int startOffset;
|
||||||
|
private int endOffset;
|
||||||
|
private String closestHeadline;
|
||||||
|
private float[] color;
|
||||||
|
private List<Integer> containingNodeId;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.resources;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||||
|
import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity;
|
||||||
|
|
||||||
|
public interface UnprocessedManualEntityResource {
|
||||||
|
|
||||||
|
@GetMapping(value = "/mergeUnprocessedManualEntities", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
List<UnprocessedManualEntity> mergeUnprocessedManualEntities(@RequestParam(value = "fileId") String fileId,
|
||||||
|
@RequestParam(value = "dossierId") String dossierId,
|
||||||
|
@RequestParam(value = "dossierTemplateId") String dosserTemplateId,
|
||||||
|
@RequestBody ManualRedactions manualRedactions);
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ val layoutParserVersion = "0.74.0"
|
|||||||
val jacksonVersion = "2.15.2"
|
val jacksonVersion = "2.15.2"
|
||||||
val droolsVersion = "9.44.0.Final"
|
val droolsVersion = "9.44.0.Final"
|
||||||
val pdfBoxVersion = "3.0.0"
|
val pdfBoxVersion = "3.0.0"
|
||||||
val persistenceServiceVersion = "2.210.0"
|
val persistenceServiceVersion = "2.223.0"
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
all {
|
all {
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.controller;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||||
|
import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity;
|
||||||
|
import com.iqser.red.service.redaction.v1.resources.UnprocessedManualEntityResource;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.UnprocessedChangesService;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UnprocessedManualEntityController implements UnprocessedManualEntityResource {
|
||||||
|
|
||||||
|
private final UnprocessedChangesService unprocessedChangesService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UnprocessedManualEntity> mergeUnprocessedManualEntities(String fileId, String dossierId, String dossierTemplateId, ManualRedactions manualRedactions) {
|
||||||
|
|
||||||
|
return unprocessedChangesService.addInformationToUnprocessedManualEntities(fileId, dossierId, dossierTemplateId, manualRedactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.service;
|
||||||
|
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
|
||||||
|
import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.EntityType;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.PositionOnPage;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.TextEntity;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.document.DocumentGraphMapper;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityEnrichmentService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.utils.exception.NotFoundException;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UnprocessedChangesService {
|
||||||
|
|
||||||
|
private final RedactionStorageService redactionStorageService;
|
||||||
|
private final EntityEnrichmentService entityEnrichmentService;
|
||||||
|
private final DictionaryService dictionaryService;
|
||||||
|
|
||||||
|
|
||||||
|
public List<UnprocessedManualEntity> addInformationToUnprocessedManualEntities(String fileId, String dossierId, String dossierTemplateId, ManualRedactions manualRedactions) {
|
||||||
|
|
||||||
|
Document document = DocumentGraphMapper.toDocumentGraph(redactionStorageService.getDocumentData(dossierId, fileId));
|
||||||
|
List<UnprocessedManualEntity> unprocessedManualEntities = new ArrayList<>();
|
||||||
|
|
||||||
|
for (SemanticNode node : document.streamChildren().toList()) {
|
||||||
|
|
||||||
|
if (manualRedactions.getEntriesToAdd().isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iterator = manualRedactions.getEntriesToAdd().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
var manualAddRedaction = iterator.next();
|
||||||
|
if (sectionContainsEntry(node, manualAddRedaction.getPositions())) {
|
||||||
|
TextEntity surroundingText = findSurroundingText(node, manualAddRedaction.getValue(), manualAddRedaction.getPositions());
|
||||||
|
unprocessedManualEntities.add(UnprocessedManualEntity.builder()
|
||||||
|
.annotationId(manualAddRedaction.getAnnotationId())
|
||||||
|
.closestHeadline(surroundingText.getDeepestFullyContainingNode().getHeadline().getTextBlock().getSearchText())
|
||||||
|
.color(getColor(surroundingText.getType(), dossierTemplateId, surroundingText.applied(), surroundingText.getEntityType().equals(EntityType.HINT)))
|
||||||
|
.startOffset(surroundingText.getTextRange().start())
|
||||||
|
.endOffset(surroundingText.getTextRange().end())
|
||||||
|
.containingNodeId(surroundingText.getDeepestFullyContainingNode().getTreeId())
|
||||||
|
.textBefore(surroundingText.getTextBefore())
|
||||||
|
.textAfter(surroundingText.getTextAfter())
|
||||||
|
.build());
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unprocessedManualEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private TextEntity findSurroundingText(SemanticNode node, String value, List<Rectangle> toFindPositions) {
|
||||||
|
|
||||||
|
EntityCreationService entityCreationService = new EntityCreationService(entityEnrichmentService);
|
||||||
|
Set<TextEntity> entities = RedactionSearchUtility.findTextRangesByString(value, node.getTextBlock())
|
||||||
|
.stream()
|
||||||
|
.map(boundary -> entityCreationService.forceByTextRange(boundary, "searchHelper", EntityType.RECOMMENDATION, node))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return getEntityOnCorrectPosition(entities, toFindPositions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean sectionContainsEntry(SemanticNode semanticNode, List<Rectangle> positions) {
|
||||||
|
|
||||||
|
for (Rectangle position : positions) {
|
||||||
|
if (semanticNode.containsRectangle(UnprocessedChangesService.toRectangle2D(position), position.getPage())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private TextEntity getEntityOnCorrectPosition(Set<TextEntity> entities, List<Rectangle> toFindPositions) {
|
||||||
|
|
||||||
|
return entities.stream()
|
||||||
|
.filter(entity -> entity.getPositionsOnPagePerPage()
|
||||||
|
.stream()
|
||||||
|
.map(PositionOnPage::getRectanglePerLine)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.allMatch(rectangle2D -> toFindPositionsIntersectRectangle(toFindPositions, rectangle2D)))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NotFoundException("No matching Entity could be found for positions" + toFindPositions));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean toFindPositionsIntersectRectangle(List<Rectangle> toFindPositions, Rectangle2D rectangle2D) {
|
||||||
|
|
||||||
|
return toFindPositions.stream().map(UnprocessedChangesService::toRectangle2D).anyMatch(toFindRectangle -> toFindRectangle.intersects(rectangle2D));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Rectangle2D toRectangle2D(Rectangle rect) {
|
||||||
|
|
||||||
|
return new Rectangle2D.Double(rect.getTopLeftX() - rect.getWidth(), rect.getTopLeftY() - rect.getHeight(), rect.getWidth(), rect.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] getColor(String type, String dossierTemplateId, boolean isApplied, boolean isHint) {
|
||||||
|
|
||||||
|
if (!isApplied && !isHint) {
|
||||||
|
return dictionaryService.getNotRedactedColor(dossierTemplateId);
|
||||||
|
}
|
||||||
|
return dictionaryService.getColor(type, dossierTemplateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user