diff --git a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java index 9b467cb..e055ffb 100644 --- a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java +++ b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java @@ -259,7 +259,6 @@ public class MarketingAnalysisService { logger.info("Starting parallel JSON analysis generation"); // Создаем CompletableFuture для каждого типа анализа - @SuppressWarnings("unchecked") CompletableFuture> audienceFuture = (CompletableFuture>) CompletableFuture .>supplyAsync(() -> { logger.info("Starting audience analysis generation"); @@ -276,7 +275,6 @@ public class MarketingAnalysisService { return new HashMap<>(); }); - @SuppressWarnings("unchecked") CompletableFuture> competitorFuture = (CompletableFuture>) CompletableFuture .>supplyAsync(() -> { logger.info("Starting competitor analysis generation"); @@ -293,7 +291,6 @@ public class MarketingAnalysisService { return new HashMap<>(); }); - @SuppressWarnings("unchecked") CompletableFuture> seasonalityFuture = (CompletableFuture>) CompletableFuture .>supplyAsync(() -> { logger.info("Starting seasonality and market analysis generation"); @@ -310,7 +307,6 @@ public class MarketingAnalysisService { return new HashMap<>(); }); - @SuppressWarnings("unchecked") CompletableFuture> strategyFuture = (CompletableFuture>) CompletableFuture .>supplyAsync(() -> { logger.info("Starting strategy and funnel analysis generation"); @@ -1234,7 +1230,22 @@ public class MarketingAnalysisService { // Новая структура: competitorAnalysis (marketShareChart, comparisonTable, // competitorsDetails, swotCompetitors, etc.) if (fullJson.containsKey("competitorAnalysis")) { - context.put("competitorAnalysis", fullJson.get("competitorAnalysis")); + Object competitorAnalysisObj = fullJson.get("competitorAnalysis"); + context.put("competitorAnalysis", competitorAnalysisObj); + // Aliases для совместимости: плоские ключи для секции конкурентов + // (данные физически лежат в competitorAnalysis.*) + if (competitorAnalysisObj instanceof Map) { + @SuppressWarnings("unchecked") + Map competitorAnalysis = (Map) competitorAnalysisObj; + if (competitorAnalysis != null) { + if (competitorAnalysis.containsKey("marketShareChart")) { + context.put("marketShareChart", competitorAnalysis.get("marketShareChart")); + } + if (competitorAnalysis.containsKey("comparisonTable")) { + context.put("comparisonTable", competitorAnalysis.get("comparisonTable")); + } + } + } } else { // Backward compatibility (старая структура) if (fullJson.containsKey("competitors")) { @@ -1574,6 +1585,8 @@ public class MarketingAnalysisService { "Детально проанализируй аудиторию на основе audienceAnalysis (segments, ageGroups, genderDistribution):\n"); promptBuilder.append( "- Не просто опиши сегменты, а проанализируй данные графиков [[CHART_AGE_DISTRIBUTION]] и [[CHART_GENDER_DISTRIBUTION]].\n"); + promptBuilder.append( + "- Обязательно вставь тег [[CHART_AGE_DISTRIBUTION]] после анализа возраста и [[CHART_GENDER_DISTRIBUTION]] после анализа пола. Опиши данные этих графиков.\n"); promptBuilder.append( "- Объясни, почему именно эти группы принесут больше денег (через частоту, удержание, вероятность апсейла, LTV).\n"); promptBuilder.append( @@ -1647,6 +1660,10 @@ public class MarketingAnalysisService { promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n"); promptBuilder.append( "5. Это должен быть самый мощный раздел отчёта: каждое утверждение подтверждай цифрами из competitorAnalysis.marketShareChart / competitorAnalysis.comparisonTable.\n\n"); + promptBuilder.append( + "КРИТИЧНО (ОБЯЗАТЕЛЬНЫЕ ТЕГИ): Ты ОБЯЗАН вставить тег [[CHART_MARKET_SHARE]] в начале раздела и [[TABLE_COMPARISON]] в середине. Без этих тегов отчет будет неполным.\n"); + promptBuilder.append( + "КРИТИЧНО (ТАБЛИЦА): Опиши каждую строку сравнительной таблицы (каждый feature) и сделай практический вывод.\n\n"); promptBuilder.append("6. Сделай этот раздел самым длинным во всём отчёте.\n"); promptBuilder.append( "7. Проведи детальный баттл: Наш бренд vs Конкурент А vs Конкурент B. Используй данные из [[TABLE_COMPARISON]].\n"); @@ -1667,13 +1684,13 @@ public class MarketingAnalysisService { promptBuilder.append("- Рекомендации по дифференциации и конкурентным преимуществам\n\n"); promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА И ТАБЛИЦЫ:\n"); promptBuilder.append( - "1. После анализа долей рынка вставь плейсхолдер [[CHART_MARKET_SHARE]] на отдельной строке\n"); + "1. В НАЧАЛЕ раздела (сразу после заголовка V. Анализ конкурентов) вставь плейсхолдер [[CHART_MARKET_SHARE]] на отдельной строке\n"); promptBuilder.append( " - ПЕРЕД графиком: вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); promptBuilder.append( " - ПОСЛЕ графика: интерпретация (2-3 предложения), начинающаяся с: \"Из этих показателей следует, что...\"\n"); promptBuilder.append( - "2. Затем вставь плейсхолдер [[TABLE_COMPARISON]] на отдельной строке (это сравнительная таблица)\n"); + "2. В СЕРЕДИНЕ раздела вставь плейсхолдер [[TABLE_COMPARISON]] на отдельной строке (это сравнительная таблица)\n"); promptBuilder.append( " - ПЕРЕД таблицей: короткий ввод (1-2 предложения), что именно сравниваем\n"); promptBuilder.append( @@ -3173,6 +3190,12 @@ public class MarketingAnalysisService { placeholderMap.put("[[CHART_SEASONALITY]]", new ChartMapping("seasonality", "seasonality")); placeholderMap.put("[[CHART_AUDIENCE]]", new ChartMapping("audienceSegmentation", "audienceSegmentation")); placeholderMap.put("[[CHART_COMPETITORS]]", new ChartMapping("competitors", "competitors")); + // CRITICAL mapping (front-end expects exactly these keys in ```json: + // blocks): + // [[CHART_MARKET_SHARE]] -> marketShareChart + // [[TABLE_COMPARISON]] -> comparisonTable + // [[CHART_AGE_DISTRIBUTION]] -> audienceAge + // [[CHART_GENDER_DISTRIBUTION]] -> audienceGender placeholderMap.put("[[CHART_MARKET_SHARE]]", new ChartMapping("marketShareChart", "marketShareChart")); placeholderMap.put("[[TABLE_COMPARISON]]", new ChartMapping("comparisonTable", "comparisonTable")); placeholderMap.put("[[CHART_AGE_DISTRIBUTION]]", new ChartMapping("audienceAge", "audienceAge"));