fix
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package kz.konturai.parser.model;
|
||||
|
||||
import kz.konturai.parser.dto.MarketingAnalysisResponseV2;
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
@@ -9,6 +10,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Document(collection = "marketing_analysis_v2")
|
||||
public class MarketingAnalysisV2Document {
|
||||
|
||||
@@ -62,124 +64,5 @@ public class MarketingAnalysisV2Document {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getBusinessNiche() {
|
||||
return businessNiche;
|
||||
}
|
||||
|
||||
public void setBusinessNiche(String businessNiche) {
|
||||
this.businessNiche = businessNiche;
|
||||
}
|
||||
|
||||
public String getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(String product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public Map<String, Object> getTargetAudience() {
|
||||
return targetAudience;
|
||||
}
|
||||
|
||||
public void setTargetAudience(Map<String, Object> targetAudience) {
|
||||
this.targetAudience = targetAudience;
|
||||
}
|
||||
|
||||
public List<String> getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public void setRegion(List<String> region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public String getGoal() {
|
||||
return goal;
|
||||
}
|
||||
|
||||
public void setGoal(String goal) {
|
||||
this.goal = goal;
|
||||
}
|
||||
|
||||
public String getDetailLevel() {
|
||||
return detailLevel;
|
||||
}
|
||||
|
||||
public void setDetailLevel(String detailLevel) {
|
||||
this.detailLevel = detailLevel;
|
||||
}
|
||||
|
||||
public String getStrongSide() {
|
||||
return strongSide;
|
||||
}
|
||||
|
||||
public void setStrongSide(String strongSide) {
|
||||
this.strongSide = strongSide;
|
||||
}
|
||||
|
||||
public String getWeakSide() {
|
||||
return weakSide;
|
||||
}
|
||||
|
||||
public void setWeakSide(String weakSide) {
|
||||
this.weakSide = weakSide;
|
||||
}
|
||||
|
||||
public List<String> getAnalysisType() {
|
||||
return analysisType;
|
||||
}
|
||||
|
||||
public void setAnalysisType(List<String> analysisType) {
|
||||
this.analysisType = analysisType;
|
||||
}
|
||||
|
||||
public MarketingAnalysisResponseV2 getAnalysisData() {
|
||||
return analysisData;
|
||||
}
|
||||
|
||||
public void setAnalysisData(MarketingAnalysisResponseV2 analysisData) {
|
||||
this.analysisData = analysisData;
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public String getAnalysisId() {
|
||||
return analysisId;
|
||||
}
|
||||
|
||||
public void setAnalysisId(String analysisId) {
|
||||
this.analysisId = analysisId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@ import kz.konturai.parser.dto.MarketingStrategyRequest;
|
||||
import kz.konturai.parser.dto.MarketingStrategyResponse;
|
||||
import kz.konturai.parser.dto.StatusHistoryEntry;
|
||||
import kz.konturai.parser.model.MarketingAnalysis;
|
||||
import kz.konturai.parser.model.MarketingAnalysisV2Document;
|
||||
import kz.konturai.parser.model.MarketingStrategy;
|
||||
import kz.konturai.parser.model.PostingTask;
|
||||
import kz.konturai.parser.repository.MarketingAnalysisRepository;
|
||||
import kz.konturai.parser.repository.MarketingAnalysisV2Repository;
|
||||
import kz.konturai.parser.repository.MarketingStrategyRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -24,6 +27,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MarketingStrategyService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MarketingStrategyService.class);
|
||||
@@ -31,6 +35,7 @@ public class MarketingStrategyService {
|
||||
private final MarketingStrategyRepository repository;
|
||||
private final MarketingAnalysisService marketingAnalysisService;
|
||||
private final MarketingAnalysisRepository analysisRepository;
|
||||
private final MarketingAnalysisV2Repository v2Repository;
|
||||
private final OpenAIAnalyticsService openAIAnalyticsService;
|
||||
private final ImageGenerationService imageGenerationService;
|
||||
private final MinIOService minIOService;
|
||||
@@ -40,41 +45,31 @@ public class MarketingStrategyService {
|
||||
@Value("${image.generation.delayBetweenRequestsMs:3000}")
|
||||
private long delayBetweenRequestsMs;
|
||||
|
||||
public MarketingStrategyService(
|
||||
MarketingStrategyRepository repository,
|
||||
MarketingAnalysisService marketingAnalysisService,
|
||||
MarketingAnalysisRepository analysisRepository,
|
||||
OpenAIAnalyticsService openAIAnalyticsService,
|
||||
ImageGenerationService imageGenerationService,
|
||||
MinIOService minIOService,
|
||||
PostingTaskService postingTaskService) {
|
||||
this.repository = repository;
|
||||
this.marketingAnalysisService = marketingAnalysisService;
|
||||
this.analysisRepository = analysisRepository;
|
||||
this.openAIAnalyticsService = openAIAnalyticsService;
|
||||
this.imageGenerationService = imageGenerationService;
|
||||
this.minIOService = minIOService;
|
||||
this.postingTaskService = postingTaskService;
|
||||
}
|
||||
|
||||
public MarketingStrategy generateStrategy(String analysisId, MarketingStrategyRequest request, String userId) {
|
||||
// Check if analysis exists and is completed
|
||||
MarketingAnalysisResult analysisResult = marketingAnalysisService.getAnalysisResult(analysisId);
|
||||
|
||||
if (analysisResult == null) {
|
||||
Optional<MarketingAnalysisV2Document> v2Opt = v2Repository.findById(analysisId);
|
||||
if (v2Opt.isPresent()) {
|
||||
analysisResult = convertV2ToResult(v2Opt.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (analysisResult == null) {
|
||||
throw new IllegalArgumentException("Анализ с ID " + analysisId + " не найден");
|
||||
}
|
||||
|
||||
if (!"completed".equals(analysisResult.getStatus())) {
|
||||
throw new IllegalStateException("Анализ еще не завершен. Статус: " + analysisResult.getStatus());
|
||||
}
|
||||
|
||||
// Check if strategy already exists
|
||||
Optional<MarketingStrategy> existingStrategy = repository.findByAnalysisId(analysisId);
|
||||
if (existingStrategy.isPresent()) {
|
||||
logger.info("Стратегия для анализа {} уже существует: {}", analysisId, existingStrategy.get().getId());
|
||||
return existingStrategy.get();
|
||||
}
|
||||
|
||||
// Create new strategy
|
||||
MarketingStrategy strategy = new MarketingStrategy(analysisId);
|
||||
strategy.setUserId(userId);
|
||||
strategy.setDurationWeeks(request.getDurationWeeks() != null ? request.getDurationWeeks() : 4);
|
||||
@@ -85,12 +80,43 @@ public class MarketingStrategyService {
|
||||
|
||||
logger.info("Marketing strategy created with ID: {} for user: {}", strategy.getId(), userId);
|
||||
|
||||
// Start async processing
|
||||
processStrategyGeneration(strategy.getId(), analysisId, analysisResult);
|
||||
|
||||
return strategy;
|
||||
}
|
||||
|
||||
private MarketingAnalysisResult convertV2ToResult(MarketingAnalysisV2Document v2Doc) {
|
||||
MarketingAnalysisResult result = new MarketingAnalysisResult();
|
||||
result.setAnalysisId(v2Doc.getId());
|
||||
result.setStatus("completed");
|
||||
|
||||
MarketingAnalysisResult.MarketingReport report = new MarketingAnalysisResult.MarketingReport();
|
||||
|
||||
StringBuilder fullAnalysisBuilder = new StringBuilder();
|
||||
fullAnalysisBuilder.append("# Маркетинговый анализ (V2)\n\n");
|
||||
|
||||
if (v2Doc.getProduct() != null) fullAnalysisBuilder.append("**Продукт:** ").append(v2Doc.getProduct()).append("\n");
|
||||
if (v2Doc.getBusinessNiche() != null) fullAnalysisBuilder.append("**Ниша:** ").append(v2Doc.getBusinessNiche()).append("\n");
|
||||
if (v2Doc.getGoal() != null) fullAnalysisBuilder.append("**Цель:** ").append(v2Doc.getGoal()).append("\n\n");
|
||||
|
||||
if (v2Doc.getAnalysisData() != null) {
|
||||
try {
|
||||
String jsonData = objectMapper.writeValueAsString(v2Doc.getAnalysisData());
|
||||
fullAnalysisBuilder.append("**Детальные данные анализа:**\n").append(jsonData);
|
||||
} catch (Exception e) {
|
||||
fullAnalysisBuilder.append("Ошибка обработки данных анализа V2.");
|
||||
}
|
||||
} else {
|
||||
fullAnalysisBuilder.append("Детальный анализ недоступен.");
|
||||
}
|
||||
|
||||
report.setFullAnalysis(fullAnalysisBuilder.toString());
|
||||
report.setSummary("Анализ V2 для продукта: " + v2Doc.getProduct());
|
||||
|
||||
result.setReport(report);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addStatusHistoryEntry(MarketingStrategy strategy, String status, String message) {
|
||||
if (strategy.getStatusHistory() == null) {
|
||||
strategy.setStatusHistory(new ArrayList<>());
|
||||
@@ -101,7 +127,7 @@ public class MarketingStrategyService {
|
||||
|
||||
@Async("reportGenerationExecutor")
|
||||
public void processStrategyGeneration(String strategyId, String analysisId,
|
||||
MarketingAnalysisResult analysisResult) {
|
||||
MarketingAnalysisResult analysisResult) {
|
||||
try {
|
||||
Optional<MarketingStrategy> optStrategy = repository.findById(strategyId);
|
||||
if (optStrategy.isEmpty()) {
|
||||
@@ -116,28 +142,22 @@ public class MarketingStrategyService {
|
||||
|
||||
logger.info("Starting marketing strategy generation for ID: {}", strategyId);
|
||||
|
||||
// Build context from analysis
|
||||
String context = buildContextFromAnalysis(analysisResult);
|
||||
|
||||
// Get business context for image generation
|
||||
String businessContext = getBusinessContextFromAnalysis(analysisId);
|
||||
|
||||
// Generate weekly plans
|
||||
List<MarketingStrategy.WeeklyPlan> weeklyPlans = generateWeeklyPlans(
|
||||
context, strategy.getDurationWeeks(), strategy.getPriorityPlatforms());
|
||||
|
||||
// Generate post calendar
|
||||
List<MarketingStrategy.PostCalendarItem> postCalendar = generatePostCalendar(
|
||||
context, strategy.getDurationWeeks(), strategy.getPriorityPlatforms(), weeklyPlans,
|
||||
businessContext);
|
||||
|
||||
// Update strategy
|
||||
strategy.setStatus("completed");
|
||||
strategy.setCompletedAt(LocalDateTime.now());
|
||||
strategy.setWeeklyPlans(weeklyPlans);
|
||||
strategy.setPostCalendar(postCalendar);
|
||||
|
||||
// Store full strategy data as JSON
|
||||
Map<String, Object> strategyData = new HashMap<>();
|
||||
strategyData.put("weeklyPlans", weeklyPlans);
|
||||
strategyData.put("postCalendar", postCalendar);
|
||||
@@ -174,10 +194,8 @@ public class MarketingStrategyService {
|
||||
context.append("Резюме анализа: ").append(report.getSummary()).append("\n\n");
|
||||
}
|
||||
|
||||
// Since the system migrated to fullAnalysis, use it as the primary context.
|
||||
if (report.getFullAnalysis() != null && !report.getFullAnalysis().isBlank()) {
|
||||
String full = report.getFullAnalysis().trim();
|
||||
// Guard against excessively large prompts
|
||||
int maxChars = 12000;
|
||||
if (full.length() > maxChars) {
|
||||
full = full.substring(0, maxChars) + "\n\n(…обрезано для лимита контекста…)";
|
||||
@@ -232,14 +250,12 @@ public class MarketingStrategyService {
|
||||
return generateDefaultWeeklyPlans(durationWeeks, priorityPlatforms);
|
||||
}
|
||||
|
||||
// Extract JSON from response
|
||||
String jsonStr = extractJsonFromResponse(response);
|
||||
if (jsonStr == null) {
|
||||
logger.warn("Could not extract JSON from weekly plans response, using default");
|
||||
return generateDefaultWeeklyPlans(durationWeeks, priorityPlatforms);
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -263,7 +279,6 @@ public class MarketingStrategyService {
|
||||
|
||||
@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()
|
||||
@@ -287,39 +302,68 @@ public class MarketingStrategyService {
|
||||
try {
|
||||
Optional<MarketingAnalysis> optAnalysis = analysisRepository.findById(analysisId);
|
||||
if (optAnalysis.isPresent()) {
|
||||
MarketingAnalysis analysis = optAnalysis.get();
|
||||
StringBuilder businessContext = new StringBuilder();
|
||||
|
||||
if (analysis.getProduct() != null && !analysis.getProduct().isEmpty()) {
|
||||
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 extractContextFromV1(optAnalysis.get());
|
||||
}
|
||||
|
||||
Optional<MarketingAnalysisV2Document> optV2 = v2Repository.findById(analysisId);
|
||||
if (optV2.isPresent()) {
|
||||
return extractContextFromV2(optV2.get());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get business context from analysis: {}", e.getMessage());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String extractContextFromV1(MarketingAnalysis analysis) {
|
||||
StringBuilder businessContext = new StringBuilder();
|
||||
if (analysis.getProduct() != null && !analysis.getProduct().isEmpty()) {
|
||||
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();
|
||||
appendTargetAudience(businessContext, ta);
|
||||
}
|
||||
return businessContext.toString();
|
||||
}
|
||||
|
||||
private String extractContextFromV2(MarketingAnalysisV2Document v2) {
|
||||
StringBuilder businessContext = new StringBuilder();
|
||||
if (v2.getProduct() != null && !v2.getProduct().isEmpty()) {
|
||||
businessContext.append("Главный объект изображения (продукт): ").append(v2.getProduct()).append(". ");
|
||||
}
|
||||
if (v2.getBusinessNiche() != null && !v2.getBusinessNiche().isEmpty()) {
|
||||
businessContext.append("Ниша: ").append(v2.getBusinessNiche()).append(". ");
|
||||
}
|
||||
if (v2.getTargetAudience() != null) {
|
||||
if (v2.getTargetAudience() instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> ta = (Map<String, Object>) v2.getTargetAudience();
|
||||
appendTargetAudience(businessContext, ta);
|
||||
} else if (v2.getTargetAudience() != null) {
|
||||
businessContext.append("Целевая аудитория: ").append(v2.getTargetAudience().toString()).append(". ");
|
||||
}
|
||||
}
|
||||
return businessContext.toString();
|
||||
}
|
||||
|
||||
private void appendTargetAudience(StringBuilder sb, Map<String, Object> ta) {
|
||||
if (ta.containsKey("ageRanges") || ta.containsKey("types")) {
|
||||
sb.append("Целевая аудитория (люди на фото): ");
|
||||
if (ta.containsKey("types")) {
|
||||
sb.append(ta.get("types")).append(" ");
|
||||
}
|
||||
if (ta.containsKey("ageRanges")) {
|
||||
sb.append("возраст ").append(ta.get("ageRanges"));
|
||||
}
|
||||
sb.append(". ");
|
||||
}
|
||||
}
|
||||
|
||||
private List<MarketingStrategy.PostCalendarItem> generatePostCalendar(
|
||||
String context, Integer durationWeeks, List<String> priorityPlatforms,
|
||||
List<MarketingStrategy.WeeklyPlan> weeklyPlans, String businessContext) {
|
||||
@@ -328,7 +372,6 @@ public class MarketingStrategyService {
|
||||
? String.join(", ", priorityPlatforms)
|
||||
: "Instagram, Facebook, LinkedIn, Telegram, TikTok, YouTube";
|
||||
|
||||
// Build weekly plans summary for context
|
||||
String weeklyPlansSummary = "";
|
||||
if (weeklyPlans != null && !weeklyPlans.isEmpty()) {
|
||||
weeklyPlansSummary = weeklyPlans.stream()
|
||||
@@ -337,7 +380,7 @@ public class MarketingStrategyService {
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
LocalDateTime startDate = LocalDateTime.now().plusDays(1); // Start from tomorrow
|
||||
LocalDateTime startDate = LocalDateTime.now().plusDays(1);
|
||||
|
||||
String prompt = String.format(
|
||||
"На основе следующего маркетингового анализа и недельного плана создай детальный календарь постов на %d недель.\n\n"
|
||||
@@ -386,14 +429,12 @@ public class MarketingStrategyService {
|
||||
return generateDefaultPostCalendar(durationWeeks, priorityPlatforms, startDate);
|
||||
}
|
||||
|
||||
// Extract JSON from response
|
||||
String jsonStr = extractJsonFromResponse(response);
|
||||
if (jsonStr == null) {
|
||||
logger.warn("Could not extract JSON from post calendar response, using default");
|
||||
return generateDefaultPostCalendar(durationWeeks, priorityPlatforms, startDate);
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
Map<String, Object> jsonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -408,7 +449,6 @@ public class MarketingStrategyService {
|
||||
for (Map<String, Object> postMap : postCalendarList) {
|
||||
MarketingStrategy.PostCalendarItem item = new MarketingStrategy.PostCalendarItem();
|
||||
|
||||
// Parse date
|
||||
String dateStr = (String) postMap.get("publishDate");
|
||||
if (dateStr != null) {
|
||||
try {
|
||||
@@ -423,13 +463,11 @@ public class MarketingStrategyService {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -450,11 +488,8 @@ public class MarketingStrategyService {
|
||||
|
||||
item.setPublishTime((String) postMap.get("publishTime"));
|
||||
|
||||
// Generate image for the post
|
||||
generateAndSaveImageForPost(item, businessContext);
|
||||
|
||||
// Add delay between image generation requests to avoid rate limiting
|
||||
// This helps prevent 429 errors from Gemini API
|
||||
if (delayBetweenRequestsMs > 0) {
|
||||
try {
|
||||
Thread.sleep(delayBetweenRequestsMs);
|
||||
@@ -480,7 +515,6 @@ public class MarketingStrategyService {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to find JSON object in response
|
||||
int startIdx = response.indexOf("{");
|
||||
int endIdx = response.lastIndexOf("}");
|
||||
|
||||
@@ -488,7 +522,6 @@ public class MarketingStrategyService {
|
||||
return response.substring(startIdx, endIdx + 1);
|
||||
}
|
||||
|
||||
// Try to find JSON array
|
||||
startIdx = response.indexOf("[");
|
||||
endIdx = response.lastIndexOf("]");
|
||||
|
||||
@@ -531,9 +564,8 @@ public class MarketingStrategyService {
|
||||
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
|
||||
item.setImageUrl(filename);
|
||||
|
||||
logger.info("Successfully generated and saved image for post: {}", filename);
|
||||
} else {
|
||||
@@ -541,7 +573,6 @@ public class MarketingStrategyService {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating image for post: {}", e.getMessage(), e);
|
||||
// Continue without image - post will be published without image
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,12 +593,10 @@ public class MarketingStrategyService {
|
||||
|
||||
prompt.append("Фотореалистичное изображение. ");
|
||||
|
||||
// Добавляем контекст продукта (это самое важное!)
|
||||
if (businessContext != null && !businessContext.isEmpty()) {
|
||||
prompt.append(businessContext).append(" ");
|
||||
}
|
||||
|
||||
// 3. Контекст поста
|
||||
if (item.getTheme() != null && !item.getTheme().isEmpty()) {
|
||||
prompt.append("Сюжет изображения: ").append(item.getTheme()).append(". ");
|
||||
}
|
||||
@@ -590,10 +619,10 @@ public class MarketingStrategyService {
|
||||
List<String> contentTypes = Arrays.asList("пост", "сторис", "видео");
|
||||
List<String> times = Arrays.asList("10:00", "14:00", "18:00");
|
||||
|
||||
int postCount = durationWeeks * 3; // 3 posts per week
|
||||
int postCount = durationWeeks * 3;
|
||||
for (int i = 0; i < postCount; i++) {
|
||||
MarketingStrategy.PostCalendarItem item = new MarketingStrategy.PostCalendarItem();
|
||||
item.setPublishDate(startDate.plusDays(i * 2)); // Every 2 days
|
||||
item.setPublishDate(startDate.plusDays(i * 2));
|
||||
item.setPlatform(platforms.get(i % platforms.size()));
|
||||
item.setContentType(contentTypes.get(i % contentTypes.size()));
|
||||
item.setTheme("Тема поста " + (i + 1));
|
||||
@@ -626,7 +655,6 @@ public class MarketingStrategyService {
|
||||
&& "completed".equals(strategy.getStatus())) {
|
||||
MarketingStrategyResponse.StrategyContent strategyContent = new MarketingStrategyResponse.StrategyContent();
|
||||
|
||||
// Convert WeeklyPlans
|
||||
List<MarketingStrategyResponse.WeeklyPlan> weeklyPlans = new ArrayList<>();
|
||||
for (MarketingStrategy.WeeklyPlan plan : strategy.getWeeklyPlans()) {
|
||||
MarketingStrategyResponse.WeeklyPlan dtoPlan = new MarketingStrategyResponse.WeeklyPlan();
|
||||
@@ -638,9 +666,7 @@ public class MarketingStrategyService {
|
||||
}
|
||||
strategyContent.setWeeklyPlans(weeklyPlans);
|
||||
|
||||
// Convert PostCalendarItems and add taskId if tasks exist
|
||||
List<MarketingStrategyResponse.PostCalendarItem> postCalendar = new ArrayList<>();
|
||||
// Получаем все задачи для этой стратегии
|
||||
List<PostingTask> tasks = postingTaskService.getStrategyTasks(strategyId);
|
||||
|
||||
for (MarketingStrategy.PostCalendarItem item : strategy.getPostCalendar()) {
|
||||
@@ -655,7 +681,6 @@ public class MarketingStrategyService {
|
||||
dtoItem.setImageUrl(item.getImageUrl());
|
||||
dtoItem.setImageFilename(item.getImageFilename());
|
||||
|
||||
// Находим соответствующую задачу по дате публикации, платформе и тексту поста
|
||||
Optional<PostingTask> matchingTask = tasks.stream()
|
||||
.filter(task -> task.getPublishDate() != null && item.getPublishDate() != null
|
||||
&& task.getPublishDate().equals(item.getPublishDate())
|
||||
@@ -696,14 +721,6 @@ public class MarketingStrategyService {
|
||||
return repository.findById(strategyId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Регенерирует изображение для указанного поста в стратегии
|
||||
*
|
||||
* @param strategyId ID стратегии
|
||||
* @param postIndex Индекс поста в списке postCalendar (начиная с 0)
|
||||
* @return Обновленный элемент календаря постов с новым изображением, или null
|
||||
* если пост не найден
|
||||
*/
|
||||
public MarketingStrategy.PostCalendarItem regeneratePostImage(String strategyId, int postIndex) {
|
||||
Optional<MarketingStrategy> optStrategy = repository.findById(strategyId);
|
||||
if (optStrategy.isEmpty()) {
|
||||
@@ -722,20 +739,13 @@ public class MarketingStrategyService {
|
||||
|
||||
MarketingStrategy.PostCalendarItem item = postCalendar.get(postIndex);
|
||||
|
||||
// Get business context for image generation
|
||||
String businessContext = getBusinessContextFromAnalysis(strategy.getAnalysisId());
|
||||
|
||||
// Note: Old image file is not deleted (MinIO doesn't have deleteFile method)
|
||||
// New image will have a different filename, so old file will remain but won't
|
||||
// be used
|
||||
|
||||
// Generate new image
|
||||
generateAndSaveImageForPost(item, businessContext);
|
||||
|
||||
// Save updated strategy
|
||||
repository.save(strategy);
|
||||
|
||||
logger.info("Successfully regenerated image for post at index {} in strategy {}", postIndex, strategyId);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user