RED-3239: Protoyped logic for imported redactions

This commit is contained in:
deiflaender 2022-01-27 15:21:33 +01:00
parent 0da2a1ab26
commit 26661fa87b
6 changed files with 277 additions and 9 deletions

View File

@ -1,6 +1,8 @@
package com.iqser.red.service.redaction.v1.model;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotation;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ManualRedactions;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -12,7 +14,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Data
@Builder
@NoArgsConstructor
@ -36,5 +37,8 @@ public class AnalyzeRequest {
@Builder.Default
private List<FileAttribute> fileAttributes = new ArrayList<>();
@Builder.Default
List<ImportedAnnotation> importedAnnotations = new ArrayList<>();
}

View File

@ -48,6 +48,7 @@ public class AnalyzeService {
private final SectionGridCreatorService sectionGridCreatorService;
private final NerAnalyserService nerAnalyserService;
private final ImageService imageService;
private final ImportedRedactionService importedRedactionService;
public void analyzeDocumentStructure(StructureAnalyzeRequest analyzeRequest) {
@ -121,6 +122,7 @@ public class AnalyzeService {
redactionLogEntries, legalBasis, dictionary.getVersion().getDossierTemplateVersion(), dictionary.getVersion().getDossierVersion(),
rulesVersion, legalBasisClient.getVersion(analyzeRequest.getDossierTemplateId()));
importedRedactionService.processImportedRedactions(redactionLog, analyzeRequest.getImportedAnnotations(), analyzeRequest.getDossierTemplateId());
return finalizeAnalysis(analyzeRequest, startTime, redactionLog, text, dictionary.getVersion(), false);
}
@ -170,6 +172,7 @@ public class AnalyzeService {
redactionLog.getRedactionLogEntry().removeIf(entry -> sectionsToReanalyse.contains(entry.getSectionNumber()));
redactionLog.getRedactionLogEntry().addAll(newRedactionLogEntries);
importedRedactionService.processImportedRedactions(redactionLog, analyzeRequest.getImportedAnnotations(), analyzeRequest.getDossierTemplateId());
return finalizeAnalysis(analyzeRequest, startTime, redactionLog, text, dictionaryIncrement.getDictionaryVersion(), true);
}

View File

@ -0,0 +1,98 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotation;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotationStatus;
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.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ImportedRedactionService {
private final DictionaryService dictionaryService;
public void processImportedRedactions(RedactionLog redactionLog, List<ImportedAnnotation> importedAnnotations, String dossierTemplateId) {
Iterator<RedactionLogEntry> itty = redactionLog.getRedactionLogEntry().iterator();
while (itty.hasNext()) {
RedactionLogEntry redactionLogEntry = itty.next();
boolean mustBeRemoved = false;
if (redactionLogEntry.getType().equals("imported_redaction")) {
itty.remove();
continue;
}
loop:
for (ImportedAnnotation importedAnnotation : importedAnnotations) {
for (com.iqser.red.service.persistence.service.v1.api.model.annotations.Rectangle importedPosition : importedAnnotation.getPositions()) {
for (Rectangle rectangle : redactionLogEntry.getPositions()) {
if (intersects(importedPosition, rectangle)) {
mustBeRemoved = true;
break loop;
}
}
}
}
if (mustBeRemoved) {
itty.remove();
}
}
for (ImportedAnnotation importedAnnotation : importedAnnotations) {
RedactionLogEntry redactionLogEntry = RedactionLogEntry.builder()
.id(importedAnnotation.getAnnotationId())
.type("imported_redaction")
.redacted(importedAnnotation.getStatus().equals(ImportedAnnotationStatus.DECLINED) ? false : true)
.positions(importedAnnotation.getPositions()
.stream()
.map(this::convert)
.collect(Collectors.toList()))
.color(getColor("imported_redaction", dossierTemplateId, importedAnnotation.getStatus().equals(ImportedAnnotationStatus.DECLINED) ? false : true))
.build();
redactionLog.getRedactionLogEntry().add(redactionLogEntry);
}
}
public Rectangle convert(
com.iqser.red.service.persistence.service.v1.api.model.annotations.Rectangle importedPosition) {
return new Rectangle(new Point(importedPosition.getTopLeftX(), importedPosition.getTopLeftY()), importedPosition.getWidth(), importedPosition.getHeight(), importedPosition.getPage());
}
public boolean intersects(
com.iqser.red.service.persistence.service.v1.api.model.annotations.Rectangle importedPosition,
Rectangle redactionLogPosition) {
return importedPosition.getPage() == redactionLogPosition.getPage() && redactionLogPosition.getTopLeft()
.getX() + redactionLogPosition.getWidth() > importedPosition.getTopLeftX() && redactionLogPosition.getTopLeft()
.getY() + redactionLogPosition.getHeight() > importedPosition.getTopLeftY() && redactionLogPosition.getTopLeft()
.getX() < importedPosition.getTopLeftX() + importedPosition.getWidth() && redactionLogPosition.getTopLeft()
.getY() < importedPosition.getTopLeftY() + importedPosition.getHeight();
}
private float[] getColor(String type, String dossierTemplateId, boolean isRedaction) {
if (!isRedaction) {
return dictionaryService.getNotRedactedColor(dossierTemplateId);
}
return dictionaryService.getColor(type, dossierTemplateId);
}
}

View File

@ -23,6 +23,8 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.type.TypeReference;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotation;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.*;
import org.apache.commons.io.IOUtils;
import org.junit.After;
@ -108,6 +110,7 @@ public class RedactionIntegrationTest {
private static final String FORMULA = "formula";
private static final String OCR = "ocr";
private static final String DOSSIER_REDACTIONS = "dossier_redactions";
private static final String IMPORTED_REDACTION = "imported_redaction";
private static final String RECOMMENDATION_AUTHOR = "recommendation_CBI_author";
private static final String RECOMMENDATION_ADDRESS = "recommendation_CBI_address";
@ -248,6 +251,7 @@ public class RedactionIntegrationTest {
when(dictionaryClient.getDictionaryForType(SIGNATURE + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(SIGNATURE, false));
when(dictionaryClient.getDictionaryForType(FORMULA + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(FORMULA, false));
when(dictionaryClient.getDictionaryForType(DOSSIER_REDACTIONS + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(DOSSIER_REDACTIONS, true));
when(dictionaryClient.getDictionaryForType(IMPORTED_REDACTION + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(IMPORTED_REDACTION, true));
when(dictionaryClient.getColors(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(colors);
}
@ -359,6 +363,7 @@ public class RedactionIntegrationTest {
.stream()
.map(this::cleanDictionaryEntry)
.collect(Collectors.toSet()));
dossierDictionary.put(IMPORTED_REDACTION, new ArrayList<>());
}
@ -390,6 +395,7 @@ public class RedactionIntegrationTest {
typeColorMap.put(LOGO, "#ffe187");
typeColorMap.put(FORMULA, "#ffe187");
typeColorMap.put(SIGNATURE, "#ffe187");
typeColorMap.put(IMPORTED_REDACTION, "#32a852");
hintTypeMap.put(VERTEBRATE, true);
hintTypeMap.put(ADDRESS, false);
@ -412,6 +418,7 @@ public class RedactionIntegrationTest {
hintTypeMap.put(LOGO, false);
hintTypeMap.put(SIGNATURE, false);
hintTypeMap.put(DOSSIER_REDACTIONS, false);
hintTypeMap.put(IMPORTED_REDACTION, false);
caseInSensitiveMap.put(VERTEBRATE, true);
caseInSensitiveMap.put(ADDRESS, false);
@ -434,6 +441,7 @@ public class RedactionIntegrationTest {
caseInSensitiveMap.put(LOGO, true);
caseInSensitiveMap.put(FORMULA, true);
caseInSensitiveMap.put(DOSSIER_REDACTIONS, false);
caseInSensitiveMap.put(IMPORTED_REDACTION, false);
recommendationTypeMap.put(VERTEBRATE, false);
recommendationTypeMap.put(ADDRESS, false);
@ -456,6 +464,7 @@ public class RedactionIntegrationTest {
recommendationTypeMap.put(SIGNATURE, false);
recommendationTypeMap.put(LOGO, false);
recommendationTypeMap.put(DOSSIER_REDACTIONS, false);
recommendationTypeMap.put(IMPORTED_REDACTION, false);
rankTypeMap.put(FALSE_POSITIVE, 160);
rankTypeMap.put(PURITY, 155);
@ -478,6 +487,7 @@ public class RedactionIntegrationTest {
rankTypeMap.put(SIGNATURE, 27);
rankTypeMap.put(FORMULA, 26);
rankTypeMap.put(DOSSIER_REDACTIONS, 200);
rankTypeMap.put(IMPORTED_REDACTION, 200);
colors.setDefaultColor("#acfc00");
colors.setNotRedacted("#cccccc");
@ -495,7 +505,7 @@ public class RedactionIntegrationTest {
.type(typeColor.getKey())
.dossierTemplateId(TEST_DOSSIER_TEMPLATE_ID)
.hexColor(typeColor.getValue())
.isHint(hintTypeMap.get(typeColor.getKey()))
.isHint(hintTypeMap.get(typeColor.getKey()))
.isCaseInsensitive(caseInSensitiveMap.get(typeColor.getKey()))
.isRecommendation(recommendationTypeMap.get(typeColor.getKey()))
.rank(rankTypeMap.get(typeColor.getKey()))
@ -841,6 +851,7 @@ public class RedactionIntegrationTest {
System.out.println("Output file:" + outputFileName);
}
@Test
public void testChangeComputation() throws IOException {
@ -856,24 +867,27 @@ public class RedactionIntegrationTest {
dictionary.get(AUTHOR).add("report");
reanlysisVersions.put("report", 2L);
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(2L);
when(dictionaryClient.getDictionaryForType(AUTHOR +":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
when(dictionaryClient.getDictionaryForType(AUTHOR + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
analyzeService.reanalyze(request);
dictionary.get(AUTHOR).add("assessment report");
reanlysisVersions.put("assessment report", 3L);
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(3L);
when(dictionaryClient.getDictionaryForType(AUTHOR +":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
when(dictionaryClient.getDictionaryForType(AUTHOR + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
analyzeService.reanalyze(request);
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(3L);
when(dictionaryClient.getDictionaryForType(AUTHOR +":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
when(dictionaryClient.getDictionaryForType(AUTHOR + ":" + TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getDictionaryResponse(AUTHOR, false));
analyzeService.reanalyze(request);
var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
var changes = redactionLog.getRedactionLogEntry().stream().filter(entry ->
entry.getValue() != null && entry.getValue().equals("report"))
.findFirst().get().getChanges();
var changes = redactionLog.getRedactionLogEntry()
.stream()
.filter(entry -> entry.getValue() != null && entry.getValue().equals("report"))
.findFirst()
.get()
.getChanges();
assertThat(changes.size()).isEqualTo(2);
@ -887,6 +901,7 @@ public class RedactionIntegrationTest {
}
}
@Test
public void redactionTest() throws IOException {
@ -1556,4 +1571,31 @@ public class RedactionIntegrationTest {
}
@Test
public void testImportedRedactions() throws IOException {
String outputFileName = OsUtils.getTemporaryDirectory() + "/Annotated.pdf";
ClassPathResource pdfFileResource = new ClassPathResource("files/ImportedRedactions/S13.pdf");
ClassPathResource importedRedactions = new ClassPathResource("files/ImportedRedactions/S13.json");
List<ImportedAnnotation> importedAnnotations = objectMapper.readValue(importedRedactions.getInputStream().readAllBytes(), new TypeReference<List<ImportedAnnotation>>() {
});
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
request.setImportedAnnotations(importedAnnotations);
analyzeService.analyzeDocumentStructure(new StructureAnalyzeRequest(request.getDossierId(), request.getFileId()));
AnalyzeResult result = analyzeService.analyze(request);
var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
AnnotateResponse annotateResponse = redactionController.annotate(AnnotateRequest.builder()
.dossierId(TEST_DOSSIER_ID)
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(outputFileName)) {
fileOutputStream.write(annotateResponse.getDocument());
}
}
}

View File

@ -0,0 +1,121 @@
[
{
"annotationId": "6113d300d4a5cd7e0e91ef692e046fc5",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 147.86,
"topLeftY": 519.11,
"width": 122.496,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "04d043c73922f6e0dc50a1c7484e9425",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 147.86,
"topLeftY": 544.43,
"width": 83.414,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "83f5f2cbe55f2acbbf7adc479cf694cb",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 147.86,
"topLeftY": 557.03,
"width": 57.624,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "4bacdb3675c46181c75295fe8c6e6562",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 147.86,
"topLeftY": 531.83,
"width": 83.414,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "8db925e788f2ab1c9ded097a9de10111",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 148.94,
"topLeftY": 317.49,
"width": 141.263,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "a4d2f29216efe7507bf97d2e55010dd4",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 148.94,
"topLeftY": 342.81,
"width": 94.389,
"height": 11.018,
"page": 1
}
],
"status": "NEW",
"user": null,
"comment": null,
"processedDate": null
},
{
"annotationId": "9983b5000e8f3540a402178f91b3a2e2",
"fileId": "536bfa2d5ef9aecedda09e300a37cd81",
"positions": [
{
"topLeftX": 148.94,
"topLeftY": 330.21,
"width": 94.332,
"height": 11.018,
"page": 1
}
],
"status": "APPROVED",
"user": "its a me",
"comment": "First Test",
"processedDate": "2022-01-27T12:57:25.48Z"
}
]