Merge remote-tracking branch 'refs/remotes/origin/analyze-graphics' into analyze-graphics
This commit is contained in:
@@ -289,12 +289,29 @@ public class MarketingStrategyService {
|
|||||||
if (optAnalysis.isPresent()) {
|
if (optAnalysis.isPresent()) {
|
||||||
MarketingAnalysis analysis = optAnalysis.get();
|
MarketingAnalysis analysis = optAnalysis.get();
|
||||||
StringBuilder businessContext = new StringBuilder();
|
StringBuilder businessContext = new StringBuilder();
|
||||||
if (analysis.getBusinessNiche() != null) {
|
|
||||||
businessContext.append("Ниша бизнеса: ").append(analysis.getBusinessNiche()).append(". ");
|
if (analysis.getProduct() != null && !analysis.getProduct().isEmpty()) {
|
||||||
|
businessContext.append("Главный объект изображения (продукт): ").append(analysis.getProduct()).append(". ");
|
||||||
}
|
}
|
||||||
if (analysis.getProduct() != null) {
|
|
||||||
businessContext.append("Продукт: ").append(analysis.getProduct()).append(".");
|
if (analysis.getBusinessNiche() != null && !analysis.getBusinessNiche().isEmpty()) {
|
||||||
|
businessContext.append("Ниша: ").append(analysis.getBusinessNiche()).append(". ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (analysis.getTargetAudience() != null) {
|
||||||
|
Map<String, Object> ta = analysis.getTargetAudience();
|
||||||
|
if (ta.containsKey("ageRanges") || ta.containsKey("types")) {
|
||||||
|
businessContext.append("Целевая аудитория (люди на фото): ");
|
||||||
|
if (ta.containsKey("types")) {
|
||||||
|
businessContext.append(ta.get("types")).append(" ");
|
||||||
|
}
|
||||||
|
if (ta.containsKey("ageRanges")) {
|
||||||
|
businessContext.append("возраст ").append(ta.get("ageRanges"));
|
||||||
|
}
|
||||||
|
businessContext.append(". ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return businessContext.toString();
|
return businessContext.toString();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -504,14 +521,13 @@ public class MarketingStrategyService {
|
|||||||
|
|
||||||
private void generateAndSaveImageForPost(MarketingStrategy.PostCalendarItem item, String businessContext) {
|
private void generateAndSaveImageForPost(MarketingStrategy.PostCalendarItem item, String businessContext) {
|
||||||
try {
|
try {
|
||||||
// Create prompt for image generation
|
|
||||||
String imagePrompt = buildImagePrompt(item, businessContext);
|
String imagePrompt = buildImagePrompt(item, businessContext);
|
||||||
|
|
||||||
// Generate image
|
logger.info("Generating image with prompt: {}", imagePrompt);
|
||||||
|
|
||||||
byte[] imageBytes = imageGenerationService.generateImage(imagePrompt);
|
byte[] imageBytes = imageGenerationService.generateImage(imagePrompt);
|
||||||
|
|
||||||
if (imageBytes != null && imageBytes.length > 0) {
|
if (imageBytes != null && imageBytes.length > 0) {
|
||||||
// Save image to MinIO
|
|
||||||
String filename = "post_image_" + System.currentTimeMillis() + "_" + item.hashCode() + ".png";
|
String filename = "post_image_" + System.currentTimeMillis() + "_" + item.hashCode() + ".png";
|
||||||
minIOService.uploadFile(filename, imageBytes, MediaType.IMAGE_PNG.toString());
|
minIOService.uploadFile(filename, imageBytes, MediaType.IMAGE_PNG.toString());
|
||||||
|
|
||||||
@@ -531,26 +547,36 @@ public class MarketingStrategyService {
|
|||||||
|
|
||||||
private String buildImagePrompt(MarketingStrategy.PostCalendarItem item, String businessContext) {
|
private String buildImagePrompt(MarketingStrategy.PostCalendarItem item, String businessContext) {
|
||||||
StringBuilder prompt = new StringBuilder();
|
StringBuilder prompt = new StringBuilder();
|
||||||
prompt.append("Создай привлекательное маркетинговое изображение для поста в социальных сетях. ");
|
|
||||||
|
|
||||||
|
String style = "высококачественная фотография, реалистичное освещение, 8k, высокая детализация";
|
||||||
|
if (item.getPlatform() != null) {
|
||||||
|
String platform = item.getPlatform().toLowerCase();
|
||||||
|
if (platform.contains("linkedin")) {
|
||||||
|
style += ", корпоративный стиль, профессионально, минимализм, чисто";
|
||||||
|
} else if (platform.contains("instagram") || platform.contains("tiktok")) {
|
||||||
|
style += ", лайфстайл, эстетика, яркие цвета, привлекательно, инстаграм-стиль";
|
||||||
|
} else if (platform.contains("facebook")) {
|
||||||
|
style += ", уютно, дружелюбно, для сообщества";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.append("Фотореалистичное изображение. ");
|
||||||
|
|
||||||
|
// Добавляем контекст продукта (это самое важное!)
|
||||||
if (businessContext != null && !businessContext.isEmpty()) {
|
if (businessContext != null && !businessContext.isEmpty()) {
|
||||||
prompt.append(businessContext).append(" ");
|
prompt.append(businessContext).append(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Контекст поста
|
||||||
if (item.getTheme() != null && !item.getTheme().isEmpty()) {
|
if (item.getTheme() != null && !item.getTheme().isEmpty()) {
|
||||||
prompt.append("Тема поста: ").append(item.getTheme()).append(". ");
|
prompt.append("Сюжет изображения: ").append(item.getTheme()).append(". ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getPostText() != null && !item.getPostText().isEmpty()) {
|
prompt.append("Композиция: продукт или услуга в центре внимания. ");
|
||||||
// Use first 100 characters of post text for context
|
prompt.append("Если на фото есть люди, они должны взаимодействовать с продуктом естественно. ");
|
||||||
String textPreview = item.getPostText().length() > 100
|
prompt.append("Избегать: абстрактных концепций, людей с планшетами смотрящих в камеру, искусственных поз, текста на изображении, размытия, искажений. ");
|
||||||
? item.getPostText().substring(0, 100) + "..."
|
|
||||||
: item.getPostText();
|
|
||||||
prompt.append("Текст поста: ").append(textPreview).append(". ");
|
|
||||||
}
|
|
||||||
|
|
||||||
prompt.append("Стиль: современный, профессиональный, привлекающий внимание, подходящий для социальных сетей. ");
|
prompt.append("Визуальный стиль: ").append(style).append(".");
|
||||||
prompt.append("Изображение должно быть ярким, но не перегруженным, с акцентом на главную идею поста.");
|
|
||||||
|
|
||||||
return prompt.toString();
|
return prompt.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,14 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
String endpointUrl = String.format(VERTEX_API_TEMPLATE, location, projectId, location, model);
|
String endpointUrl = String.format(VERTEX_API_TEMPLATE, location, projectId, location, model);
|
||||||
String enrichedPrompt = enrichPromptForGemini(prompt);
|
|
||||||
Map<String, Object> requestBody = buildImagenRequestBody(enrichedPrompt);
|
|
||||||
|
String finalPrompt = prompt;
|
||||||
|
if (prompt != null && prompt.length() < 50) {
|
||||||
|
finalPrompt = "High quality, photorealistic image of: " + prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> requestBody = buildImagenRequestBody(finalPrompt);
|
||||||
|
|
||||||
logger.info("Sending request to Vertex AI. Project: {}, Model: {}", projectId, model);
|
logger.info("Sending request to Vertex AI. Project: {}, Model: {}", projectId, model);
|
||||||
|
|
||||||
@@ -150,9 +156,11 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
|||||||
Map<String, Object> parameters = new HashMap<>();
|
Map<String, Object> parameters = new HashMap<>();
|
||||||
parameters.put("sampleCount", 1);
|
parameters.put("sampleCount", 1);
|
||||||
parameters.put("aspectRatio", "1:1");
|
parameters.put("aspectRatio", "1:1");
|
||||||
|
|
||||||
parameters.put("safetyFilterLevel", "block_some");
|
parameters.put("safetyFilterLevel", "block_some");
|
||||||
parameters.put("personGeneration", "allow_adult");
|
parameters.put("personGeneration", "allow_adult");
|
||||||
parameters.put("negativePrompt", "nsfw, nudity, sexual content, lgbt symbols, rainbow flags, provocative clothing, violence, gore, blood, deformed, ugly, watermark, text, signature");
|
|
||||||
|
parameters.put("negativePrompt", "nsfw, nudity, sexual content, lgbt symbols, rainbow flags, provocative clothing, violence, gore, blood, deformed, ugly, watermark, text, signature, low quality, blurry, distorted, unrealistic");
|
||||||
|
|
||||||
body.put("parameters", parameters);
|
body.put("parameters", parameters);
|
||||||
return body;
|
return body;
|
||||||
@@ -186,9 +194,4 @@ public class NanoBananaImageGenerationService implements ImageGenerationService
|
|||||||
.filter(t -> t instanceof WebClientResponseException &&
|
.filter(t -> t instanceof WebClientResponseException &&
|
||||||
((WebClientResponseException) t).getStatusCode().value() == 429);
|
((WebClientResponseException) t).getStatusCode().value() == 429);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String enrichPromptForGemini(String original) {
|
|
||||||
return "Professional, high quality, photorealistic image of: " + original +
|
|
||||||
". Style: neutral, business-appropriate, culturally respectful.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user