From fea2d5ad8929b5875ceaa825761ad93705b8475a Mon Sep 17 00:00:00 2001 From: vladp Date: Tue, 10 Feb 2026 16:23:49 +0700 Subject: [PATCH] dev add utf encoding --- .../handler/ImageFoundRequestHandler.java | 7 +- .../SearchApiToYandexResponseMapper.java | 94 ++++++++----- .../service/search/YandexSearchService.java | 127 ------------------ 3 files changed, 64 insertions(+), 164 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java index e02d034..000f74a 100644 --- a/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/ImageFoundRequestHandler.java @@ -79,15 +79,14 @@ public class ImageFoundRequestHandler implements RequestHandler { Map.of("fileId", fileId)); } - int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1; - int pageSize = imageSearchRequest.getPageSize() != null ? imageSearchRequest.getPageSize() : 10; - tariffInfoService.writeOffTokens(fileEntity.getUserId(), TariffConstants.TOKEN_VALUE_FOR_SEARCH); checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType()); + int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1; + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getDescription(), mapper.mapToYandexResponse(yandexReverseSearchResponse, page, - pageSize)); + 10)); } } diff --git a/src/main/java/ru/soune/nocopy/service/search/SearchApiToYandexResponseMapper.java b/src/main/java/ru/soune/nocopy/service/search/SearchApiToYandexResponseMapper.java index 5403d04..4c66a4d 100644 --- a/src/main/java/ru/soune/nocopy/service/search/SearchApiToYandexResponseMapper.java +++ b/src/main/java/ru/soune/nocopy/service/search/SearchApiToYandexResponseMapper.java @@ -3,57 +3,85 @@ package ru.soune.nocopy.service.search; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import ru.soune.nocopy.dto.file.YandexSearchResponse; + +import java.io.IOException; import java.util.ArrayList; import java.util.List; public class SearchApiToYandexResponseMapper { private final ObjectMapper objectMapper = new ObjectMapper(); - public YandexSearchResponse mapToYandexResponse(String searchApiJson, int page, int pageSize) throws Exception { + public YandexSearchResponse mapToYandexResponse(String searchApiJson, int page, int pageSize) throws IOException { + JsonNode root = objectMapper.readTree(searchApiJson); - - YandexSearchResponse response = new YandexSearchResponse(); - List imageResults = new ArrayList<>(); - JsonNode visualMatches = root.path("visual_matches"); - if (visualMatches.isArray()) { - int startIndex = (page - 1) * pageSize; - int endIndex = Math.min(startIndex + pageSize, visualMatches.size()); - - for (int i = startIndex; i < endIndex; i++) { - JsonNode match = visualMatches.get(i); - YandexSearchResponse.ImageResult result = new YandexSearchResponse.ImageResult(); - - JsonNode imageNode = match.path("image"); - if (!imageNode.isMissingNode()) { - result.setUrl(imageNode.path("link").asText()); - result.setWidth(imageNode.path("width").asInt()); - result.setHeight(imageNode.path("height").asInt()); - } - - result.setPageUrl(match.path("link").asText()); - result.setPageTitle(match.path("title").asText()); - - String source = match.path("source").asText(); - result.setHost(extractHostFromSource(source)); - - if (result.getUrl() != null && !result.getUrl().isEmpty()) { - imageResults.add(result); - } - } + YandexSearchResponse response = new YandexSearchResponse(); + List images = new ArrayList<>(); + if (!visualMatches.isArray() || visualMatches.isEmpty()) { + response.setImages(images); response.setPage(page); response.setPageSize(pageSize); - response.setTotalResults(visualMatches.size()); - response.setTotalPages((int) Math.ceil((double) visualMatches.size() / pageSize)); + response.setTotalResults(0); + response.setTotalPages(0); + return response; } - response.setImages(imageResults); + int totalResults = visualMatches.size(); + int totalPages = (int) Math.ceil((double) totalResults / pageSize); + + if (page > totalPages) { + response.setImages(images); + response.setPage(page); + response.setPageSize(pageSize); + response.setTotalResults(totalResults); + response.setTotalPages(totalPages); + return response; + } + + int startIndex = (page - 1) * pageSize; + int endIndex = Math.min(startIndex + pageSize, totalResults); + + for (int i = startIndex; i < endIndex; i++) { + JsonNode match = visualMatches.get(i); + YandexSearchResponse.ImageResult result = mapImageResult(match); + + if (result.getUrl() != null && !result.getUrl().isBlank()) { + images.add(result); + } + } + + response.setImages(images); + response.setPage(page); + response.setPageSize(pageSize); + response.setTotalResults(totalResults); + response.setTotalPages(totalPages); return response; } + private YandexSearchResponse.ImageResult mapImageResult(JsonNode match) { + + YandexSearchResponse.ImageResult result = + new YandexSearchResponse.ImageResult(); + + JsonNode imageNode = match.path("image"); + if (imageNode.isObject()) { + result.setUrl(imageNode.path("link").asText(null)); + result.setWidth(imageNode.path("width").asInt(0)); + result.setHeight(imageNode.path("height").asInt(0)); + } + + result.setPageUrl(match.path("link").asText(null)); + result.setPageTitle(match.path("title").asText(null)); + + String source = match.path("source").asText(null); + result.setHost(extractHostFromSource(source)); + + return result; + } + private String extractHostFromSource(String source) { if (source == null || source.isEmpty()) { return ""; diff --git a/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java b/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java index 0240a9a..3102e89 100644 --- a/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java +++ b/src/main/java/ru/soune/nocopy/service/search/YandexSearchService.java @@ -103,46 +103,6 @@ public class YandexSearchService { return callReverseImageApiByUrl(publicUrl); } -// private String callReverseImageApiByUrl(String imageUrl) throws IOException { -// if (searchApiKey == null || searchApiKey.isEmpty()) { -// throw new IllegalStateException("SearchAPI key not configured. Set searchapi.api-key property"); -// } -// -// HttpUrl url = HttpUrl.parse("https://searchapi.io/api/v1/search") -// .newBuilder() -// .addQueryParameter("engine", "yandex_reverse_image") -// .addQueryParameter("api_key", searchApiKey) -// .addQueryParameter("url", imageUrl) -// .addQueryParameter("wait", "true") -// .addQueryParameter("timeout", "30000") -// .build(); -// -// log.info("Calling Yandex Reverse Image API: {}", url); -// -// Request request = new Request.Builder() -// .url(url) -// .header("Accept", "application/json") -// .header("User-Agent", "Mozilla/5.0") -// .build(); -// -// try (Response response = httpClient.newCall(request).execute()) { -// log.info("Response code: {}", response.code()); -// log.info("Response headers: {}", response.headers()); -// -// if (!response.isSuccessful()) { -// String errorBody = response.body() != null ? response.body().string() : "No error body"; -// log.error("API request failed: {} - {}", response.code(), errorBody); -// throw new IOException("API request failed: " + response.code() + " - " + response.message()); -// } -// -// String responseBody = response.body().string(); -// log.info("Response body length: {} characters", responseBody.length()); -// -// return responseBody; -// } -// } - - private boolean isImageFile(FileEntity fileEntity) { String mimeType = fileEntity.getMimeType(); return mimeType != null && mimeType.startsWith("image"); @@ -275,93 +235,6 @@ public class YandexSearchService { } } -// public String searchReverseByPublicUrlWithTimeout(FileEntity fileEntity, int timeoutSeconds) -// throws IOException, TimeoutException { -// if (!isImageFile(fileEntity)) { -// log.error("File not image: {}", fileEntity.getMimeType()); -// throw new NotValidFieldException("File not image", new BaseResponse(20007, -// MessageCode.INVALID_FIELD.getCode(), MessageCode.INVALID_FIELD.getDescription(), -// Map.of("file_type", fileEntity.getMimeType()))); -// } -// -// String publicUrl = String.format("%s/api/files/public/%s", appBaseUrl, fileEntity.getId()); -// log.info("Searching reverse for image: {}", publicUrl); -// -// ExecutorService executor = Executors.newSingleThreadExecutor(); -// -// try { -// Future future = executor.submit(() -> -// callReverseImageApiByUrlWithTimeout(publicUrl, timeoutSeconds) -// ); -// -// return future.get(timeoutSeconds, TimeUnit.SECONDS); -// -// } catch (TimeoutException e) { -// log.error("Yandex search timeout after {} seconds for file: {}", timeoutSeconds, fileEntity.getId()); -// throw e; -// } catch (InterruptedException e) { -// Thread.currentThread().interrupt(); -// throw new IOException("Search interrupted", e); -// } catch (ExecutionException e) { -// Throwable cause = e.getCause(); -// if (cause instanceof IOException) { -// throw (IOException) cause; -// } -// throw new IOException("Search failed", cause); -// } finally { -// executor.shutdownNow(); -// } -// } - -// private String callReverseImageApiByUrlWithTimeout(String imageUrl, int timeoutSeconds) throws IOException { -// if (searchApiKey == null || searchApiKey.isEmpty()) { -// throw new IllegalStateException("SearchAPI key not configured"); -// } -// -// int apiTimeout = Math.max(1, timeoutSeconds - 2) * 1000; -// -// HttpUrl url = HttpUrl.parse("https://searchapi.io/api/v1/search") -// .newBuilder() -// .addQueryParameter("engine", "yandex_reverse_image") -// .addQueryParameter("api_key", searchApiKey) -// .addQueryParameter("url", imageUrl) -// .addQueryParameter("wait", "true") -// .addQueryParameter("timeout", String.valueOf(apiTimeout)) -// .build(); -// -// log.info("Calling Yandex API with timeout {}ms: {}", apiTimeout, imageUrl); -// -// Request request = new Request.Builder() -// .url(url) -// .header("Accept", "application/json") -// .header("User-Agent", "Mozilla/5.0") -// .build(); -// -// long startTime = System.currentTimeMillis(); -// -// try (Response response = httpClient.newCall(request).execute()) { -// long duration = System.currentTimeMillis() - startTime; -// -// log.info("Response code: {}, duration: {}ms", response.code(), duration); -// -// if (!response.isSuccessful()) { -// String errorBody = response.body() != null ? response.body().string() : "No error body"; -// log.error("API request failed: {} - {}", response.code(), errorBody); -// throw new IOException("API request failed: " + response.code()); -// } -// -// ResponseBody body = response.body(); -// if (body == null) { -// throw new IOException("Empty response body"); -// } -// -// String responseBody = body.string(); -// log.info("Response body length: {} characters", responseBody.length()); -// -// return responseBody; -// } -// } - private String readAll(BufferedReader reader) throws IOException { StringBuilder sb = new StringBuilder(); String line;