From 6a20d95641b88a34eae65f7b7b1700f60b30c286 Mon Sep 17 00:00:00 2001 From: arys Date: Tue, 3 Mar 2026 14:30:52 +0500 Subject: [PATCH] fix --- .../service/GeminiVideoGenerationService.java | 77 +++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/main/java/kz/konturai/parser/service/GeminiVideoGenerationService.java b/src/main/java/kz/konturai/parser/service/GeminiVideoGenerationService.java index d8c7555..479063a 100644 --- a/src/main/java/kz/konturai/parser/service/GeminiVideoGenerationService.java +++ b/src/main/java/kz/konturai/parser/service/GeminiVideoGenerationService.java @@ -42,10 +42,10 @@ public class GeminiVideoGenerationService { public GeminiVideoGenerationService() { HttpClient httpClient = HttpClient.create() .resolver(DefaultAddressResolverGroup.INSTANCE) - .responseTimeout(Duration.ofMillis(600000)); + .responseTimeout(Duration.ofMillis(600000)); // 10 минут таймаут ExchangeStrategies strategies = ExchangeStrategies.builder() - .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(150 * 1024 * 1024)) + .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(150 * 1024 * 1024)) // 150 MB под видео .build(); this.webClient = WebClient.builder() @@ -54,19 +54,52 @@ public class GeminiVideoGenerationService { .build(); } - public byte[] generateVideo(String prompt) { + // НОВЫЙ МЕТОД: Полная диагностика перед запуском + private boolean runPreflightCheck() { + logger.info("=== СТАРТ ДИАГНОСТИКИ VEO ==="); + + // Шаг 1. Проверяем переменные окружения if (projectId == null || projectId.trim().isEmpty()) { - logger.error("VEO: Project ID is missing!"); + logger.error("[ПРОВАЛ] Project ID не задан в application.properties!"); + return false; + } + logger.info("[ОК] Project ID: {}", projectId); + logger.info("[ОК] Location: {}", location); + logger.info("[ОК] Model: {}", model); + + // Шаг 2. Проверяем файл ключа + ClassPathResource resource = new ClassPathResource(CREDENTIALS_FILE_PATH); + if (!resource.exists()) { + logger.error("[ПРОВАЛ] Файл ключа не найден по пути: src/main/resources/{}", CREDENTIALS_FILE_PATH); + return false; + } + logger.info("[ОК] Файл ключа найден."); + + // Шаг 3. Проверяем генерацию токена + String token = getAccessTokenFromResources(); + if (token == null || token.isEmpty()) { + logger.error("[ПРОВАЛ] Не удалось сгенерировать Access Token. Проверьте содержимое ключа и права аккаунта!"); + return false; + } + logger.info("[ОК] Access Token успешно сгенерирован (длина: {})", token.length()); + + // Шаг 4. Проверяем URL + String endpointUrl = String.format(VERTEX_API_TEMPLATE, location, projectId, location, model); + logger.info("[ОК] Endpoint URL сформирован: {}", endpointUrl); + + logger.info("=== ДИАГНОСТИКА УСПЕШНО ЗАВЕРШЕНА ==="); + return true; + } + + public byte[] generateVideo(String prompt) { + // Запускаем проверку перед каждой генерацией + if (!runPreflightCheck()) { + logger.error("VEO: Генерация отменена из-за провала базовых проверок."); return null; } try { String accessToken = getAccessTokenFromResources(); - if (accessToken == null) { - logger.error("VEO: Failed to load Google Credentials!"); - return null; - } - String endpointUrl = String.format(VERTEX_API_TEMPLATE, location, projectId, location, model); Map requestBody = new HashMap<>(); @@ -80,7 +113,8 @@ public class GeminiVideoGenerationService { parameters.put("aspectRatio", "9:16"); requestBody.put("parameters", parameters); - logger.info("VEO: Requesting video generation. Prompt: {}", prompt); + // Логируем сам запрос, чтобы проверить его формат + logger.info("VEO: Отправка JSON запроса в Google: {}", requestBody); Map response = webClient.post() .uri(URI.create(endpointUrl)) @@ -96,17 +130,22 @@ public class GeminiVideoGenerationService { byte[] videoBytes = extractVideoFromResponse(response); if (videoBytes != null) { - logger.info("VEO: Successfully generated video! Size: {} bytes", videoBytes.length); + logger.info("VEO: Успех! Видео сгенерировано. Размер: {} байт", videoBytes.length); } else { - logger.error("VEO: Failed to extract video bytes from Google response."); + logger.error("VEO: Видео не найдено в ответе. Ответ от Google: {}", response); } return videoBytes; } catch (WebClientResponseException e) { - logger.error("VEO API Error! Status: {}, Body: {}", e.getStatusCode(), e.getResponseBodyAsString()); + // САМОЕ ВАЖНОЕ: Расшифровка ответа от Google + logger.error("=================================================="); + logger.error("VEO API ERROR CRASH!"); + logger.error("HTTP Status Code: {}", e.getStatusCode()); + logger.error("Error Body from Google: {}", e.getResponseBodyAsString()); + logger.error("=================================================="); return null; } catch (Exception e) { - logger.error("VEO API Fatal Error: {}", e.getMessage()); + logger.error("VEO API Неизвестная ошибка: {}", e.getMessage(), e); return null; } } @@ -122,6 +161,7 @@ public class GeminiVideoGenerationService { return credentials.getAccessToken().getTokenValue(); } } catch (IOException e) { + logger.error("Ошибка при чтении файла ключа: {}", e.getMessage()); return null; } } @@ -133,12 +173,21 @@ public class GeminiVideoGenerationService { List> predictions = (List>) response.get("predictions"); if (predictions != null && !predictions.isEmpty()) { Map firstPrediction = predictions.get(0); + + // Проверяем разные варианты ключей, в которых Google может вернуть видео String base64Video = (String) firstPrediction.get("bytesBase64Encoded"); + if (base64Video == null) { + base64Video = (String) firstPrediction.get("b64"); + } + if (base64Video != null) { return java.util.Base64.getDecoder().decode(base64Video); + } else { + logger.warn("VEO: Ключ с Base64 видео не найден в 'predictions'. Доступные ключи: {}", firstPrediction.keySet()); } } } catch (Exception e) { + logger.error("VEO: Ошибка парсинга ответа: {}", e.getMessage()); } return null; }