RED-1814: Apply manual image recategorization before rules execution

This commit is contained in:
Dominique Eifländer 2021-07-14 12:24:27 +02:00
parent c8eb6489fa
commit cb41187be6
5 changed files with 55 additions and 22 deletions

View File

@ -17,8 +17,6 @@ public class ManualImageRecategorization {
private String user; private String user;
private Status status; private Status status;
private String type; private String type;
private String legalBasis;
private boolean redacted;
private OffsetDateTime requestDate; private OffsetDateTime requestDate;
private OffsetDateTime processedDate; private OffsetDateTime processedDate;

View File

@ -1,19 +1,24 @@
package com.iqser.red.service.redaction.v1.server.redaction.service; package com.iqser.red.service.redaction.v1.server.redaction.service;
import com.iqser.red.service.redaction.v1.model.FileAttribute; import com.iqser.red.service.redaction.v1.model.FileAttribute;
import com.iqser.red.service.redaction.v1.model.ManualImageRecategorization;
import com.iqser.red.service.redaction.v1.model.ManualRedactionEntry; import com.iqser.red.service.redaction.v1.model.ManualRedactionEntry;
import com.iqser.red.service.redaction.v1.model.ManualRedactions; import com.iqser.red.service.redaction.v1.model.ManualRedactions;
import com.iqser.red.service.redaction.v1.model.Point; import com.iqser.red.service.redaction.v1.model.Point;
import com.iqser.red.service.redaction.v1.model.Rectangle; import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.model.SectionArea; import com.iqser.red.service.redaction.v1.model.SectionArea;
import com.iqser.red.service.redaction.v1.model.Status;
import com.iqser.red.service.redaction.v1.server.classification.model.*; import com.iqser.red.service.redaction.v1.server.classification.model.*;
import com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary; import com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary;
import com.iqser.red.service.redaction.v1.server.redaction.model.*; import com.iqser.red.service.redaction.v1.server.redaction.model.*;
import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils; import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils;
import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell; import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table; import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieContainer;
@ -34,7 +39,8 @@ public class EntityRedactionService {
private final SurroundingWordsService surroundingWordsService; private final SurroundingWordsService surroundingWordsService;
public void processDocument(Document classifiedDoc, String dossierTemplateId, ManualRedactions manualRedactions, String dossierId, List<FileAttribute> fileAttributes) { public void processDocument(Document classifiedDoc, String dossierTemplateId, ManualRedactions manualRedactions,
String dossierId, List<FileAttribute> fileAttributes) {
dictionaryService.updateDictionary(dossierTemplateId, dossierId); dictionaryService.updateDictionary(dossierTemplateId, dossierId);
KieContainer container = droolsExecutionService.updateRules(dossierTemplateId); KieContainer container = droolsExecutionService.updateRules(dossierTemplateId);
@ -85,7 +91,8 @@ public class EntityRedactionService {
private Set<Entity> findEntities(Document classifiedDoc, KieContainer kieContainer, private Set<Entity> findEntities(Document classifiedDoc, KieContainer kieContainer,
ManualRedactions manualRedactions, Dictionary dictionary, boolean local, ManualRedactions manualRedactions, Dictionary dictionary, boolean local,
Map<Integer, Set<Entity>> hintsPerSectionNumber, List<FileAttribute> fileAttributes) { Map<Integer, Set<Entity>> hintsPerSectionNumber,
List<FileAttribute> fileAttributes) {
Set<Entity> documentEntities = new HashSet<>(); Set<Entity> documentEntities = new HashSet<>();
@ -165,7 +172,8 @@ public class EntityRedactionService {
ManualRedactions manualRedactions, ManualRedactions manualRedactions,
AtomicInteger sectionNumber, Dictionary dictionary, AtomicInteger sectionNumber, Dictionary dictionary,
boolean local, boolean local,
Map<Integer, Set<Entity>> hintsPerSectionNumber, List<FileAttribute> fileAttributes) { Map<Integer, Set<Entity>> hintsPerSectionNumber,
List<FileAttribute> fileAttributes) {
List<SectionSearchableTextPair> sectionSearchableTextPairs = new ArrayList<>(); List<SectionSearchableTextPair> sectionSearchableTextPairs = new ArrayList<>();
@ -334,7 +342,7 @@ public class EntityRedactionService {
sectionText.setSectionNumber(sectionNumber.intValue()); sectionText.setSectionNumber(sectionNumber.intValue());
sectionText.setTable(false); sectionText.setTable(false);
sectionText.setImages(images.stream() sectionText.setImages(images.stream()
.map(image -> convert(image, sectionNumber.intValue(), headline)) .map(image -> convertAndRecategorize(image, sectionNumber.intValue(), headline, manualRedactions))
.collect(Collectors.toSet())); .collect(Collectors.toSet()));
sectionText.setTextBlocks(paragraphTextBlocks); sectionText.setTextBlocks(paragraphTextBlocks);
classifiedDoc.getSectionText().add(sectionText); classifiedDoc.getSectionText().add(sectionText);
@ -357,7 +365,7 @@ public class EntityRedactionService {
.searchableText(searchableText) .searchableText(searchableText)
.dictionary(dictionary) .dictionary(dictionary)
.images(images.stream() .images(images.stream()
.map(image -> convert(image, sectionNumber.intValue(), headline)) .map(image -> convertAndRecategorize(image, sectionNumber.intValue(), headline, manualRedactions))
.collect(Collectors.toSet())) .collect(Collectors.toSet()))
.fileAttributes(fileAttributes) .fileAttributes(fileAttributes)
.build(), searchableText); .build(), searchableText);
@ -376,9 +384,11 @@ public class EntityRedactionService {
String lowercaseInputString = searchableString.toLowerCase(); String lowercaseInputString = searchableString.toLowerCase();
for (DictionaryModel model : dictionary.getDictionaryModels()) { for (DictionaryModel model : dictionary.getDictionaryModels()) {
if (model.isCaseInsensitive()) { if (model.isCaseInsensitive()) {
found.addAll(EntitySearchUtils.find(lowercaseInputString, model.getValues(local), model.getType(), headline, sectionNumber, local, model.isDossierDictionary())); found.addAll(EntitySearchUtils.find(lowercaseInputString, model.getValues(local), model.getType(), headline, sectionNumber, local, model
.isDossierDictionary()));
} else { } else {
found.addAll(EntitySearchUtils.find(searchableString, model.getValues(local), model.getType(), headline, sectionNumber, local, model.isDossierDictionary())); found.addAll(EntitySearchUtils.find(searchableString, model.getValues(local), model.getType(), headline, sectionNumber, local, model
.isDossierDictionary()));
} }
} }
@ -406,9 +416,9 @@ public class EntityRedactionService {
} }
private Image convert(PdfImage pdfImage, int sectionNumber, String headline) { private Image convertAndRecategorize(PdfImage pdfImage, int sectionNumber, String headline, ManualRedactions manualRedactions) {
return Image.builder() Image image = Image.builder()
.type(pdfImage.getImageType().equals(ImageType.OTHER) ? "image" : pdfImage.getImageType() .type(pdfImage.getImageType().equals(ImageType.OTHER) ? "image" : pdfImage.getImageType()
.name() .name()
.toLowerCase(Locale.ROOT)) .toLowerCase(Locale.ROOT))
@ -417,6 +427,18 @@ public class EntityRedactionService {
.section(headline) .section(headline)
.page(pdfImage.getPage()) .page(pdfImage.getPage())
.build(); .build();
String imageId = IdBuilder.buildId(image.getPosition(), image.getPage());
if (manualRedactions != null && manualRedactions.getImageRecategorizations() != null) {
for (ManualImageRecategorization imageRecategorization : manualRedactions.getImageRecategorizations()) {
if (imageRecategorization.getStatus().equals(Status.APPROVED) && imageRecategorization.getId()
.equals(imageId)) {
image.setType(imageRecategorization.getType());
}
}
}
return image;
} }
} }

View File

@ -27,6 +27,7 @@ import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.model.RedactionLog; import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry; import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.model.SectionArea; import com.iqser.red.service.redaction.v1.model.SectionArea;
import com.iqser.red.service.redaction.v1.model.Status;
import com.iqser.red.service.redaction.v1.server.classification.model.Document; import com.iqser.red.service.redaction.v1.server.classification.model.Document;
import com.iqser.red.service.redaction.v1.server.classification.model.SectionText; import com.iqser.red.service.redaction.v1.server.classification.model.SectionText;
import com.iqser.red.service.redaction.v1.server.classification.model.Text; import com.iqser.red.service.redaction.v1.server.classification.model.Text;
@ -42,6 +43,7 @@ import com.iqser.red.service.redaction.v1.server.redaction.model.RedRectangle2D;
import com.iqser.red.service.redaction.v1.server.redaction.model.Section; import com.iqser.red.service.redaction.v1.server.redaction.model.Section;
import com.iqser.red.service.redaction.v1.server.redaction.model.SectionSearchableTextPair; import com.iqser.red.service.redaction.v1.server.redaction.model.SectionSearchableTextPair;
import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils; import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils;
import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService; import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService; import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
@ -205,6 +207,20 @@ public class ReanalyzeService {
surroundingWordsService.addSurroundingText(entities, reanalysisSection.getSearchableText(), dictionary); surroundingWordsService.addSurroundingText(entities, reanalysisSection.getSearchableText(), dictionary);
} }
if (reanalysisSection.getImages() != null && !reanalysisSection.getImages()
.isEmpty() && analyzeRequest.getManualRedactions() != null && analyzeRequest.getManualRedactions()
.getImageRecategorizations() != null) {
for (Image image : reanalysisSection.getImages()) {
String imageId = IdBuilder.buildId(image.getPosition(), image.getPage());
for(ManualImageRecategorization imageRecategorization: analyzeRequest.getManualRedactions()
.getImageRecategorizations()){
if(imageRecategorization.getStatus().equals(Status.APPROVED) && imageRecategorization.getId().equals(imageId)){
image.setType(imageRecategorization.getType());
}
}
}
}
sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder() sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder()
.isLocal(false) .isLocal(false)
.dictionaryTypes(dictionary.getTypes()) .dictionaryTypes(dictionary.getTypes())
@ -300,9 +316,13 @@ public class ReanalyzeService {
return new HashSet<>(); return new HashSet<>();
} }
return Stream.concat(manualRedactions.getManualLegalBasisChanges().stream().map(ManualLegalBasisChange::getId), return Stream.concat(manualRedactions.getManualLegalBasisChanges()
Stream.concat(manualRedactions.getImageRecategorizations().stream().map(ManualImageRecategorization::getId), .stream()
Stream.concat(manualRedactions.getIdsToRemove().stream().map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId)))) .map(ManualLegalBasisChange::getId), Stream.concat(manualRedactions.getImageRecategorizations()
.stream()
.map(ManualImageRecategorization::getId), Stream.concat(manualRedactions.getIdsToRemove()
.stream()
.map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId))))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }

View File

@ -99,14 +99,9 @@ public class RedactionLogCreatorService {
if (recategorization.getId().equals(redactionLogEntry.getId())) { if (recategorization.getId().equals(redactionLogEntry.getId())) {
String manualOverrideReason = null; String manualOverrideReason = null;
if (recategorization.getStatus().equals(Status.APPROVED)) { if (recategorization.getStatus().equals(Status.APPROVED)) {
image.setRedaction(recategorization.isRedacted());
redactionLogEntry.setType(recategorization.getType());
redactionLogEntry.setHint(dictionaryService.isHint(recategorization.getType(), dossierTemplateId));
redactionLogEntry.setRedacted(recategorization.isRedacted());
redactionLogEntry.setStatus(Status.APPROVED); redactionLogEntry.setStatus(Status.APPROVED);
redactionLogEntry.setLegalBasis(recategorization.getLegalBasis()); redactionLogEntry.setType(recategorization.getType());
manualOverrideReason = mergeReasonIfNecessary(image.getRedactionReason(), ", recategorized by manual override"); manualOverrideReason = mergeReasonIfNecessary(image.getRedactionReason(), ", recategorized by manual override");
redactionLogEntry.setColor(getColorForImage(redactionLogEntry.getType(), dossierTemplateId, false, redactionLogEntry.isRedacted()));
} else if (recategorization.getStatus().equals(Status.REQUESTED)) { } else if (recategorization.getStatus().equals(Status.REQUESTED)) {
manualOverrideReason = mergeReasonIfNecessary(image.getRedactionReason(), ", requested to recategorize"); manualOverrideReason = mergeReasonIfNecessary(image.getRedactionReason(), ", requested to recategorize");
redactionLogEntry.setStatus(Status.REQUESTED); redactionLogEntry.setStatus(Status.REQUESTED);

View File

@ -698,8 +698,6 @@ public class RedactionIntegrationTest {
.id("37eee3e9d589a5cc529bfec38c3ba479") .id("37eee3e9d589a5cc529bfec38c3ba479")
.status(Status.APPROVED) .status(Status.APPROVED)
.type("signature") .type("signature")
.redacted(true)
.legalBasis("Article 39(e)(1) and Article 39(e)(2) of Regulation (EC) No 178/2002")
.build())); .build()));
request.setManualRedactions(manualRedactions); request.setManualRedactions(manualRedactions);