This commit is contained in:
arys
2026-01-25 22:12:33 +05:00
parent 68e5262925
commit a89566a83f
@@ -1296,21 +1296,18 @@ public class MarketingAnalysisService {
private MarketingAnalysisResponseV2 buildAnalysisV2ExampleForPrompt(MarketingAnalysisRequest request,
List<String> competitorCompanies) {
MarketingAnalysisResponseV2 response = new MarketingAnalysisResponseV2();
// Заголовок
String niche = (request.getBusinessNiche() != null && !request.getBusinessNiche().isEmpty())
? request.getBusinessNiche() : "Анализируемая ниша";
response.setReportTitle("Стратегический анализ рынка: " + niche);
// Используем нишу из запроса для заголовка примера, чтобы ГПТ понимал контекст
String nicheTitle = (request.getBusinessNiche() != null) ? request.getBusinessNiche() : "Фитнес услуги";
response.setReportTitle("Стратегический анализ рынка: " + nicheTitle);
MarketingAnalysisResponseV2.Sections sections = new MarketingAnalysisResponseV2.Sections();
// ---------------------------------------------------------
// 1. Market Overview
// ---------------------------------------------------------
MarketingAnalysisResponseV2.MarketOverview marketOverview = new MarketingAnalysisResponseV2.MarketOverview();
marketOverview.setTitle("Обзор рынка");
MarketingAnalysisResponseV2.MarketOverviewMetrics moMetrics = new MarketingAnalysisResponseV2.MarketOverviewMetrics();
moMetrics.setOnlineDemandIndex("Высокий (Активный рост)");
moMetrics.setOnlineDemandIndex("Высокий (8/10)");
moMetrics.setOnlinePotential("Растущий тренд (+15-20% YoY)");
moMetrics.setDemandGrowthRateYoy("+18.5%");
moMetrics.setSeasonalityCoefficientSpring("1.25 (Высокий сезон)");
@@ -1318,38 +1315,36 @@ public class MarketingAnalysisService {
marketOverview.setMetrics(moMetrics);
MarketingAnalysisResponseV2.MonthlyOnlineIndex monthlyOnlineIndex = new MarketingAnalysisResponseV2.MonthlyOnlineIndex();
// Реалистичная сезонность (спад летом, рост к весне)
monthlyOnlineIndex.setJanuary(0.95); monthlyOnlineIndex.setFebruary(0.90); monthlyOnlineIndex.setMarch(1.0);
monthlyOnlineIndex.setApril(0.95); monthlyOnlineIndex.setMay(0.85); monthlyOnlineIndex.setJune(0.70);
monthlyOnlineIndex.setJuly(0.60); monthlyOnlineIndex.setAugust(0.75); monthlyOnlineIndex.setSeptember(0.90);
monthlyOnlineIndex.setOctober(0.95); monthlyOnlineIndex.setNovember(1.0); monthlyOnlineIndex.setDecember(0.98);
marketOverview.setMonthlyOnlineIndex(monthlyOnlineIndex);
// ЛОГИКА ГОРОДОВ: Берем из запроса или ставим дефолт
// Логика городов: берем из запроса или дефолт
Map<String, Integer> geography = new LinkedHashMap<>();
List<String> requestedRegions = request.getRegion();
if (requestedRegions != null && !requestedRegions.isEmpty()) {
// Если юзер выбрал города, используем их
for (String region : requestedRegions) {
geography.put(region, 80); // Примерное значение для промпта
List<String> reqRegions = request.getRegion();
if (reqRegions != null && !reqRegions.isEmpty()) {
int step = 100 / Math.max(1, reqRegions.size());
for (int i = 0; i < reqRegions.size(); i++) {
geography.put(reqRegions.get(i), Math.max(10, 90 - (i * 15))); // Разные значения
}
} else {
// Дефолт для КЗ
geography.put("Алматы", 45);
geography.put("Астана", 30);
geography.put("Алматы", 50);
geography.put("Астана", 35);
geography.put("Шымкент", 15);
geography.put("Караганда", 10);
}
marketOverview.setGeography(geography);
marketOverview.setConclusion("Рынок находится в стадии активного роста. Основной спрос сконцентрирован в мегаполисах (75%), сезонность ярко выражена с пиками весной и осенью.");
marketOverview.setConclusion("Рынок находится в стадии активного роста. Основной спрос сконцентрирован в мегаполисах, сезонность ярко выражена.");
sections.setMarketOverview(marketOverview);
// ---------------------------------------------------------
// 2. Target Audience
// ---------------------------------------------------------
MarketingAnalysisResponseV2.TargetAudience targetAudience = new MarketingAnalysisResponseV2.TargetAudience();
targetAudience.setTitle("Портрет целевой аудитории");
MarketingAnalysisResponseV2.TargetAudienceMetrics taMetrics = new MarketingAnalysisResponseV2.TargetAudienceMetrics();
taMetrics.setTotalAudienceSize("~350 000 - 500 000 активных пользователей");
taMetrics.setTotalAudienceSize("~450 000 активных пользователей");
taMetrics.setLeadingSegmentShare("Женщины 25-34 года");
taMetrics.setAboveAverageIncomeShare("42% (Средний+)");
targetAudience.setMetrics(taMetrics);
@@ -1366,47 +1361,53 @@ public class MarketingAnalysisService {
targetAudience.setAgeStructure(ageStructure);
Map<String, Integer> incomeByAge = new LinkedHashMap<>();
incomeByAge.put("18-24", 180000); incomeByAge.put("25-34", 350000);
incomeByAge.put("35-44", 420000); incomeByAge.put("45+", 300000);
incomeByAge.put("18-24", 180000); incomeByAge.put("25-34", 380000);
incomeByAge.put("35-44", 450000); incomeByAge.put("45+", 320000);
targetAudience.setIncomeByAge(incomeByAge);
targetAudience.setConclusion("Ключевой клиент — специалист/менеджер 25-35 лет с доходом выше среднего, ценит сервис и скорость.");
targetAudience.setConclusion("Ключевой клиент — специалист 25-35 лет с доходом выше среднего. Вторичный сегмент — студенты (чувствительны к цене).");
sections.setTargetAudience(targetAudience);
// ---------------------------------------------------------
// 3. Competitive Environment
// ---------------------------------------------------------
MarketingAnalysisResponseV2.CompetitiveEnvironment competitiveEnvironment = new MarketingAnalysisResponseV2.CompetitiveEnvironment();
competitiveEnvironment.setTitle("Конкурентный ландшафт");
// 3.1 Новые метрики
MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics ceMetrics = new MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics();
ceMetrics.setLeaderMarketShare("45-50%");
ceMetrics.setCompetitionLevel("Высокая (Красный океан)");
ceMetrics.setAdPressure("Агрессивная");
ceMetrics.setMarketLeaderName("Сетевые лидеры");
ceMetrics.setAdPressure("Агрессивная (Высокие ставки)");
ceMetrics.setMarketLeaderName("Сетевые лидеры / Маркетплейсы");
competitiveEnvironment.setMetrics(ceMetrics);
// 3.2 Список конкурентов (List<CompetitorRow>) - для таблицы и графика
List<MarketingAnalysisResponseV2.CompetitorRow> competitorRows = new java.util.ArrayList<>();
List<String> companies = (competitorCompanies != null && !competitorCompanies.isEmpty())
? competitorCompanies
: List.of("Крупный сетевой бренд", "Агрессивный дискаунтер", "Премиум-игрок");
for (int i = 0; i < Math.min(companies.size(), 5); i++) {
// Берем реальных конкурентов из поиска или дефолтные, если список пуст
List<String> activeCompetitors = (competitorCompanies != null && !competitorCompanies.isEmpty())
? competitorCompanies
: List.of("Конкурент A (Лидер)", "Конкурент B (Сетевой)", "Конкурент C (Дискаунтер)");
for (int i = 0; i < Math.min(activeCompetitors.size(), 5); i++) {
MarketingAnalysisResponseV2.CompetitorRow row = new MarketingAnalysisResponseV2.CompetitorRow();
row.setName(companies.get(i));
row.setWebsite("https://google.com/search?q=" + companies.get(i).replace(" ", "+"));
row.setVisibilityScore(90 - (i * 12));
row.setKeyStrengths(List.of("Сильный бренд", "Широкая сеть", "Активный SMM"));
row.setName(activeCompetitors.get(i));
// Генерируем ссылку-заглушку, которую GPT должен заменить на реальную
row.setWebsite("https://google.com/search?q=" + activeCompetitors.get(i).replace(" ", "+"));
row.setVisibilityScore(90 - (i * 12)); // 90, 78, 66... (Красивый график)
row.setKeyStrengths(List.of("Сильный бренд", "Широкая сеть филиалов", "Активный SMM"));
row.setPriceSegment(i == 0 ? "Premium" : (i == 1 ? "Low-cost" : "Middle"));
competitorRows.add(row);
}
competitiveEnvironment.setCompetitors(competitorRows);
competitiveEnvironment.setConclusion("Рынок консолидирован крупными игроками. Для входа требуется четкое УТП.");
competitiveEnvironment.setConclusion("Рынок консолидирован крупными игроками. Для успешного входа требуется четкое УТП или узкое нишевание.");
sections.setCompetitiveEnvironment(competitiveEnvironment);
// ---------------------------------------------------------
// 4. Demand And Behavior (ЗАПОЛНЯЕМ ОБЯЗАТЕЛЬНО!)
// ---------------------------------------------------------
// 4. Demand And Behavior
MarketingAnalysisResponseV2.DemandAndBehavior demandAndBehavior = new MarketingAnalysisResponseV2.DemandAndBehavior();
demandAndBehavior.setTitle("Паттерны поведения");
demandAndBehavior.setTitle("Спрос и поведение");
MarketingAnalysisResponseV2.DemandAndBehaviorMetrics dabMetrics = new MarketingAnalysisResponseV2.DemandAndBehaviorMetrics();
dabMetrics.setSearchVolumeGrowth("+22% YoY");
dabMetrics.setInteractionsBeforePurchase("5-7 касаний");
@@ -1414,87 +1415,89 @@ public class MarketingAnalysisService {
demandAndBehavior.setMetrics(dabMetrics);
Map<String, String> searchQueryTypes = new LinkedHashMap<>();
searchQueryTypes.put("Коммерческие (купить, цена)", "45%");
searchQueryTypes.put("Информационные (отзывы)", "30%");
searchQueryTypes.put("Брендовые", "15%");
searchQueryTypes.put("Гео-запросы", "10%");
searchQueryTypes.put("direct_interest_catalog", "40% (Прямой спрос)");
searchQueryTypes.put("question_based_articles", "25% (Как выбрать?)");
searchQueryTypes.put("competitors_reviews", "20% (Сравнение)");
searchQueryTypes.put("problem_solving_hot_promo", "15% (Акции)");
demandAndBehavior.setSearchQueryTypes(searchQueryTypes);
Map<String, String> decisionFactors = new LinkedHashMap<>();
decisionFactors.put("Цена / Рассрочка", "35%");
decisionFactors.put("Отзывы", "25%");
decisionFactors.put("Локация", "20%");
decisionFactors.put("Сервис", "15%");
decisionFactors.put("Бренд", "5%");
decisionFactors.put("promo_discount", "35% (Цена)");
decisionFactors.put("review_recommendation", "25% (Отзывы)");
decisionFactors.put("warranty_quality", "20% (Качество)");
decisionFactors.put("convenience_service", "15% (Сервис)");
decisionFactors.put("availability", "5% (Наличие)");
decisionFactors.put("price", "Важно"); // Дублирует promo, но нужно для структуры
demandAndBehavior.setDecisionFactors(decisionFactors);
Map<String, String> reasonsForRefusal = new LinkedHashMap<>();
reasonsForRefusal.put("Скрытые условия", "40%");
reasonsForRefusal.put("Плохие отзывы", "30%");
reasonsForRefusal.put("Долгая реакция", "30%");
reasonsForRefusal.put("high_price", "40% (Дорого)");
reasonsForRefusal.put("no_reviews_social_proof", "30% (Нет доверия)");
reasonsForRefusal.put("choice_difficulty_unclear_offer", "30% (Непонятно)");
demandAndBehavior.setReasonsForRefusal(reasonsForRefusal);
demandAndBehavior.setConclusion("Пользователи активно сравнивают цены и читают отзывы перед покупкой.");
demandAndBehavior.setConclusion("Покупатели чувствительны к цене и отзывам. Важно наличие социального доказательства.");
sections.setDemandAndBehavior(demandAndBehavior);
// ---------------------------------------------------------
// 5. Customer Journey
// ---------------------------------------------------------
MarketingAnalysisResponseV2.CustomerJourney customerJourney = new MarketingAnalysisResponseV2.CustomerJourney();
customerJourney.setTitle("Воронка продаж");
customerJourney.setTitle("Путь клиента");
MarketingAnalysisResponseV2.FunnelMetrics funnelMetrics = new MarketingAnalysisResponseV2.FunnelMetrics();
funnelMetrics.setAdTraffic("~15 000 показов");
funnelMetrics.setSiteVisitors("~800 переходов (CTR 1.5%)");
funnelMetrics.setLeads(150);
funnelMetrics.setBookings(60);
funnelMetrics.setPayments(45);
funnelMetrics.setAdTraffic("15 000");
funnelMetrics.setSiteVisitors("12 000 (CTR 80%)"); // Условный переход
funnelMetrics.setLeads(450); // 3-4% конверсия
funnelMetrics.setBookings(200); // Квалифицированные
funnelMetrics.setPayments(120); // Продажи
customerJourney.setFunnelMetrics(funnelMetrics);
MarketingAnalysisResponseV2.ConversionRates conversionRates = new MarketingAnalysisResponseV2.ConversionRates();
conversionRates.setLeadToBooking("40%");
conversionRates.setBookingToPayment("75%");
conversionRates.setLeadToPaymentTotal("30%");
conversionRates.setLeadToBooking("45%");
conversionRates.setBookingToPayment("60%");
conversionRates.setLeadToPaymentTotal("27%");
customerJourney.setConversionRates(conversionRates);
MarketingAnalysisResponseV2.FunnelBottlenecks funnelBottlenecks = new MarketingAnalysisResponseV2.FunnelBottlenecks();
funnelBottlenecks.setLeadToBooking("Недозвон / Долгая реакция");
funnelBottlenecks.setBookingToPayment("Возражение 'Дорого'");
funnelBottlenecks.setLeadToBooking("Долгая обработка заявки / Недозвон");
funnelBottlenecks.setBookingToPayment("Высокая цена / Нет рассрочки");
customerJourney.setFunnelBottlenecks(funnelBottlenecks);
customerJourney.setConclusion("Узкое место — обработка входящих заявок (этап квалификации).");
customerJourney.setConclusion("Основные потери лидов происходят на этапе первого звонка и квалификации.");
sections.setCustomerJourney(customerJourney);
// ---------------------------------------------------------
// 6. Acquisition Channels
// ---------------------------------------------------------
MarketingAnalysisResponseV2.AcquisitionChannels acquisitionChannels = new MarketingAnalysisResponseV2.AcquisitionChannels();
acquisitionChannels.setTitle("Каналы трафика");
acquisitionChannels.setTitle("Каналы привлечения");
MarketingAnalysisResponseV2.AcquisitionChannelsMetrics acMetrics = new MarketingAnalysisResponseV2.AcquisitionChannelsMetrics();
acMetrics.setSearchTrafficShare("~30% (SEO + Context)");
acMetrics.setAverageLeadCost("2500 - 4500 KZT");
acMetrics.setSearchTrafficShare("35%");
acMetrics.setAverageLeadCost("2500 - 4000 KZT");
acMetrics.setGrowthPotential("TikTok / Reels");
acquisitionChannels.setMetrics(acMetrics);
Map<String, String> channelShares = new LinkedHashMap<>();
channelShares.put("Instagram", "50%");
channelShares.put("Google Ads", "20%");
channelShares.put("TikTok", "15%");
channelShares.put("2GIS", "10%");
channelShares.put("Other", "5%");
channelShares.put("instagram_target", "45%");
channelShares.put("tiktok_ads", "25%");
channelShares.put("kaspi_marketing", "15%");
channelShares.put("google_ads", "10%");
channelShares.put("2gis_ads", "5%");
acquisitionChannels.setChannelShares(channelShares);
Map<String, MarketingAnalysisResponseV2.ChannelEfficiency> channelEfficiency = new LinkedHashMap<>();
channelEfficiency.put("instagram", new MarketingAnalysisResponseV2.ChannelEfficiency("2000-3500 ", "High"));
channelEfficiency.put("tiktok", new MarketingAnalysisResponseV2.ChannelEfficiency("1500-2500 ₸", "High"));
channelEfficiency.put("google_search", new MarketingAnalysisResponseV2.ChannelEfficiency("4000-6000 ₸", "Medium"));
channelEfficiency.put("instagram", new MarketingAnalysisResponseV2.ChannelEfficiency("2500 KZT", "High"));
channelEfficiency.put("tiktok", new MarketingAnalysisResponseV2.ChannelEfficiency("1800 KZT", "High"));
channelEfficiency.put("kaspi", new MarketingAnalysisResponseV2.ChannelEfficiency("2000 KZT", "Very High"));
channelEfficiency.put("google_search", new MarketingAnalysisResponseV2.ChannelEfficiency("4500 KZT", "Medium"));
channelEfficiency.put("2gis", new MarketingAnalysisResponseV2.ChannelEfficiency("Бесплатно", "Local"));
channelEfficiency.put("threads_meta", new MarketingAnalysisResponseV2.ChannelEfficiency("N/A", "New"));
acquisitionChannels.setChannelEfficiency(channelEfficiency);
acquisitionChannels.setConclusion("Instagram остается основным драйвером продаж. Рекомендуется диверсификация через TikTok.");
acquisitionChannels.setConclusion("Instagram и TikTok — наиболее рентабельные каналы. Kaspi обязателен для товарного бизнеса.");
sections.setAcquisitionChannels(acquisitionChannels);
// ---------------------------------------------------------
// 7. Marketing Economics
// ---------------------------------------------------------
MarketingAnalysisResponseV2.MarketingEconomics marketingEconomics = new MarketingAnalysisResponseV2.MarketingEconomics();
marketingEconomics.setTitle("Юнит-экономика");
marketingEconomics.setTitle("Экономика маркетинга");
MarketingAnalysisResponseV2.MarketingEconomicsMetrics meMetrics = new MarketingAnalysisResponseV2.MarketingEconomicsMetrics();
meMetrics.setCustomerAcquisitionCostCac("3 500 KZT");
meMetrics.setRepeatSalesConversion("30%");
@@ -1502,46 +1505,46 @@ public class MarketingAnalysisService {
marketingEconomics.setMetrics(meMetrics);
MarketingAnalysisResponseV2.FinancialPerformance financialPerformance = new MarketingAnalysisResponseV2.FinancialPerformance();
// Используем бюджет ~1.5 млн
financialPerformance.setMarketingExpenses(new MarketingAnalysisResponseV2.MonthYearValue("1.5 млн KZT", "18 млн KZT"));
financialPerformance.setClients(new MarketingAnalysisResponseV2.MonthYearValue("~430", "~5 160"));
financialPerformance.setCac(new MarketingAnalysisResponseV2.MonthYearValue("3 500 KZT", "3 200 KZT"));
financialPerformance.setRevenueFromClient(new MarketingAnalysisResponseV2.MonthYearValue("25 000 KZT", "300 000 KZT"));
financialPerformance.setProfitFromClient(new MarketingAnalysisResponseV2.MonthYearValue("7 500 KZT", "90 000 KZT"));
financialPerformance.setRevenueFromClient(new MarketingAnalysisResponseV2.MonthYearValue("20 000 KZT", "240 000 KZT"));
financialPerformance.setProfitFromClient(new MarketingAnalysisResponseV2.MonthYearValue("8 000 KZT", "96 000 KZT"));
marketingEconomics.setFinancialPerformance(financialPerformance);
marketingEconomics.setConclusion("Модель масштабируема. Основной рычаг роста — увеличение LTV.");
marketingEconomics.setConclusion("Экономика сходится с положительным ROI. Рекомендуется реинвестировать прибыль в масштабирование.");
sections.setMarketingEconomics(marketingEconomics);
// ---------------------------------------------------------
// 8. Bottlenecks (ЗАПОЛНЯЕМ ОБЯЗАТЕЛЬНО!)
// ---------------------------------------------------------
// 8. Bottlenecks
MarketingAnalysisResponseV2.Bottlenecks bottlenecks = new MarketingAnalysisResponseV2.Bottlenecks();
bottlenecks.setTitle("Точки роста и проблемы");
bottlenecks.setTitle("Узкие места");
Map<String, String> statistics = new LinkedHashMap<>();
statistics.put("landing_page_issues", "Высокий показатель отказов (60%)");
statistics.put("slow_manager_responses", "Звонок > 15 мин (30% потерь)");
statistics.put("repeat_interaction_refusal", "Нет дожима в CRM (20% потерь)");
statistics.put("landing_page_issues", "25% (Отказы)");
statistics.put("slow_manager_responses", "30% отери)");
statistics.put("repeat_interaction_refusal", "20% (Недожим)");
bottlenecks.setStatistics(statistics);
MarketingAnalysisResponseV2.BottlenecksDetails details = new MarketingAnalysisResponseV2.BottlenecksDetails();
details.setLanding(List.of("Долгая загрузка", "Непонятный оффер", "Сложная форма"));
details.setLeadManagement(List.of("Менеджеры не перезванивают", "Нет скриптов", "Нет CRM"));
details.setRetention(List.of("Нет программы лояльности", "Нет NPS", "Нет Email-маркетинга"));
details.setLanding(List.of("Медленная загрузка", "Непонятное УТП", "Нет мобильной адаптации"));
details.setLeadManagement(List.of("Долгий ответ (>15 мин)", "Нет скриптов", "Нет CRM"));
details.setRetention(List.of("Нет программы лояльности", "Редкие касания базы", "Высокая цена без ценности"));
bottlenecks.setDetails(details);
bottlenecks.setConclusion("Технические ошибки сайта и человеческий фактор в продажах — главные ограничители роста.");
bottlenecks.setConclusion("Технические проблемы сайта и отсутствие CRM — главные барьеры.");
sections.setBottlenecks(bottlenecks);
// ---------------------------------------------------------
// 9. Recommendations (ЗАПОЛНЯЕМ ОБЯЗАТЕЛЬНО!)
// ---------------------------------------------------------
// 9. Recommendations
MarketingAnalysisResponseV2.Recommendations recommendations = new MarketingAnalysisResponseV2.Recommendations();
recommendations.setTitle("План действий");
recommendations.setTitle("Рекомендации");
recommendations.setCorePillars(List.of(
new MarketingAnalysisResponseV2.CorePillar("Быстрые победы", "Запустить ретаргетинг и авто-ответ в WhatsApp."),
new MarketingAnalysisResponseV2.CorePillar("Оптимизация сайта", "Упростить форму заявки и ускорить загрузку."),
new MarketingAnalysisResponseV2.CorePillar("Контент", "Снять Reels с отзывами для доверия."),
new MarketingAnalysisResponseV2.CorePillar("Систематизация", "Внедрить CRM для контроля лидов.")
new MarketingAnalysisResponseV2.CorePillar("Быстрый старт", "Запустить таргет с лид-магнитом."),
new MarketingAnalysisResponseV2.CorePillar("Оптимизация", "Внедрить CRM и скрипты продаж."),
new MarketingAnalysisResponseV2.CorePillar("Масштабирование", "Подключить TikTok Ads и блогеров."),
new MarketingAnalysisResponseV2.CorePillar("Удержание", "Внедрить систему лояльности.")
));
recommendations.setConclusion("Фокус на ближайший квартал: повышение конверсии и автоматизация.");
recommendations.setConclusion("Реализация плана позволит удвоить количество лидов за 3 месяца.");
sections.setRecommendations(recommendations);
response.setSections(sections);