diff --git a/src/main/java/ru/soune/nocopy/dto/file/ImageSearchRequest.java b/src/main/java/ru/soune/nocopy/dto/file/ImageSearchRequest.java index ff4fd06..27d6a27 100644 --- a/src/main/java/ru/soune/nocopy/dto/file/ImageSearchRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/file/ImageSearchRequest.java @@ -8,6 +8,9 @@ public class ImageSearchRequest { @JsonProperty("file_id") private String fileId; + @JsonProperty("check_similar_first") + private Boolean checkSimilarFirst; + @JsonProperty("page") private Integer page = 1; diff --git a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java index 741bf3e..cc1fcd0 100644 --- a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java @@ -14,12 +14,19 @@ import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.tokenoperation.OperationType; import ru.soune.nocopy.exception.NotValidFieldException; import ru.soune.nocopy.repository.FileEntityRepository; +import ru.soune.nocopy.repository.SimilarImageProjection; +import ru.soune.nocopy.service.FileSimilarityService; +import ru.soune.nocopy.service.ImageHashService; import ru.soune.nocopy.service.file.CheckCounterService; +import ru.soune.nocopy.service.file.FileUploadService; import ru.soune.nocopy.service.search.SearchImageService; import ru.soune.nocopy.service.tariff.TariffConstants; import ru.soune.nocopy.service.tariff.TariffInfoService; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeoutException; @@ -40,6 +47,12 @@ public class ImageFoundRequestHandler implements RequestHandler { private final SearchProperties searchProperties; + private final FileUploadService fileUploadService; + + private final ImageHashService imageHashService; + + private final FileSimilarityService fileSimilarityService; + @Override public BaseResponse handle(BaseRequest request) throws Exception { ImageSearchRequest imageSearchRequest = objectMapper.convertValue(request.getMessageBody(), @@ -125,6 +138,35 @@ public class ImageFoundRequestHandler implements RequestHandler { int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1; int pageSize = 5; + if (imageSearchRequest.getCheckSimilarFirst() && !allUniqueImages.isEmpty()) { + YandexSearchResponse.ImageResult image = allUniqueImages.getFirst(); + String url = image.getUrl(); + Path tempFile = null; + + try { + tempFile = fileUploadService.downloadImageFromUrl(url); + String filePath = tempFile.toAbsolutePath().toString(); + + Map hash = imageHashService.calculateHash(Paths.get(filePath)); + + List duplicates = fileSimilarityService.findDuplicatedByHash(hash.get("hi"), + hash.get("low")); + + if (duplicates.isEmpty()) { + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + "Not found similar pictures", new YandexSearchResponse()); + } + } finally { + if (tempFile != null) { + try { + Files.deleteIfExists(tempFile); + } catch (IOException e) { + log.warn("Not delete temp file: {}", tempFile, e); + } + } + } + } + List pagedResults = searchImageService.paginateResults(allUniqueImages, page, pageSize * 2); diff --git a/src/main/java/ru/soune/nocopy/service/file/FileUploadService.java b/src/main/java/ru/soune/nocopy/service/file/FileUploadService.java index ac7bc06..7882c21 100644 --- a/src/main/java/ru/soune/nocopy/service/file/FileUploadService.java +++ b/src/main/java/ru/soune/nocopy/service/file/FileUploadService.java @@ -5,6 +5,10 @@ import ru.soune.nocopy.dto.file.UploadProgressResponse; import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.file.FileUploadSession; +import ru.soune.nocopy.exception.DuplicateImageException; + +import java.io.IOException; +import java.nio.file.Path; public interface FileUploadService { FileUploadSession initUpload(Long userId, String fileName, @@ -22,4 +26,8 @@ public interface FileUploadService { UploadProgressResponse getUploadProgress(String uploadId); FileEntity completeFileProcessing(FileUploadSession session, FileStatus status); + + public void checkForDuplicatesSynchronously(String filePath) throws IOException, DuplicateImageException; + + public Path downloadImageFromUrl(String urlString) throws IOException; } diff --git a/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java b/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java index 915aca5..36a83c3 100644 --- a/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java +++ b/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java @@ -6,13 +6,11 @@ import com.vrt.fileprotection.NoCopyCheckResult; import com.vrt.fileprotection.audio.AudioCheckResult; import com.vrt.fileprotection.documents.DocumentCheckResult; import jakarta.annotation.PostConstruct; -import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -30,7 +28,6 @@ import ru.soune.nocopy.service.cost.CostService; import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileUploadService; import ru.soune.nocopy.service.file.cloud.CloudStorageService; -import ru.soune.nocopy.service.tariff.TariffConstants; import ru.soune.nocopy.service.file.moderation.ModerationFileService; import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.register.AuthService; @@ -38,6 +35,8 @@ import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.util.FileUtil; import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; import java.nio.file.*; import java.nio.file.attribute.PosixFilePermission; import java.security.MessageDigest; @@ -584,8 +583,8 @@ public class FileUploadServiceImpl implements FileUploadService { return finalFilePath.toString(); } - private void checkForDuplicatesSynchronously(String filePath) - throws IOException , DuplicateImageException { + @Override + public void checkForDuplicatesSynchronously(String filePath) throws IOException , DuplicateImageException { Path path = Paths.get(filePath); Map hash = imageHashService.calculateHash(path); @@ -599,6 +598,33 @@ public class FileUploadServiceImpl implements FileUploadService { } } + public Path downloadImageFromUrl(String urlString) throws IOException { + URL url = new URL(urlString); + + String extension = ".tmp"; + String path = url.getPath(); + int lastDot = path.lastIndexOf('.'); + if (lastDot > 0) { + String ext = path.substring(lastDot).toLowerCase(); + if (ext.matches("\\.(jpg|jpeg|png|gif|bmp|webp)")) { + extension = ext; + } + } + + Path tempFile = Files.createTempFile("upload_check_", extension); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(10000); + + try (InputStream in = connection.getInputStream()) { + Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING); + } + + return tempFile; + } + private UploadProgressResponse handleExistingChunk(FileUploadSession session, Integer chunkNumber, MultipartFile chunkFile,