This commit is contained in:
root
2026-01-05 00:46:19 +05:00
parent ead5e73ade
commit 9a806eadfb
@@ -668,46 +668,84 @@ public class MarketingAnalysisService {
+ " - проценты/строки формата \"76/100\", \"+27%\", \"1.34x\" => string\n"
+ " - monthly_online_index.* => number (double)\n"
+ " - funnel_metrics.leads/bookings/payments => integer\n"
+ "5) Пиши на русском языке.\n\n"
+ "Ниже пример правильной структуры (пример для ориентира; цифры должны быть основаны на evidence):\n"
+ "5) Пиши на русском языке.\n"
+ "6) НИКОГДА не копируй значения из примера. В примере намеренно стоят плейсхолдеры, "
+ "которые начинаются с 'EXAMPLE__' и числа -9999/-9999.0 — в твоем ответе их быть НЕ должно.\n\n"
+ "Ниже пример правильной структуры (пример только для формы/полей; все значения должны быть заменены на значения из evidence):\n"
+ exampleJson;
String contextJson = objectMapper.writeValueAsString(Map.of(
"request", request,
"evidence", researchPack));
// 3) Call OpenAI (sleep to reduce 429 rate-limit bursts)
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
// 3) Call OpenAI (sleep to reduce 429 rate-limit bursts) + guard against
// copying placeholders
String lastCleaned = null;
for (int attempt = 1; attempt <= 2; attempt++) {
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
String attemptInstruction = instruction;
if (attempt > 1) {
attemptInstruction = instruction
+ "\n\nКРИТИЧЕСКИ: В ПРЕДЫДУЩЕМ ОТВЕТЕ БЫЛИ ПЛЕЙСХОЛДЕРЫ."
+ " Перегенерируй ответ, полностью заменив любые строки, содержащие 'EXAMPLE__',"
+ " и любые числа -9999 / -9999.0 на реальные значения."
+ " Верни ТОЛЬКО JSON.";
}
String aiResponse = openAIAnalyticsService.generateWithInstructionWithModel(
contextJson,
attemptInstruction,
"ru",
textModelName,
systemPrompt,
15000,
180000L);
if (aiResponse == null || aiResponse.isBlank()) {
throw new IllegalStateException("OpenAI returned empty response for analysis v2");
}
// 4) Clean + validate placeholders + parse
String cleaned = cleanJsonFromMarkdown(aiResponse);
if (cleaned != null) {
cleaned = cleaned.replace("\uFEFF", "").trim();
}
lastCleaned = cleaned;
if (containsV2ExamplePlaceholders(cleaned)) {
logger.warn("generateAnalysisV2: LLM output still contains placeholders (attempt {}/2). Retrying.",
attempt);
continue;
}
return objectMapper.readValue(cleaned, MarketingAnalysisResponseV2.class);
}
String aiResponse = openAIAnalyticsService.generateWithInstructionWithModel(
contextJson,
instruction,
"ru",
textModelName,
systemPrompt,
15000,
180000L);
if (aiResponse == null || aiResponse.isBlank()) {
throw new IllegalStateException("OpenAI returned empty response for analysis v2");
}
// 4) Clean + parse
String cleaned = cleanJsonFromMarkdown(aiResponse);
if (cleaned != null) {
cleaned = cleaned.replace("\uFEFF", "").trim();
}
return objectMapper.readValue(cleaned, MarketingAnalysisResponseV2.class);
throw new IllegalStateException(
"OpenAI returned response containing placeholder tokens for analysis v2: " + lastCleaned);
} catch (Exception e) {
logger.error("generateAnalysisV2: Failed to generate/parse v2 response: {}", e.getMessage(), e);
throw new RuntimeException("Не удалось сгенерировать marketing analysis v2", e);
}
}
private boolean containsV2ExamplePlaceholders(String json) {
if (json == null || json.isBlank()) {
return true;
}
// Explicit placeholder tokens from buildAnalysisV2ExampleForPrompt()
if (json.contains("EXAMPLE__")) {
return true;
}
// Numeric placeholders from buildAnalysisV2ExampleForPrompt()
return json.contains("-9999");
}
/**
* Генерирует анализ v2 и сохраняет его в MongoDB
*
@@ -797,213 +835,217 @@ public class MarketingAnalysisService {
*/
private MarketingAnalysisResponseV2 buildAnalysisV2ExampleForPrompt() {
MarketingAnalysisResponseV2 response = new MarketingAnalysisResponseV2();
response.setReportTitle("Маркетинговый анализ для интернет-продвижения");
response.setReportTitle("EXAMPLE__REPORT_TITLE");
MarketingAnalysisResponseV2.Sections sections = new MarketingAnalysisResponseV2.Sections();
// market_overview
MarketingAnalysisResponseV2.MarketOverview marketOverview = new MarketingAnalysisResponseV2.MarketOverview();
marketOverview.setTitle("Обзор рынка");
marketOverview.setTitle("EXAMPLE__MARKET_OVERVIEW_TITLE");
MarketingAnalysisResponseV2.MarketOverviewMetrics moMetrics = new MarketingAnalysisResponseV2.MarketOverviewMetrics();
moMetrics.setOnlineDemandIndex("76/100");
moMetrics.setOnlinePotential("Высокий");
moMetrics.setDemandGrowthRateYoy("+27%");
moMetrics.setSeasonalityCoefficientSpring("1.34x");
moMetrics.setSeasonalityRange("1.29 - 1.38");
moMetrics.setOnlineDemandIndex("EXAMPLE__ONLINE_DEMAND_INDEX");
moMetrics.setOnlinePotential("EXAMPLE__ONLINE_POTENTIAL");
moMetrics.setDemandGrowthRateYoy("EXAMPLE__DEMAND_GROWTH_RATE_YOY");
moMetrics.setSeasonalityCoefficientSpring("EXAMPLE__SEASONALITY_COEFFICIENT_SPRING");
moMetrics.setSeasonalityRange("EXAMPLE__SEASONALITY_RANGE");
marketOverview.setMetrics(moMetrics);
MarketingAnalysisResponseV2.MonthlyOnlineIndex monthlyOnlineIndex = new MarketingAnalysisResponseV2.MonthlyOnlineIndex();
monthlyOnlineIndex.setMarch(1.32);
monthlyOnlineIndex.setApril(1.34);
monthlyOnlineIndex.setMay(1.38);
monthlyOnlineIndex.setMarch(-9999.0);
monthlyOnlineIndex.setApril(-9999.0);
monthlyOnlineIndex.setMay(-9999.0);
marketOverview.setMonthlyOnlineIndex(monthlyOnlineIndex);
marketOverview.setGeography("Казахстан (анализ по регионам представлен на тепловой карте)");
marketOverview.setConclusion(
"Онлайн-спрос показывает устойчивый рост в течение года, весной достигая пика. Интернет-продвижение даст максимальный эффект.");
marketOverview.setGeography("EXAMPLE__GEOGRAPHY");
marketOverview.setConclusion("EXAMPLE__MARKET_OVERVIEW_CONCLUSION");
sections.setMarketOverview(marketOverview);
// target_audience
MarketingAnalysisResponseV2.TargetAudience targetAudience = new MarketingAnalysisResponseV2.TargetAudience();
targetAudience.setTitle("Целевая аудитория");
targetAudience.setTitle("EXAMPLE__TARGET_AUDIENCE_TITLE");
MarketingAnalysisResponseV2.TargetAudienceMetrics taMetrics = new MarketingAnalysisResponseV2.TargetAudienceMetrics();
taMetrics.setTotalAudienceSize("1.8 млн человек");
taMetrics.setLeadingSegmentShare("29%");
taMetrics.setAboveAverageIncomeShare("35%");
taMetrics.setTotalAudienceSize("EXAMPLE__TOTAL_AUDIENCE_SIZE");
taMetrics.setLeadingSegmentShare("EXAMPLE__LEADING_SEGMENT_SHARE");
taMetrics.setAboveAverageIncomeShare("EXAMPLE__ABOVE_AVERAGE_INCOME_SHARE");
targetAudience.setMetrics(taMetrics);
targetAudience.setSegments(List.of(
new MarketingAnalysisResponseV2.AudienceSegment("Женщины, 2534 года", "29%"),
new MarketingAnalysisResponseV2.AudienceSegment("Мужчины, 2544 года", "24%"),
new MarketingAnalysisResponseV2.AudienceSegment("Доход выше среднего", "35%")));
new MarketingAnalysisResponseV2.AudienceSegment("EXAMPLE__AUDIENCE_SEGMENT_1",
"EXAMPLE__AUDIENCE_SEGMENT_SHARE_1"),
new MarketingAnalysisResponseV2.AudienceSegment("EXAMPLE__AUDIENCE_SEGMENT_2",
"EXAMPLE__AUDIENCE_SEGMENT_SHARE_2"),
new MarketingAnalysisResponseV2.AudienceSegment("EXAMPLE__AUDIENCE_SEGMENT_3",
"EXAMPLE__AUDIENCE_SEGMENT_SHARE_3")));
Map<String, String> ageStructure = new LinkedHashMap<>();
ageStructure.put("18-24", "10%");
ageStructure.put("25-34", "29%");
ageStructure.put("35-44", "Высокая доля (визуально на графике)");
ageStructure.put("45-54", "15-24%");
ageStructure.put("55_plus", "Низкая доля");
ageStructure.put("18-24", "EXAMPLE__AGE_18_24_SHARE");
ageStructure.put("25-34", "EXAMPLE__AGE_25_34_SHARE");
ageStructure.put("35-44", "EXAMPLE__AGE_35_44_SHARE");
ageStructure.put("45-54", "EXAMPLE__AGE_45_54_SHARE");
ageStructure.put("55_plus", "EXAMPLE__AGE_55_PLUS_SHARE");
targetAudience.setAgeStructure(ageStructure);
targetAudience.setConclusion(
"Основную ценность представляют мужчины и женщины 25–44 лет с доходом выше среднего (до 35% аудитории).");
targetAudience.setConclusion("EXAMPLE__TARGET_AUDIENCE_CONCLUSION");
sections.setTargetAudience(targetAudience);
// competitive_environment
MarketingAnalysisResponseV2.CompetitiveEnvironment competitiveEnvironment = new MarketingAnalysisResponseV2.CompetitiveEnvironment();
competitiveEnvironment.setTitle("Конкурентная среда");
competitiveEnvironment.setTitle("EXAMPLE__COMPETITIVE_ENVIRONMENT_TITLE");
MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics ceMetrics = new MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics();
ceMetrics.setMarketShareTraffic("16%");
ceMetrics.setVisibilityRank("#3");
ceMetrics.setCompetitorShareInContextAds("27%");
ceMetrics.setBenchmarkAstana("13-25%");
ceMetrics.setMarketShareTraffic("EXAMPLE__MARKET_SHARE_TRAFFIC");
ceMetrics.setVisibilityRank("EXAMPLE__VISIBILITY_RANK");
ceMetrics.setCompetitorShareInContextAds("EXAMPLE__COMPETITOR_SHARE_IN_CONTEXT_ADS");
ceMetrics.setBenchmarkAstana("EXAMPLE__BENCHMARK_ASTANA");
competitiveEnvironment.setMetrics(ceMetrics);
Map<String, Integer> digitalVisibilityBenchmarks = new LinkedHashMap<>();
digitalVisibilityBenchmarks.put("competitor_a", 1050);
digitalVisibilityBenchmarks.put("your_business", 600);
digitalVisibilityBenchmarks.put("lead", 300);
digitalVisibilityBenchmarks.put("payment", 450);
digitalVisibilityBenchmarks.put("others", 680);
digitalVisibilityBenchmarks.put("competitor_a", -9999);
digitalVisibilityBenchmarks.put("your_business", -9999);
digitalVisibilityBenchmarks.put("lead", -9999);
digitalVisibilityBenchmarks.put("payment", -9999);
digitalVisibilityBenchmarks.put("others", -9999);
competitiveEnvironment.setDigitalVisibilityBenchmarks(digitalVisibilityBenchmarks);
Map<String, List<String>> competitorStrengths = new LinkedHashMap<>();
competitorStrengths.put("your_business", List.of("Цена", "Оффер"));
competitorStrengths.put("competitor_a", List.of("Отзывы", "Рекламный бюджет"));
competitorStrengths.put("competitor_b", List.of("Контент", "Соцсети", "Экспириенс"));
competitorStrengths.put("competitor_c", List.of("Контент", "Сайт"));
competitorStrengths.put("your_business", List.of("EXAMPLE__STRENGTH_1", "EXAMPLE__STRENGTH_2"));
competitorStrengths.put("competitor_a", List.of("EXAMPLE__COMP_A_STRENGTH_1", "EXAMPLE__COMP_A_STRENGTH_2"));
competitorStrengths.put("competitor_b", List.of("EXAMPLE__COMP_B_STRENGTH_1", "EXAMPLE__COMP_B_STRENGTH_2"));
competitorStrengths.put("competitor_c", List.of("EXAMPLE__COMP_C_STRENGTH_1", "EXAMPLE__COMP_C_STRENGTH_2"));
competitiveEnvironment.setCompetitorStrengths(competitorStrengths);
competitiveEnvironment.setConclusion(
"Ваш бизнес занимает 3-е место по видимости. Основные преимущества конкурентов — соцдоказательства и контент. Ценовая борьба не является оптимальной.");
competitiveEnvironment.setConclusion("EXAMPLE__COMPETITIVE_ENVIRONMENT_CONCLUSION");
sections.setCompetitiveEnvironment(competitiveEnvironment);
// demand_and_behavior
MarketingAnalysisResponseV2.DemandAndBehavior demandAndBehavior = new MarketingAnalysisResponseV2.DemandAndBehavior();
demandAndBehavior.setTitle("Спрос и поведение");
demandAndBehavior.setTitle("EXAMPLE__DEMAND_AND_BEHAVIOR_TITLE");
MarketingAnalysisResponseV2.DemandAndBehaviorMetrics dabMetrics = new MarketingAnalysisResponseV2.DemandAndBehaviorMetrics();
dabMetrics.setSearchVolumeGrowth("+62%");
dabMetrics.setInteractionsBeforePurchase("3-4");
dabMetrics.setRepeatRefusalProbability("54%");
dabMetrics.setSearchVolumeGrowth("EXAMPLE__SEARCH_VOLUME_GROWTH");
dabMetrics.setInteractionsBeforePurchase("EXAMPLE__INTERACTIONS_BEFORE_PURCHASE");
dabMetrics.setRepeatRefusalProbability("EXAMPLE__REPEAT_REFUSAL_PROBABILITY");
demandAndBehavior.setMetrics(dabMetrics);
Map<String, String> searchQueryTypes = new LinkedHashMap<>();
searchQueryTypes.put("direct_interest_catalog", "52%");
searchQueryTypes.put("question_based_articles", "28%");
searchQueryTypes.put("competitors_reviews", "13%");
searchQueryTypes.put("problem_solving_hot_promo", "7%");
searchQueryTypes.put("direct_interest_catalog", "EXAMPLE__QUERY_TYPE_DIRECT");
searchQueryTypes.put("question_based_articles", "EXAMPLE__QUERY_TYPE_QUESTION");
searchQueryTypes.put("competitors_reviews", "EXAMPLE__QUERY_TYPE_COMPETITORS");
searchQueryTypes.put("problem_solving_hot_promo", "EXAMPLE__QUERY_TYPE_PROMO");
demandAndBehavior.setSearchQueryTypes(searchQueryTypes);
Map<String, String> decisionFactors = new LinkedHashMap<>();
decisionFactors.put("promo_discount", "43%");
decisionFactors.put("review_recommendation", "36%");
decisionFactors.put("warranty_quality", "33%");
decisionFactors.put("convenience_service", "25%");
decisionFactors.put("availability", "21%");
decisionFactors.put("price", "19%");
decisionFactors.put("promo_discount", "EXAMPLE__FACTOR_PROMO");
decisionFactors.put("review_recommendation", "EXAMPLE__FACTOR_REVIEWS");
decisionFactors.put("warranty_quality", "EXAMPLE__FACTOR_WARRANTY");
decisionFactors.put("convenience_service", "EXAMPLE__FACTOR_CONVENIENCE");
decisionFactors.put("availability", "EXAMPLE__FACTOR_AVAILABILITY");
decisionFactors.put("price", "EXAMPLE__FACTOR_PRICE");
demandAndBehavior.setDecisionFactors(decisionFactors);
Map<String, String> reasonsForRefusal = new LinkedHashMap<>();
reasonsForRefusal.put("high_price", "37%");
reasonsForRefusal.put("no_reviews_social_proof", "34%");
reasonsForRefusal.put("choice_difficulty_unclear_offer", "29%");
reasonsForRefusal.put("high_price", "EXAMPLE__REFUSAL_HIGH_PRICE");
reasonsForRefusal.put("no_reviews_social_proof", "EXAMPLE__REFUSAL_NO_REVIEWS");
reasonsForRefusal.put("choice_difficulty_unclear_offer", "EXAMPLE__REFUSAL_UNCLEAR_OFFER");
demandAndBehavior.setReasonsForRefusal(reasonsForRefusal);
demandAndBehavior.setConclusion(
"Основной трафик приходит из поиска. Для отклика ключевую роль играют акции и отзывы.");
demandAndBehavior.setConclusion("EXAMPLE__DEMAND_AND_BEHAVIOR_CONCLUSION");
sections.setDemandAndBehavior(demandAndBehavior);
// customer_journey
MarketingAnalysisResponseV2.CustomerJourney customerJourney = new MarketingAnalysisResponseV2.CustomerJourney();
customerJourney.setTitle("Путь клиента");
customerJourney.setTitle("EXAMPLE__CUSTOMER_JOURNEY_TITLE");
MarketingAnalysisResponseV2.FunnelMetrics funnelMetrics = new MarketingAnalysisResponseV2.FunnelMetrics();
funnelMetrics.setAdTraffic("Реклама");
funnelMetrics.setSiteVisitors("Сайт / Лендинг");
funnelMetrics.setLeads(5600);
funnelMetrics.setBookings(1200);
funnelMetrics.setPayments(680);
funnelMetrics.setAdTraffic("EXAMPLE__FUNNEL_AD_TRAFFIC");
funnelMetrics.setSiteVisitors("EXAMPLE__FUNNEL_SITE_VISITORS");
funnelMetrics.setLeads(-9999);
funnelMetrics.setBookings(-9999);
funnelMetrics.setPayments(-9999);
customerJourney.setFunnelMetrics(funnelMetrics);
MarketingAnalysisResponseV2.ConversionRates conversionRates = new MarketingAnalysisResponseV2.ConversionRates();
conversionRates.setLeadToBooking("21%");
conversionRates.setBookingToPayment("57%");
conversionRates.setLeadToPaymentTotal("12%");
conversionRates.setLeadToBooking("EXAMPLE__LEAD_TO_BOOKING");
conversionRates.setBookingToPayment("EXAMPLE__BOOKING_TO_PAYMENT");
conversionRates.setLeadToPaymentTotal("EXAMPLE__LEAD_TO_PAYMENT_TOTAL");
customerJourney.setConversionRates(conversionRates);
MarketingAnalysisResponseV2.FunnelBottlenecks funnelBottlenecks = new MarketingAnalysisResponseV2.FunnelBottlenecks();
funnelBottlenecks.setLeadToBooking("Медленная скорость ответа");
funnelBottlenecks.setBookingToPayment("Недостаточно касаний / напоминаний");
funnelBottlenecks.setLeadToBooking("EXAMPLE__BOTTLENECK_LEAD_TO_BOOKING");
funnelBottlenecks.setBookingToPayment("EXAMPLE__BOTTLENECK_BOOKING_TO_PAYMENT");
customerJourney.setFunnelBottlenecks(funnelBottlenecks);
customerJourney.setConclusion(
"Основные потери происходят на этапе лид -> запись (конверсия 21%) из-за медленных ответов менеджеров.");
customerJourney.setConclusion("EXAMPLE__CUSTOMER_JOURNEY_CONCLUSION");
sections.setCustomerJourney(customerJourney);
// acquisition_channels
MarketingAnalysisResponseV2.AcquisitionChannels acquisitionChannels = new MarketingAnalysisResponseV2.AcquisitionChannels();
acquisitionChannels.setTitle("Каналы привлечения");
acquisitionChannels.setTitle("EXAMPLE__ACQUISITION_CHANNELS_TITLE");
MarketingAnalysisResponseV2.AcquisitionChannelsMetrics acMetrics = new MarketingAnalysisResponseV2.AcquisitionChannelsMetrics();
acMetrics.setSearchTrafficShare("48%");
acMetrics.setAverageLeadCost("37 P");
acMetrics.setGrowthPotential("+21%");
acMetrics.setSearchTrafficShare("EXAMPLE__SEARCH_TRAFFIC_SHARE");
acMetrics.setAverageLeadCost("EXAMPLE__AVERAGE_LEAD_COST");
acMetrics.setGrowthPotential("EXAMPLE__GROWTH_POTENTIAL");
acquisitionChannels.setMetrics(acMetrics);
Map<String, String> channelShares = new LinkedHashMap<>();
channelShares.put("seo", "48%");
channelShares.put("yandex_direct", "31%");
channelShares.put("retargeting", "13%");
channelShares.put("vkontakte", "6%");
channelShares.put("seo", "EXAMPLE__SHARE_SEO");
channelShares.put("yandex_direct", "EXAMPLE__SHARE_YANDEX_DIRECT");
channelShares.put("retargeting", "EXAMPLE__SHARE_RETARGETING");
channelShares.put("vkontakte", "EXAMPLE__SHARE_VKONTAKTE");
acquisitionChannels.setChannelShares(channelShares);
Map<String, MarketingAnalysisResponseV2.ChannelEfficiency> channelEfficiency = new LinkedHashMap<>();
channelEfficiency.put("seo", new MarketingAnalysisResponseV2.ChannelEfficiency("25 P", "Эффективен"));
channelEfficiency.put("yandex", new MarketingAnalysisResponseV2.ChannelEfficiency("45 P", "Эффективен"));
channelEfficiency.put("seo",
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_SEO", "EXAMPLE__EFF_SEO"));
channelEfficiency.put("yandex",
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_YANDEX", "EXAMPLE__EFF_YANDEX"));
channelEfficiency.put("retargeting",
new MarketingAnalysisResponseV2.ChannelEfficiency("40 P", "Удовлетворительно"));
channelEfficiency.put("vkontakte", new MarketingAnalysisResponseV2.ChannelEfficiency("57 P", "Завышено"));
channelEfficiency.put("youtube", new MarketingAnalysisResponseV2.ChannelEfficiency("63 P", "Завышено"));
channelEfficiency.put("instagram", new MarketingAnalysisResponseV2.ChannelEfficiency("77 P", "Завышено"));
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_RETARGETING",
"EXAMPLE__EFF_RETARGETING"));
channelEfficiency.put("vkontakte",
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_VK", "EXAMPLE__EFF_VK"));
channelEfficiency.put("youtube",
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_YOUTUBE", "EXAMPLE__EFF_YOUTUBE"));
channelEfficiency.put("instagram",
new MarketingAnalysisResponseV2.ChannelEfficiency("EXAMPLE__CPL_INSTAGRAM", "EXAMPLE__EFF_INSTAGRAM"));
acquisitionChannels.setChannelEfficiency(channelEfficiency);
acquisitionChannels.setConclusion(
"Основной источник лидов — SEO. VK, Youtube и Instagram требуют оптимизации из-за завышенной стоимости лида.");
acquisitionChannels.setConclusion("EXAMPLE__ACQUISITION_CHANNELS_CONCLUSION");
sections.setAcquisitionChannels(acquisitionChannels);
// marketing_economics
MarketingAnalysisResponseV2.MarketingEconomics marketingEconomics = new MarketingAnalysisResponseV2.MarketingEconomics();
marketingEconomics.setTitle("Экономика маркетинга");
marketingEconomics.setTitle("EXAMPLE__MARKETING_ECONOMICS_TITLE");
MarketingAnalysisResponseV2.MarketingEconomicsMetrics meMetrics = new MarketingAnalysisResponseV2.MarketingEconomicsMetrics();
meMetrics.setCustomerAcquisitionCostCac("2900 P");
meMetrics.setRepeatSalesConversion("32%");
meMetrics.setRoi("3.5x");
meMetrics.setCustomerAcquisitionCostCac("EXAMPLE__CAC");
meMetrics.setRepeatSalesConversion("EXAMPLE__REPEAT_SALES_CONVERSION");
meMetrics.setRoi("EXAMPLE__ROI");
marketingEconomics.setMetrics(meMetrics);
MarketingAnalysisResponseV2.FinancialPerformance financialPerformance = new MarketingAnalysisResponseV2.FinancialPerformance();
financialPerformance
.setMarketingExpenses(new MarketingAnalysisResponseV2.MonthYearValue("1.97 млн", "23.6 млн"));
financialPerformance.setClients(new MarketingAnalysisResponseV2.MonthYearValue("680", "8160"));
financialPerformance.setCac(new MarketingAnalysisResponseV2.MonthYearValue("2900 P", "2900 P"));
.setMarketingExpenses(
new MarketingAnalysisResponseV2.MonthYearValue("EXAMPLE__MARKETING_EXPENSES_MONTH",
"EXAMPLE__MARKETING_EXPENSES_YEAR"));
financialPerformance.setClients(new MarketingAnalysisResponseV2.MonthYearValue("EXAMPLE__CLIENTS_MONTH",
"EXAMPLE__CLIENTS_YEAR"));
financialPerformance
.setRevenueFromClient(new MarketingAnalysisResponseV2.MonthYearValue("10.200 P", "23.040 P"));
financialPerformance.setProfitFromClient(new MarketingAnalysisResponseV2.MonthYearValue("7.300 P", "16.720 P"));
.setCac(new MarketingAnalysisResponseV2.MonthYearValue("EXAMPLE__CAC_MONTH", "EXAMPLE__CAC_YEAR"));
financialPerformance
.setRevenueFromClient(new MarketingAnalysisResponseV2.MonthYearValue("EXAMPLE__REV_PER_CLIENT_MONTH",
"EXAMPLE__REV_PER_CLIENT_YEAR"));
financialPerformance
.setProfitFromClient(new MarketingAnalysisResponseV2.MonthYearValue("EXAMPLE__PROFIT_PER_CLIENT_MONTH",
"EXAMPLE__PROFIT_PER_CLIENT_YEAR"));
marketingEconomics.setFinancialPerformance(financialPerformance);
marketingEconomics.setConclusion(
"Экономика digital-маркетинга эффективна: возврат инвестиций 3.5х. Точки роста — повторные продажи и удержание.");
marketingEconomics.setConclusion("EXAMPLE__MARKETING_ECONOMICS_CONCLUSION");
sections.setMarketingEconomics(marketingEconomics);
// bottlenecks
MarketingAnalysisResponseV2.Bottlenecks bottlenecks = new MarketingAnalysisResponseV2.Bottlenecks();
bottlenecks.setTitle("Проблемы и узкие места");
bottlenecks.setTitle("EXAMPLE__BOTTLENECKS_TITLE");
Map<String, String> statistics = new LinkedHashMap<>();
statistics.put("landing_page_issues", "51%");
statistics.put("slow_manager_responses", "60%");
statistics.put("repeat_interaction_refusal", "36%");
statistics.put("landing_page_issues", "EXAMPLE__STAT_LANDING_PAGE_ISSUES");
statistics.put("slow_manager_responses", "EXAMPLE__STAT_SLOW_MANAGER_RESPONSES");
statistics.put("repeat_interaction_refusal", "EXAMPLE__STAT_REPEAT_INTERACTION_REFUSAL");
bottlenecks.setStatistics(statistics);
MarketingAnalysisResponseV2.BottlenecksDetails details = new MarketingAnalysisResponseV2.BottlenecksDetails();
details.setLanding(List.of("Низкая конверсия (2%)", "Проблемы с формой записи", "Уход посетителей"));
details.setLanding(List.of("EXAMPLE__LANDING_ISSUE_1", "EXAMPLE__LANDING_ISSUE_2", "EXAMPLE__LANDING_ISSUE_3"));
details.setLeadManagement(
List.of("Медленные ответы (30-40+ мин)", "Недостаток напоминаний", "Пропущенные лиды"));
details.setRetention(List.of("Недостаток повторных предложений", "Нет прогрева", "Слабая работа с CRM"));
List.of("EXAMPLE__LEAD_MGMT_ISSUE_1", "EXAMPLE__LEAD_MGMT_ISSUE_2", "EXAMPLE__LEAD_MGMT_ISSUE_3"));
details.setRetention(
List.of("EXAMPLE__RETENTION_ISSUE_1", "EXAMPLE__RETENTION_ISSUE_2", "EXAMPLE__RETENTION_ISSUE_3"));
bottlenecks.setDetails(details);
bottlenecks.setConclusion(
"Теряются десятки процентов лидов из-за медленных ответов менеджеров и слабой ретаргетинговой работы.");
bottlenecks.setConclusion("EXAMPLE__BOTTLENECKS_CONCLUSION");
sections.setBottlenecks(bottlenecks);
// recommendations
MarketingAnalysisResponseV2.Recommendations recommendations = new MarketingAnalysisResponseV2.Recommendations();
recommendations.setTitle("Рекомендации (итоги)");
recommendations.setTitle("EXAMPLE__RECOMMENDATIONS_TITLE");
recommendations.setCorePillars(List.of(
new MarketingAnalysisResponseV2.CorePillar("Фокус на эффективных каналах",
"Перераспределение бюджета на каналы с устойчивым спросом (Яндекс/SEO)"),
new MarketingAnalysisResponseV2.CorePillar("Увеличение повторных касаний",
"Усиление удерживающих кампаний и серий касаний с клиентами"),
new MarketingAnalysisResponseV2.CorePillar("Приоритет высокоценных аудиторий",
"Смещение акцента на платёжеспособные сегменты и B2B"),
new MarketingAnalysisResponseV2.CorePillar("Рост эффективности трафика",
"Снижение зависимости от дорогих источников и оптимизация каналов")));
recommendations.setConclusion(
"Рекомендации фокусируют усилия на эффективности интернет-продвижения и служат базой для следующих шагов.");
new MarketingAnalysisResponseV2.CorePillar("EXAMPLE__PILLAR_1_TITLE", "EXAMPLE__PILLAR_1_DESC"),
new MarketingAnalysisResponseV2.CorePillar("EXAMPLE__PILLAR_2_TITLE", "EXAMPLE__PILLAR_2_DESC"),
new MarketingAnalysisResponseV2.CorePillar("EXAMPLE__PILLAR_3_TITLE", "EXAMPLE__PILLAR_3_DESC"),
new MarketingAnalysisResponseV2.CorePillar("EXAMPLE__PILLAR_4_TITLE", "EXAMPLE__PILLAR_4_DESC")));
recommendations.setConclusion("EXAMPLE__RECOMMENDATIONS_CONCLUSION");
sections.setRecommendations(recommendations);
response.setSections(sections);