This commit is contained in:
root
2025-12-18 20:11:36 +05:00
parent 501a651ced
commit 332cd7c7f2
@@ -2506,10 +2506,11 @@ public class MarketingAnalysisService {
report.put("detailLevel", detailLevelName); report.put("detailLevel", detailLevelName);
report.put("fullAnalysis", report.put("fullAnalysis",
processedTextReport != null ? processedTextReport : "Анализ не удалось сгенерировать."); processedTextReport != null ? processedTextReport : "Анализ не удалось сгенерировать.");
report.put("summary",
processedTextReport != null ? processedTextReport : "Анализ не удалось сгенерировать."); // Keep for // Извлекаем только первую секцию (I. Краткое резюме) для поля summary
// backward // чтобы избежать дублирования полного текста отчета
// compatibility String shortSummary = extractSummarySection(processedTextReport);
report.put("summary", shortSummary != null ? shortSummary : "Анализ не удалось сгенерировать.");
// Извлекаем данные из analysisJson вместо повторных вызовов AI // Извлекаем данные из analysisJson вместо повторных вызовов AI
logger.info("generateMarketingReport: Extracting targetAudience from analysisJson"); logger.info("generateMarketingReport: Extracting targetAudience from analysisJson");
@@ -2944,6 +2945,59 @@ public class MarketingAnalysisService {
return strategy; return strategy;
} }
/**
* Извлекает только первую секцию "I. Краткое резюме" из полного текстового
* отчета.
* Используется для поля summary, чтобы избежать дублирования полного текста.
*
* @param fullReport Полный текстовый отчет
* @return Текст только первой секции (краткое резюме)
*/
private String extractSummarySection(String fullReport) {
if (fullReport == null || fullReport.trim().isEmpty()) {
return null;
}
try {
// Ищем начало первой секции "I. Краткое резюме"
int startIndex = fullReport.indexOf("I. Краткое резюме");
if (startIndex == -1) {
// Если не нашли, пробуем найти просто "Краткое резюме"
startIndex = fullReport.indexOf("Краткое резюме");
}
if (startIndex == -1) {
// Если нет секции резюме, возвращаем первые 500 символов
return fullReport.length() > 500
? fullReport.substring(0, 500) + "..."
: fullReport;
}
// Ищем начало второй секции "II."
int endIndex = fullReport.indexOf("II.", startIndex + 1);
if (endIndex == -1) {
// Пробуем найти "II. " с пробелом
endIndex = fullReport.indexOf("\nII. ", startIndex + 1);
}
if (endIndex == -1) {
// Если не нашли вторую секцию, возвращаем от начала до 1000 символов
int maxLength = Math.min(startIndex + 1000, fullReport.length());
return fullReport.substring(startIndex, maxLength).trim();
}
// Извлекаем текст между I. и II.
return fullReport.substring(startIndex, endIndex).trim();
} catch (Exception e) {
logger.warn("extractSummarySection: Error extracting summary: {}", e.getMessage());
// В случае ошибки возвращаем первые 500 символов
return fullReport.length() > 500
? fullReport.substring(0, 500) + "..."
: fullReport;
}
}
private String buildMarkdownFromReport(Map<String, Object> reportData, MarketingAnalysisRequest request) { private String buildMarkdownFromReport(Map<String, Object> reportData, MarketingAnalysisRequest request) {
logger.info("buildMarkdownFromReport: Starting markdown generation for product: {}", request.getProduct()); logger.info("buildMarkdownFromReport: Starting markdown generation for product: {}", request.getProduct());
logger.debug("buildMarkdownFromReport: ReportData keys: {}", reportData != null ? reportData.keySet() : "null"); logger.debug("buildMarkdownFromReport: ReportData keys: {}", reportData != null ? reportData.keySet() : "null");
@@ -3009,109 +3063,14 @@ public class MarketingAnalysisService {
} }
markdown.append("\n"); markdown.append("\n");
// Add additional sections from JSON analysis if available // ВАЖНО: Секции "Позиционирование", "УТП", "Рекомендации по контенту" УДАЛЕНЫ,
@SuppressWarnings("unchecked") // так как они уже включены в fullAnalysis (генерируется методом
Map<String, Object> analysisJson = (Map<String, Object>) reportData.get("analysisJson"); // generatePolishedTextReport)
if (analysisJson != null && !analysisJson.isEmpty()) { // и вызывали дублирование контента в отчете
// Positioning section
@SuppressWarnings("unchecked")
Map<String, Object> positioning = (Map<String, Object>) analysisJson.get("positioning");
if (positioning != null) {
markdown.append("## Позиционирование\n\n");
if (positioning.containsKey("brandImage")) {
markdown.append("**Образ бренда:** ").append(positioning.get("brandImage")).append("\n\n");
}
if (positioning.containsKey("keyMessage")) {
markdown.append("**Ключевое сообщение:** ").append(positioning.get("keyMessage")).append("\n\n");
}
if (positioning.containsKey("toneOfVoice")) {
markdown.append("**Стиль коммуникации:** ").append(positioning.get("toneOfVoice")).append("\n\n");
}
@SuppressWarnings("unchecked")
List<String> trustFactors = (List<String>) positioning.get("trustFactors");
if (trustFactors != null && !trustFactors.isEmpty()) {
markdown.append("**Факторы доверия:**\n");
for (String factor : trustFactors) {
markdown.append("- ").append(factor).append("\n");
}
markdown.append("\n");
}
}
// Value Proposition section
@SuppressWarnings("unchecked")
Map<String, Object> valueProposition = (Map<String, Object>) analysisJson.get("valueProposition");
if (valueProposition != null) {
markdown.append("## Уникальное торговое предложение (УТП)\n\n");
@SuppressWarnings("unchecked")
List<String> utpVariants = (List<String>) valueProposition.get("utpVariants");
if (utpVariants != null && !utpVariants.isEmpty()) {
markdown.append("**Варианты УТП:**\n");
for (String utp : utpVariants) {
markdown.append("- ").append(utp).append("\n");
}
markdown.append("\n");
}
@SuppressWarnings("unchecked")
List<String> mainBenefits = (List<String>) valueProposition.get("mainBenefits");
if (mainBenefits != null && !mainBenefits.isEmpty()) {
markdown.append("**Основные преимущества:**\n");
for (String benefit : mainBenefits) {
markdown.append("- ").append(benefit).append("\n");
}
markdown.append("\n");
}
}
// Content Recommendations section
@SuppressWarnings("unchecked")
Map<String, Object> contentRecommendations = (Map<String, Object>) analysisJson
.get("contentRecommendations");
if (contentRecommendations != null) {
markdown.append("## Рекомендации по контенту\n\n");
@SuppressWarnings("unchecked")
List<String> salesContent = (List<String>) contentRecommendations.get("salesContent");
if (salesContent != null && !salesContent.isEmpty()) {
markdown.append("### Продающий контент:\n");
for (String content : salesContent) {
markdown.append("- ").append(content).append("\n");
}
markdown.append("\n");
}
@SuppressWarnings("unchecked")
List<String> expertContent = (List<String>) contentRecommendations.get("expertContent");
if (expertContent != null && !expertContent.isEmpty()) {
markdown.append("### Экспертный контент:\n");
for (String content : expertContent) {
markdown.append("- ").append(content).append("\n");
}
markdown.append("\n");
}
@SuppressWarnings("unchecked")
List<String> trustContent = (List<String>) contentRecommendations.get("trustContent");
if (trustContent != null && !trustContent.isEmpty()) {
markdown.append("### Доверительный контент:\n");
for (String content : trustContent) {
markdown.append("- ").append(content).append("\n");
}
markdown.append("\n");
}
@SuppressWarnings("unchecked")
List<String> entertainmentContent = (List<String>) contentRecommendations.get("entertainmentContent");
if (entertainmentContent != null && !entertainmentContent.isEmpty()) {
markdown.append("### Развлекательный контент:\n");
for (String content : entertainmentContent) {
markdown.append("- ").append(content).append("\n");
}
markdown.append("\n");
}
}
}
// Display full analysis - это основной блок с полным отчетом // Display full analysis - это основной блок с полным отчетом
// Секции "Целевая аудитория", "Рекомендации", "Стратегия" уже включены в // Все секции (I-XI) уже включены в fullAnalysis благодаря
// fullAnalysis // generatePolishedTextReport
// благодаря методу generatePolishedTextReport, поэтому не дублируем их
String fullAnalysis = (String) reportData.get("fullAnalysis"); String fullAnalysis = (String) reportData.get("fullAnalysis");
if (fullAnalysis != null && !fullAnalysis.trim().isEmpty()) { if (fullAnalysis != null && !fullAnalysis.trim().isEmpty()) {
// Получаем данные для графиков и заменяем плейсхолдеры // Получаем данные для графиков и заменяем плейсхолдеры
@@ -3119,20 +3078,17 @@ public class MarketingAnalysisService {
Map<String, Object> chartsData = (Map<String, Object>) reportData.get("chartsData"); Map<String, Object> chartsData = (Map<String, Object>) reportData.get("chartsData");
String processedAnalysis = replaceChartPlaceholders(fullAnalysis, chartsData); String processedAnalysis = replaceChartPlaceholders(fullAnalysis, chartsData);
markdown.append("## Полный маркетинговый анализ\n\n"); // Добавляем полный отчет без дополнительного заголовка,
// так как fullAnalysis уже начинается с "I. Краткое резюме"
markdown.append(processedAnalysis).append("\n\n"); markdown.append(processedAnalysis).append("\n\n");
} else { } else {
// Fallback to summary if fullAnalysis is not available // Fallback to summary if fullAnalysis is not available
String summary = (String) reportData.get("summary"); String summary = (String) reportData.get("summary");
if (summary != null && !summary.trim().isEmpty()) { if (summary != null && !summary.trim().isEmpty()) {
markdown.append("## Комплексный маркетинговый анализ\n\n");
markdown.append(summary).append("\n\n"); markdown.append(summary).append("\n\n");
} }
} }
// Секции targetAudience, recommendations, strategy УДАЛЕНЫ,
// так как они уже включены в fullAnalysis и вызывали дублирование
return markdown.toString(); return markdown.toString();
} }