fix
This commit is contained in:
@@ -2,6 +2,8 @@ package kz.konturai.parser.service;
|
||||
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import io.netty.resolver.DefaultAddressResolverGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -22,6 +24,7 @@ import java.util.*;
|
||||
@Service
|
||||
public class GeminiVideoGenerationService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GeminiVideoGenerationService.class);
|
||||
private static final String VERTEX_API_TEMPLATE = "https://%s-aiplatform.googleapis.com/v1/projects/%s/locations/%s/publishers/google/models/%s:predict";
|
||||
private static final String CREDENTIALS_FILE_PATH = "keys/google-key.json";
|
||||
|
||||
@@ -39,10 +42,10 @@ public class GeminiVideoGenerationService {
|
||||
public GeminiVideoGenerationService() {
|
||||
HttpClient httpClient = HttpClient.create()
|
||||
.resolver(DefaultAddressResolverGroup.INSTANCE)
|
||||
.responseTimeout(Duration.ofMillis(300000));
|
||||
.responseTimeout(Duration.ofMillis(600000));
|
||||
|
||||
ExchangeStrategies strategies = ExchangeStrategies.builder()
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(100 * 1024 * 1024))
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(150 * 1024 * 1024))
|
||||
.build();
|
||||
|
||||
this.webClient = WebClient.builder()
|
||||
@@ -52,13 +55,15 @@ public class GeminiVideoGenerationService {
|
||||
}
|
||||
|
||||
public byte[] generateVideo(String prompt) {
|
||||
if (projectId == null || projectId.isEmpty()) {
|
||||
if (projectId == null || projectId.trim().isEmpty()) {
|
||||
logger.error("VEO: Project ID is missing!");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String accessToken = getAccessTokenFromResources();
|
||||
if (accessToken == null) {
|
||||
logger.error("VEO: Failed to load Google Credentials!");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -75,6 +80,8 @@ public class GeminiVideoGenerationService {
|
||||
parameters.put("aspectRatio", "9:16");
|
||||
requestBody.put("parameters", parameters);
|
||||
|
||||
logger.info("VEO: Requesting video generation. Prompt: {}", prompt);
|
||||
|
||||
Map<String, Object> response = webClient.post()
|
||||
.uri(URI.create(endpointUrl))
|
||||
.header("Authorization", "Bearer " + accessToken)
|
||||
@@ -85,11 +92,21 @@ public class GeminiVideoGenerationService {
|
||||
.retryWhen(reactor.util.retry.Retry.backoff(3, Duration.ofSeconds(15))
|
||||
.filter(t -> t instanceof WebClientResponseException &&
|
||||
((WebClientResponseException) t).getStatusCode().value() == 429))
|
||||
.block(Duration.ofMillis(300000));
|
||||
.block(Duration.ofMillis(600000));
|
||||
|
||||
return extractVideoFromResponse(response);
|
||||
byte[] videoBytes = extractVideoFromResponse(response);
|
||||
if (videoBytes != null) {
|
||||
logger.info("VEO: Successfully generated video! Size: {} bytes", videoBytes.length);
|
||||
} else {
|
||||
logger.error("VEO: Failed to extract video bytes from Google response.");
|
||||
}
|
||||
return videoBytes;
|
||||
|
||||
} catch (WebClientResponseException e) {
|
||||
logger.error("VEO API Error! Status: {}, Body: {}", e.getStatusCode(), e.getResponseBodyAsString());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
logger.error("VEO API Fatal Error: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +135,7 @@ public class GeminiVideoGenerationService {
|
||||
Map<String, Object> firstPrediction = predictions.get(0);
|
||||
String base64Video = (String) firstPrediction.get("bytesBase64Encoded");
|
||||
if (base64Video != null) {
|
||||
return Base64.getDecoder().decode(base64Video);
|
||||
return java.util.Base64.getDecoder().decode(base64Video);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -43,22 +43,13 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
||||
@Value("${google.gemini.image.model:imagen-3.0-generate-001}")
|
||||
private String model;
|
||||
|
||||
@Value("${google.gemini.timeoutMs:120000}")
|
||||
private long timeoutMs;
|
||||
|
||||
@Value("${google.gemini.retry.maxAttempts:5}")
|
||||
private int maxRetryAttempts;
|
||||
|
||||
@Value("${google.gemini.rateLimit.delayMs:15000}")
|
||||
private long rateLimitDelayMs;
|
||||
|
||||
public NanoBananaImageGenerationService() {
|
||||
HttpClient httpClient = HttpClient.create()
|
||||
.resolver(DefaultAddressResolverGroup.INSTANCE)
|
||||
.responseTimeout(Duration.ofMillis(120000));
|
||||
.responseTimeout(Duration.ofMillis(180000));
|
||||
|
||||
ExchangeStrategies strategies = ExchangeStrategies.builder()
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(20 * 1024 * 1024))
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(30 * 1024 * 1024))
|
||||
.build();
|
||||
|
||||
this.webClient = WebClient.builder()
|
||||
@@ -92,8 +83,8 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
||||
semaphore.acquire();
|
||||
|
||||
long timeSinceLast = System.currentTimeMillis() - lastRequestTimestamp;
|
||||
if (timeSinceLast < rateLimitDelayMs) {
|
||||
Thread.sleep(rateLimitDelayMs - timeSinceLast);
|
||||
if (timeSinceLast < 15000) {
|
||||
Thread.sleep(15000 - timeSinceLast);
|
||||
}
|
||||
|
||||
String accessToken = getAccessTokenFromResources();
|
||||
@@ -137,11 +128,11 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
||||
.bodyValue(requestBody)
|
||||
.retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
|
||||
.retryWhen(reactor.util.retry.Retry.backoff(maxRetryAttempts, Duration.ofSeconds(10))
|
||||
.retryWhen(reactor.util.retry.Retry.backoff(10, Duration.ofSeconds(10))
|
||||
.maxBackoff(Duration.ofSeconds(60))
|
||||
.filter(t -> t instanceof WebClientResponseException &&
|
||||
((WebClientResponseException) t).getStatusCode().value() == 429))
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
.block(Duration.ofMillis(180000));
|
||||
} catch (WebClientResponseException e) {
|
||||
if (e.getStatusCode().value() == 400) {
|
||||
throw e;
|
||||
@@ -189,7 +180,7 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
||||
refImagesList.add(referenceImageParams);
|
||||
|
||||
instance.put("referenceImages", refImagesList);
|
||||
instance.put("prompt", prompt + ". Naturally integrate the provided reference subject into the scene.");
|
||||
instance.put("prompt", prompt + ". CRITICAL: Preserve the text, letters, and typography of the provided logo EXACTLY as they appear. Do not invent new text, do not distort letters. Integrate naturally.");
|
||||
}
|
||||
|
||||
instances.add(instance);
|
||||
@@ -200,7 +191,7 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
||||
parameters.put("aspectRatio", "1:1");
|
||||
parameters.put("safetyFilterLevel", "block_some");
|
||||
parameters.put("personGeneration", "allow_adult");
|
||||
parameters.put("negativePrompt", "text, typography, watermark, signature, blurry, distorted, bad anatomy");
|
||||
parameters.put("negativePrompt", "gibberish text, alien language, wrong spelling, distorted letters, bad anatomy, nsfw, watermark");
|
||||
|
||||
body.put("parameters", parameters);
|
||||
return body;
|
||||
|
||||
Reference in New Issue
Block a user