.
This commit is contained in:
@@ -92,7 +92,8 @@ public class MarketingStrategyService {
|
||||
}
|
||||
|
||||
@Async("reportGenerationExecutor")
|
||||
public void processStrategyGeneration(String strategyId, String analysisId, MarketingAnalysisResult analysisResult) {
|
||||
public void processStrategyGeneration(String strategyId, String analysisId,
|
||||
MarketingAnalysisResult analysisResult) {
|
||||
try {
|
||||
Optional<MarketingStrategy> optStrategy = repository.findById(strategyId);
|
||||
if (optStrategy.isEmpty()) {
|
||||
@@ -119,7 +120,8 @@ public class MarketingStrategyService {
|
||||
|
||||
// Generate post calendar
|
||||
List<MarketingStrategy.PostCalendarItem> postCalendar = generatePostCalendar(
|
||||
context, strategy.getDurationWeeks(), strategy.getPriorityPlatforms(), weeklyPlans, businessContext);
|
||||
context, strategy.getDurationWeeks(), strategy.getPriorityPlatforms(), weeklyPlans,
|
||||
businessContext);
|
||||
|
||||
// Update strategy
|
||||
strategy.setStatus("completed");
|
||||
@@ -168,7 +170,8 @@ public class MarketingStrategyService {
|
||||
MarketingAnalysisResult.TargetAudience audience = report.getTargetAudience();
|
||||
context.append("Целевая аудитория: ").append(audience.getDescription()).append("\n");
|
||||
if (audience.getChannels() != null && !audience.getChannels().isEmpty()) {
|
||||
context.append("Рекомендуемые каналы: ").append(String.join(", ", audience.getChannels())).append("\n");
|
||||
context.append("Рекомендуемые каналы: ").append(String.join(", ", audience.getChannels()))
|
||||
.append("\n");
|
||||
}
|
||||
context.append("\n");
|
||||
}
|
||||
@@ -191,7 +194,8 @@ public class MarketingStrategyService {
|
||||
context.append("Каналы: ").append(String.join(", ", strategy.getChannels())).append("\n");
|
||||
}
|
||||
if (strategy.getContentTypes() != null && !strategy.getContentTypes().isEmpty()) {
|
||||
context.append("Типы контента: ").append(String.join(", ", strategy.getContentTypes())).append("\n");
|
||||
context.append("Типы контента: ").append(String.join(", ", strategy.getContentTypes()))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,14 +211,19 @@ public class MarketingStrategyService {
|
||||
: "Instagram, Facebook, LinkedIn, Telegram, TikTok, YouTube";
|
||||
|
||||
String prompt = String.format(
|
||||
"На основе следующего маркетингового анализа создай детальный недельный план продвижения на %d недель.\n\n" +
|
||||
"На основе следующего маркетингового анализа создай детальный недельный план продвижения на %d недель.\n\n"
|
||||
+
|
||||
"Требования:\n" +
|
||||
"1. Создай план для каждой недели отдельно\n" +
|
||||
"2. Для каждой недели укажи:\n" +
|
||||
" - Основные темы недели (3-5 тем)\n" +
|
||||
" - Рекомендации по контенту (1-2 абзаца)\n" +
|
||||
" - Приоритетные платформы для этой недели\n" +
|
||||
"3. Платформы для использования: %s\n" +
|
||||
"3. Платформы для использования (СТРОГО ТОЛЬКО ЭТИ ПЛАТФОРМЫ, НЕ ДОБАВЛЯЙ ДРУГИЕ): %s\n" +
|
||||
" ВАЖНО: Используй ТОЛЬКО указанные платформы. Если указан Facebook, используй ТОЛЬКО Facebook (НЕ добавляй Instagram).\n"
|
||||
+
|
||||
" Если указан Instagram, используй ТОЛЬКО Instagram (НЕ добавляй Facebook).\n" +
|
||||
" Каждая платформа независима - не предполагай связи между платформами.\n" +
|
||||
"4. Ответ должен быть структурированным и применимым на практике\n" +
|
||||
"5. Ответ должен быть на русском языке\n\n" +
|
||||
"Верни ответ в формате JSON со следующей структурой:\n" +
|
||||
@@ -245,7 +254,8 @@ public class MarketingStrategyService {
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {});
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> weeklyPlansList = (List<Map<String, Object>>) jsonMap.get("weeklyPlans");
|
||||
|
||||
@@ -258,17 +268,24 @@ public class MarketingStrategyService {
|
||||
for (Map<String, Object> planMap : weeklyPlansList) {
|
||||
MarketingStrategy.WeeklyPlan plan = new MarketingStrategy.WeeklyPlan();
|
||||
plan.setWeekNumber(((Number) planMap.get("weekNumber")).intValue());
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> themes = (List<String>) planMap.get("mainThemes");
|
||||
plan.setMainThemes(themes != null ? themes : new ArrayList<>());
|
||||
|
||||
|
||||
plan.setContentRecommendations((String) planMap.get("contentRecommendations"));
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> platforms = (List<String>) planMap.get("priorityPlatforms");
|
||||
// Filter platforms to only include those from the original request
|
||||
if (platforms != null && priorityPlatforms != null && !priorityPlatforms.isEmpty()) {
|
||||
platforms = platforms.stream()
|
||||
.filter(p -> priorityPlatforms.stream()
|
||||
.anyMatch(pp -> pp.equalsIgnoreCase(p)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
plan.setPriorityPlatforms(platforms != null ? platforms : new ArrayList<>());
|
||||
|
||||
|
||||
plans.add(plan);
|
||||
}
|
||||
|
||||
@@ -320,13 +337,14 @@ public class MarketingStrategyService {
|
||||
LocalDateTime startDate = LocalDateTime.now().plusDays(1); // Start from tomorrow
|
||||
|
||||
String prompt = String.format(
|
||||
"На основе следующего маркетингового анализа и недельного плана создай детальный календарь постов на %d недель.\n\n" +
|
||||
"На основе следующего маркетингового анализа и недельного плана создай детальный календарь постов на %d недель.\n\n"
|
||||
+
|
||||
"Требования:\n" +
|
||||
"1. Создай конкретные посты для публикации\n" +
|
||||
"2. Для каждого поста укажи:\n" +
|
||||
" - Дату публикации (в формате YYYY-MM-DD)\n" +
|
||||
" - Время публикации (в формате HH:mm, например 10:00, 14:00, 18:00)\n" +
|
||||
" - Платформу (одну из: %s)\n" +
|
||||
" - Платформу (СТРОГО ОДНУ ИЗ: %s)\n" +
|
||||
" - Тип контента (пост, сторис, видео, баннер)\n" +
|
||||
" - Тему поста\n" +
|
||||
" - Полный текст поста (готовый к публикации, 100-300 символов)\n" +
|
||||
@@ -334,7 +352,11 @@ public class MarketingStrategyService {
|
||||
"3. Распредели посты равномерно по неделям\n" +
|
||||
"4. Рекомендуемое количество постов: 3-5 постов в неделю\n" +
|
||||
"5. Чередуй платформы и типы контента\n" +
|
||||
"6. Ответ должен быть на русском языке\n\n" +
|
||||
"6. ВАЖНО: Используй ТОЛЬКО указанные платформы. Если указан Facebook, используй ТОЛЬКО Facebook (НЕ добавляй Instagram).\n"
|
||||
+
|
||||
" Если указан Instagram, используй ТОЛЬКО Instagram (НЕ добавляй Facebook).\n" +
|
||||
" Каждая платформа независима - не предполагай связи между платформами.\n" +
|
||||
"7. Ответ должен быть на русском языке\n\n" +
|
||||
"Верни ответ в формате JSON со следующей структурой:\n" +
|
||||
"{\n" +
|
||||
" \"postCalendar\": [\n" +
|
||||
@@ -352,7 +374,8 @@ public class MarketingStrategyService {
|
||||
"Начальная дата: %s\n\n" +
|
||||
"Недельный план:\n%s\n\n" +
|
||||
"Маркетинговый анализ:\n%s",
|
||||
durationWeeks, platformsStr, startDate.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), weeklyPlansSummary, context);
|
||||
durationWeeks, platformsStr, startDate.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
weeklyPlansSummary, context);
|
||||
|
||||
String response = openAIAnalyticsService.generateWithInstruction(context, prompt, "ru");
|
||||
if (response == null || response.trim().isEmpty()) {
|
||||
@@ -368,7 +391,8 @@ public class MarketingStrategyService {
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {});
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> postCalendarList = (List<Map<String, Object>>) jsonMap.get("postCalendar");
|
||||
|
||||
@@ -380,7 +404,7 @@ public class MarketingStrategyService {
|
||||
List<MarketingStrategy.PostCalendarItem> calendar = new ArrayList<>();
|
||||
for (Map<String, Object> postMap : postCalendarList) {
|
||||
MarketingStrategy.PostCalendarItem item = new MarketingStrategy.PostCalendarItem();
|
||||
|
||||
|
||||
// Parse date
|
||||
String dateStr = (String) postMap.get("publishDate");
|
||||
if (dateStr != null) {
|
||||
@@ -394,21 +418,38 @@ public class MarketingStrategyService {
|
||||
} else {
|
||||
item.setPublishDate(startDate.plusDays(calendar.size()));
|
||||
}
|
||||
|
||||
item.setPlatform((String) postMap.get("platform"));
|
||||
|
||||
String platformRaw = (String) postMap.get("platform");
|
||||
// Validate platform - only use if it's in the requested platforms
|
||||
final String platform;
|
||||
if (platformRaw != null && priorityPlatforms != null && !priorityPlatforms.isEmpty()) {
|
||||
boolean isValidPlatform = priorityPlatforms.stream()
|
||||
.anyMatch(pp -> pp.equalsIgnoreCase(platformRaw));
|
||||
if (!isValidPlatform) {
|
||||
// If platform is not in the list, use the first valid platform instead
|
||||
logger.warn("Platform '{}' not in requested platforms {}, using '{}' instead",
|
||||
platformRaw, priorityPlatforms, priorityPlatforms.get(0));
|
||||
platform = priorityPlatforms.get(0);
|
||||
} else {
|
||||
platform = platformRaw;
|
||||
}
|
||||
} else {
|
||||
platform = platformRaw;
|
||||
}
|
||||
item.setPlatform(platform);
|
||||
item.setContentType((String) postMap.get("contentType"));
|
||||
item.setTheme((String) postMap.get("theme"));
|
||||
item.setPostText((String) postMap.get("postText"));
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> hashtags = (List<String>) postMap.get("hashtags");
|
||||
item.setHashtags(hashtags != null ? hashtags : new ArrayList<>());
|
||||
|
||||
|
||||
item.setPublishTime((String) postMap.get("publishTime"));
|
||||
|
||||
|
||||
// Generate image for the post
|
||||
generateAndSaveImageForPost(item, businessContext);
|
||||
|
||||
|
||||
calendar.add(item);
|
||||
}
|
||||
|
||||
@@ -455,7 +496,8 @@ public class MarketingStrategyService {
|
||||
MarketingStrategy.WeeklyPlan plan = new MarketingStrategy.WeeklyPlan();
|
||||
plan.setWeekNumber(i);
|
||||
plan.setMainThemes(Arrays.asList("Презентация продукта", "Преимущества", "Отзывы клиентов"));
|
||||
plan.setContentRecommendations("Создавайте контент, который демонстрирует ценность продукта для целевой аудитории.");
|
||||
plan.setContentRecommendations(
|
||||
"Создавайте контент, который демонстрирует ценность продукта для целевой аудитории.");
|
||||
plan.setPriorityPlatforms(platforms);
|
||||
plans.add(plan);
|
||||
}
|
||||
@@ -467,19 +509,19 @@ public class MarketingStrategyService {
|
||||
try {
|
||||
// Create prompt for image generation
|
||||
String imagePrompt = buildImagePrompt(item, businessContext);
|
||||
|
||||
|
||||
// Generate image
|
||||
byte[] imageBytes = imageGenerationService.generateImage(imagePrompt);
|
||||
|
||||
|
||||
if (imageBytes != null && imageBytes.length > 0) {
|
||||
// Save image to MinIO
|
||||
String filename = "post_image_" + System.currentTimeMillis() + "_" + item.hashCode() + ".png";
|
||||
minIOService.uploadFile(filename, imageBytes, MediaType.IMAGE_PNG.toString());
|
||||
|
||||
|
||||
// Save filename and URL in item
|
||||
item.setImageFilename(filename);
|
||||
item.setImageUrl(filename); // In MinIO, filename is also the URL/path
|
||||
|
||||
|
||||
logger.info("Successfully generated and saved image for post: {}", filename);
|
||||
} else {
|
||||
logger.warn("Failed to generate image for post with theme: {}", item.getTheme());
|
||||
@@ -493,26 +535,26 @@ public class MarketingStrategyService {
|
||||
private String buildImagePrompt(MarketingStrategy.PostCalendarItem item, String businessContext) {
|
||||
StringBuilder prompt = new StringBuilder();
|
||||
prompt.append("Создай привлекательное маркетинговое изображение для поста в социальных сетях. ");
|
||||
|
||||
|
||||
if (businessContext != null && !businessContext.isEmpty()) {
|
||||
prompt.append(businessContext).append(" ");
|
||||
}
|
||||
|
||||
|
||||
if (item.getTheme() != null && !item.getTheme().isEmpty()) {
|
||||
prompt.append("Тема поста: ").append(item.getTheme()).append(". ");
|
||||
}
|
||||
|
||||
|
||||
if (item.getPostText() != null && !item.getPostText().isEmpty()) {
|
||||
// Use first 100 characters of post text for context
|
||||
String textPreview = item.getPostText().length() > 100
|
||||
? item.getPostText().substring(0, 100) + "..."
|
||||
String textPreview = item.getPostText().length() > 100
|
||||
? item.getPostText().substring(0, 100) + "..."
|
||||
: item.getPostText();
|
||||
prompt.append("Текст поста: ").append(textPreview).append(". ");
|
||||
}
|
||||
|
||||
|
||||
prompt.append("Стиль: современный, профессиональный, привлекающий внимание, подходящий для социальных сетей. ");
|
||||
prompt.append("Изображение должно быть ярким, но не перегруженным, с акцентом на главную идею поста.");
|
||||
|
||||
|
||||
return prompt.toString();
|
||||
}
|
||||
|
||||
@@ -560,7 +602,7 @@ public class MarketingStrategyService {
|
||||
if (strategy.getWeeklyPlans() != null && strategy.getPostCalendar() != null
|
||||
&& "completed".equals(strategy.getStatus())) {
|
||||
MarketingStrategyResponse.StrategyContent strategyContent = new MarketingStrategyResponse.StrategyContent();
|
||||
|
||||
|
||||
// Convert WeeklyPlans
|
||||
List<MarketingStrategyResponse.WeeklyPlan> weeklyPlans = new ArrayList<>();
|
||||
for (MarketingStrategy.WeeklyPlan plan : strategy.getWeeklyPlans()) {
|
||||
@@ -613,4 +655,3 @@ public class MarketingStrategyService {
|
||||
return repository.findById(strategyId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user