fix
This commit is contained in:
@@ -726,83 +726,80 @@ public class MarketingAnalysisService {
|
||||
}
|
||||
|
||||
private String buildDetailedInstruction(MarketingAnalysisRequest request, String structureExampleJson) {
|
||||
String regionsList = (request.getRegion() != null && !request.getRegion().isEmpty())
|
||||
? String.join(", ", request.getRegion())
|
||||
: "Алматы, Астана, Шымкент"; // Дефолтные города, если не выбраны
|
||||
String regionsList;
|
||||
if (request.getRegion() != null && !request.getRegion().isEmpty()) {
|
||||
regionsList = String.join(", ", request.getRegion());
|
||||
} else {
|
||||
regionsList = "Алматы, Астана, Шымкент, Караганда";
|
||||
}
|
||||
|
||||
// Логика возрастных групп
|
||||
String ageRangesInstruction = "";
|
||||
if (request.getTargetAudience() != null && request.getTargetAudience().containsKey("ageRanges")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> ranges = (List<String>) request.getTargetAudience().get("ageRanges");
|
||||
if (ranges != null && !ranges.isEmpty()) {
|
||||
ageRangesInstruction = "Для 'age_structure' и 'income_by_age' используй СТРОГО только эти возрастные группы: " + String.join(", ", ranges) + ".";
|
||||
ageRangesInstruction = "В полях 'age_structure' и 'income_by_age' используй СТРОГО только эти возрастные группы: " + String.join(", ", ranges) + ".";
|
||||
}
|
||||
}
|
||||
|
||||
String template = """
|
||||
Твоя роль: Ты — Ведущий Маркетинговый Аналитик с опытом работы в Big4 (KPMG, PwC) по рынку Казахстана.
|
||||
Твоя задача: Провести глубокий, честный и критический анализ рынка для реального бизнеса. Верни результат СТРОГО в формате JSON.
|
||||
Твоя роль: Ты — Ведущий Маркетинговый Стратег (Senior Strategy Consultant) по рынку Казахстана.
|
||||
Задача: Провести глубокий анализ для РЕАЛЬНОГО бизнеса (B2C/B2B). Никакой воды. Только факты, цифры и применимые советы.
|
||||
|
||||
ВХОДНЫЕ ДАННЫЕ:
|
||||
Ниша: {{NICHE}}
|
||||
Продукт/Услуга: {{PRODUCT}}
|
||||
Целевой регион: {{REGIONS}}
|
||||
ВХОДНЫЕ ДАННЫЕ:
|
||||
Ниша: {{NICHE}}
|
||||
Продукт: {{PRODUCT}}
|
||||
Регионы для анализа: [{{REGIONS}}]
|
||||
|
||||
================================================================================
|
||||
СТРОГИЕ ИНСТРУКЦИИ ПО ЗАПОЛНЕНИЮ (NO HALLUCINATIONS POLICY):
|
||||
================================================================================
|
||||
КРИТИЧЕСКИЕ ИНСТРУКЦИИ (KZ STANDARDS & NO NULLS):
|
||||
|
||||
1. **Market Overview (Обзор рынка):**
|
||||
- `online_demand_index`: НЕ ПИШИ ПРОСТО "Высокий". Пиши "Высокий (8/10)" или "Средний (растущий)".
|
||||
- `demand_growth_rate_yoy`: Используй некруглые числа (напр., "+12.4%", а не "10%").
|
||||
- `geography`:
|
||||
- ОБЯЗАТЕЛЬНО включи в ответ ВСЕ города из списка: [{{REGIONS}}].
|
||||
- Если список городов пуст или содержит "Весь Казахстан", добавь топ-5 городов (Алматы, Астана, Шымкент, Караганда, Актобе).
|
||||
- Значения (Integer 0-100) должны отражать РЕАЛЬНЫЙ спрос (Алматы всегда выше регионов). Разброс должен быть реалистичным (не все по 100).
|
||||
0. **ЗАПРЕЩЕНО ВОЗВРАЩАТЬ NULL**:
|
||||
- Каждая секция (`demand_and_behavior`, `bottlenecks`, `recommendations`) ДОЛЖНА быть заполнена.
|
||||
- Если данных нет, используй экспертную оценку или бенчмарки по нише.
|
||||
- НИКАКИХ ПУСТЫХ ПОЛЕЙ.
|
||||
- ВСЕГДА ИСПОЛЬЗУЙ ПРАВИЛЬНЫЙ JSON, ПО ПЛАНКЕ КОТОРУЮ МЫ СКИНУЛ, И ЧТО БЫ ВСЕ ПРАВАИЛЬНО
|
||||
|
||||
2. **Target Audience (Целевая аудитория):**
|
||||
- `income_by_age`: ЭТО ЧИСЛОВОЕ ПОЛЕ (Integer). Пиши ТОЛЬКО ЦИФРЫ (средняя ЗП в тенге).
|
||||
- ПРАВИЛЬНО: 350000
|
||||
- ОШИБКА: "350 000", "350k KZT".
|
||||
- Ориентируйся на реальные зарплаты в РК (200k - 600k KZT).
|
||||
- `metrics.total_audience_size`: Пиши текстом, но реалистично (напр. "450-500 тыс. человек"), а не "10 млн".
|
||||
1. **ГЕОГРАФИЯ (Market Overview):**
|
||||
- Ты ОБЯЗАН включить в анализ (`geography`) ТОЛЬКО указанные города: [{{REGIONS}}].
|
||||
- Если указан "Весь Казахстан" или список пуст — бери Топ-5 (Алматы, Астана, Шымкент...).
|
||||
- Распределение: Алматы обычно лидер (40-50%), Астана (30%), регионы меньше.
|
||||
|
||||
3. **Competitive Environment (Конкуренты - КРИТИЧНО!):**
|
||||
- В поле `competitors` (массив объектов) найди 3-5 РЕАЛЬНЫХ конкурентов в Казахстане.
|
||||
- **НАЗВАНИЯ (`name`):** Пиши ТОЛЬКО БРЕНД.
|
||||
- ПРАВИЛЬНО: "Invictus", "World Class", "1Fit", "Kaspi Shop".
|
||||
- ОШИБКА: "ТОО Invictus Group", "ИП Иванов", "Фитнес клуб Ромашка".
|
||||
- **САЙТЫ (`website`):** Если знаешь реальный сайт, пиши его (напр. "invictus.kz"). Если нет — ищи профиль в Instagram ("instagram.com/invictus.kz").
|
||||
- `visibility_score`: Оценка от 0 до 100. Лидеры рынка > 80.
|
||||
- `metrics.leader_market_share`: Оцени долю лидера (напр. "35%").
|
||||
2. **КОНКУРЕНТЫ (Competitive Environment):**
|
||||
- Используй данные из `market_evidence_from_search`. Найди 3-5 РЕАЛЬНЫХ игроков.
|
||||
- **ВАЖНО:** В поле `name` пиши ТОЛЬКО БРЕНД (например, "Fitnation", а не "ТОО Fitnation Group"). Без кавычек и юр. форм.
|
||||
- В поле `website` попытайся найти реальный домен или ссылку на Instagram.
|
||||
- Оценка видимости (`visibility_score`) должна быть разной (например: 95, 82, 60, 45). Не ставь всем 100.
|
||||
|
||||
4. **Acquisition Channels (Каналы):**
|
||||
- В Казахстане (B2C) доминируют: Instagram (Reels/Stories), TikTok, Kaspi Marketing (для товаров), 2GIS (для оффлайн-точек).
|
||||
- `average_lead_cost`: Пиши текстом с валютой ("2500 KZT"). Оценивай реально: фитнес ~3000-5000тг, товары ~1500-3000тг.
|
||||
3. **КАНАЛЫ (Acquisition Channels):**
|
||||
- Приоритет в Казахстане (B2C): **Instagram (Reels/Stories), TikTok, Kaspi (магазин/платежи), 2GIS (карты)**.
|
||||
- Google Ads — дорогой канал, ставь эффективность "Medium".
|
||||
- `average_lead_cost`: Пиши текстом с валютой, диапазон (напр. "2500 - 4500 KZT").
|
||||
|
||||
5. **Marketing Economics (Экономика - Бюджет до 3 млн KZT):**
|
||||
- Мы рассчитываем модель для малого/среднего бизнеса.
|
||||
- `marketing_expenses`: Указывай бюджет в диапазоне 500 000 - 3 000 000 KZT в месяц. НЕ БОЛЬШЕ.
|
||||
- `cac` (Стоимость клиента): Должна быть адекватной (не 50 тенге).
|
||||
- `roi`: Реалистичный (100% - 300%), а не 5000%.
|
||||
4. **ЭКОНОМИКА (Marketing Economics):**
|
||||
- **БЮДЖЕТ:** Рассчитывай модель для малого/среднего бизнеса (SME).
|
||||
- Бюджет на маркетинг: **500 000 - 3 000 000 KZT** в месяц. НЕ БОЛЬШЕ.
|
||||
- `cac` (Стоимость привлечения): Адекватная (2000 - 7000 KZT для масс-маркета услуг).
|
||||
- `roi`: Реалистичный (150% - 300%). Не пиши фантастические 1000% на старте.
|
||||
|
||||
6. **Customer Journey (Воронка):**
|
||||
- `funnel_metrics`: Используй реалистичную воронку.
|
||||
- Traffic: ~10 000 - 50 000
|
||||
- Leads: ~2% - 5% от трафика
|
||||
- Sales: ~10% - 30% от лидов.
|
||||
5. **ТИПЫ ДАННЫХ (Строго соблюдай типы):**
|
||||
- `income_by_age`: Значения - ТОЛЬКО ЧИСЛА (Integer). Пример: 350000. (Никаких кавычек, запятых, "KZT").
|
||||
- `monthly_online_index`: Дробные числа (0.0 - 1.0).
|
||||
|
||||
7. **Источники (Sources):**
|
||||
- Собери РЕАЛЬНЫЕ ссылки (Forbes.kz, Kapital.kz, Stat.gov.kz, сайты конкурентов) в массив `sources`.
|
||||
6. **ИСТОЧНИКИ:**
|
||||
- Собери все ссылки из `evidence` и добавь авторитетные источники (stat.gov.kz, kase.kz, forbes.kz) в массив `sources` в самом конце.
|
||||
|
||||
================================================================================
|
||||
{{AGE_INSTRUCTION}}
|
||||
================================================================================
|
||||
{{AGE_INSTRUCTION}}
|
||||
|
||||
ФОРМАТ ОТВЕТА: ТОЛЬКО JSON. Без Markdown, без "```json".
|
||||
Используй структуру ниже как ОБРАЗЕЦ, но заполни её СВОИМИ ДАННЫМИ для ниши {{NICHE}}.
|
||||
ФОРМАТ ОТВЕТА:
|
||||
Верни СТРОГО валидный JSON, соответствующий структуре ниже.
|
||||
Замени все значения `EXAMPLE__` и `-9999` на реальные аналитические данные, специфичные для ниши {{NICHE}}.
|
||||
|
||||
ОБРАЗЕЦ СТРУКТУРЫ (JSON):
|
||||
{{JSON_STRUCTURE}}
|
||||
""";
|
||||
ЭТАЛОННАЯ СТРУКТУРА JSON (Следуй ей неукоснительно):
|
||||
{{JSON_STRUCTURE}}
|
||||
""";
|
||||
|
||||
return template
|
||||
.replace("{{NICHE}}", request.getBusinessNiche())
|
||||
@@ -1299,11 +1296,16 @@ public class MarketingAnalysisService {
|
||||
private MarketingAnalysisResponseV2 buildAnalysisV2ExampleForPrompt(MarketingAnalysisRequest request,
|
||||
List<String> competitorCompanies) {
|
||||
MarketingAnalysisResponseV2 response = new MarketingAnalysisResponseV2();
|
||||
response.setReportTitle("Стратегический анализ рынка: " + request.getBusinessNiche());
|
||||
// Заголовок
|
||||
String niche = (request.getBusinessNiche() != null && !request.getBusinessNiche().isEmpty())
|
||||
? request.getBusinessNiche() : "Анализируемая ниша";
|
||||
response.setReportTitle("Стратегический анализ рынка: " + niche);
|
||||
|
||||
MarketingAnalysisResponseV2.Sections sections = new MarketingAnalysisResponseV2.Sections();
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1. Market Overview
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.MarketOverview marketOverview = new MarketingAnalysisResponseV2.MarketOverview();
|
||||
marketOverview.setTitle("Обзор рынка");
|
||||
|
||||
@@ -1316,37 +1318,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); // Black Friday
|
||||
monthlyOnlineIndex.setDecember(0.98);
|
||||
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);
|
||||
|
||||
// География (Проценты, сумма ~100, приоритет Алматы/Астана)
|
||||
marketOverview.setGeography(Map.of(
|
||||
"Алматы", 45,
|
||||
"Астана", 30,
|
||||
"Шымкент", 10,
|
||||
"Караганда", 8,
|
||||
"Актобе", 5,
|
||||
"Другие регионы", 2
|
||||
));
|
||||
// ЛОГИКА ГОРОДОВ: Берем из запроса или ставим дефолт
|
||||
Map<String, Integer> geography = new LinkedHashMap<>();
|
||||
List<String> requestedRegions = request.getRegion();
|
||||
if (requestedRegions != null && !requestedRegions.isEmpty()) {
|
||||
// Если юзер выбрал города, используем их
|
||||
for (String region : requestedRegions) {
|
||||
geography.put(region, 80); // Примерное значение для промпта
|
||||
}
|
||||
} else {
|
||||
// Дефолт для КЗ
|
||||
geography.put("Алматы", 45);
|
||||
geography.put("Астана", 30);
|
||||
geography.put("Шымкент", 15);
|
||||
geography.put("Караганда", 10);
|
||||
}
|
||||
marketOverview.setGeography(geography);
|
||||
marketOverview.setConclusion("Рынок находится в стадии активного роста. Основной спрос сконцентрирован в мегаполисах (75%), сезонность ярко выражена с пиками весной и осенью.");
|
||||
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.setLeadingSegmentShare("Женщины 25-34 года");
|
||||
@@ -1359,189 +1360,162 @@ public class MarketingAnalysisService {
|
||||
new MarketingAnalysisResponseV2.AudienceSegment("Ситуативные", "25% - Ищут акции")
|
||||
));
|
||||
|
||||
// Возрастная структура (Реальная демография активных покупателей)
|
||||
Map<String, String> ageStructure = new LinkedHashMap<>();
|
||||
ageStructure.put("18-24", "15%");
|
||||
ageStructure.put("25-34", "45%"); // Платежеспособное ядро
|
||||
ageStructure.put("35-44", "25%");
|
||||
ageStructure.put("45+", "15%");
|
||||
ageStructure.put("18-24", "15%"); ageStructure.put("25-34", "45%");
|
||||
ageStructure.put("35-44", "25%"); ageStructure.put("45+", "15%");
|
||||
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", 350000);
|
||||
incomeByAge.put("35-44", 420000); incomeByAge.put("45+", 300000);
|
||||
targetAudience.setIncomeByAge(incomeByAge);
|
||||
|
||||
targetAudience.setConclusion("Ключевой клиент — специалист/менеджер 25-35 лет с доходом выше среднего, ценит сервис и скорость. Вторичный сегмент — студенты и молодежь (чувствительны к цене).");
|
||||
targetAudience.setConclusion("Ключевой клиент — специалист/менеджер 25-35 лет с доходом выше среднего, ценит сервис и скорость.");
|
||||
sections.setTargetAudience(targetAudience);
|
||||
|
||||
// 3. Competitive Environment (ОБНОВЛЕННАЯ СТРУКТУРА)
|
||||
// ---------------------------------------------------------
|
||||
// 3. Competitive Environment
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.CompetitiveEnvironment competitiveEnvironment = new MarketingAnalysisResponseV2.CompetitiveEnvironment();
|
||||
competitiveEnvironment.setTitle("Конкурентный ландшафт");
|
||||
|
||||
MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics ceMetrics = new MarketingAnalysisResponseV2.CompetitiveEnvironmentMetrics();
|
||||
ceMetrics.setLeaderMarketShare("45-50%"); // Доля топ-игроков
|
||||
ceMetrics.setLeaderMarketShare("45-50%");
|
||||
ceMetrics.setCompetitionLevel("Высокая (Красный океан)");
|
||||
ceMetrics.setAdPressure("Агрессивная (Высокие ставки CPI)");
|
||||
ceMetrics.setMarketLeaderName("Сетевые лидеры / Маркетплейсы");
|
||||
ceMetrics.setAdPressure("Агрессивная");
|
||||
ceMetrics.setMarketLeaderName("Сетевые лидеры");
|
||||
competitiveEnvironment.setMetrics(ceMetrics);
|
||||
|
||||
// Список конкурентов (для таблицы и графика)
|
||||
List<MarketingAnalysisResponseV2.CompetitorRow> competitorRows = new java.util.ArrayList<>();
|
||||
List<String> companies = (competitorCompanies != null && !competitorCompanies.isEmpty())
|
||||
? competitorCompanies
|
||||
: List.of("Крупный сетевой бренд", "Агрессивный дискаунтер", "Премиум-игрок");
|
||||
|
||||
// Заполняем 3-5 конкурентов данными для примера
|
||||
for (int i = 0; i < Math.min(companies.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)); // 90, 78, 66...
|
||||
row.setWebsite("https://google.com/search?q=" + companies.get(i).replace(" ", "+"));
|
||||
row.setVisibilityScore(90 - (i * 12));
|
||||
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("Паттерны поведения");
|
||||
|
||||
MarketingAnalysisResponseV2.DemandAndBehaviorMetrics dabMetrics = new MarketingAnalysisResponseV2.DemandAndBehaviorMetrics();
|
||||
dabMetrics.setSearchVolumeGrowth("+22% YoY");
|
||||
dabMetrics.setInteractionsBeforePurchase("5-7 касаний");
|
||||
dabMetrics.setRepeatRefusalProbability("~15% (Сравнение цен)");
|
||||
dabMetrics.setRepeatRefusalProbability("~15%");
|
||||
demandAndBehavior.setMetrics(dabMetrics);
|
||||
|
||||
Map<String, String> searchQueryTypes = new LinkedHashMap<>();
|
||||
searchQueryTypes.put("Коммерческие (купить, цена)", "45%");
|
||||
searchQueryTypes.put("Информационные (отзывы, как выбрать)", "30%");
|
||||
searchQueryTypes.put("Брендовые (имя конкурента)", "15%");
|
||||
searchQueryTypes.put("Гео-запросы (рядом, адрес)", "10%");
|
||||
searchQueryTypes.put("Информационные (отзывы)", "30%");
|
||||
searchQueryTypes.put("Брендовые", "15%");
|
||||
searchQueryTypes.put("Гео-запросы", "10%");
|
||||
demandAndBehavior.setSearchQueryTypes(searchQueryTypes);
|
||||
|
||||
Map<String, String> decisionFactors = new LinkedHashMap<>();
|
||||
decisionFactors.put("Цена / Рассрочка", "35%");
|
||||
decisionFactors.put("Отзывы (Social Proof)", "25%");
|
||||
decisionFactors.put("Скорость / Сервис", "20%");
|
||||
decisionFactors.put("Личный бренд / Доверие", "15%");
|
||||
decisionFactors.put("Удобство оплаты", "5%");
|
||||
decisionFactors.put("Отзывы", "25%");
|
||||
decisionFactors.put("Локация", "20%");
|
||||
decisionFactors.put("Сервис", "15%");
|
||||
decisionFactors.put("Бренд", "5%");
|
||||
demandAndBehavior.setDecisionFactors(decisionFactors);
|
||||
|
||||
Map<String, String> reasonsForRefusal = new LinkedHashMap<>();
|
||||
reasonsForRefusal.put("Скрытые условия / Нет цены", "40%");
|
||||
reasonsForRefusal.put("Плохие отзывы / Нет кейсов", "30%");
|
||||
reasonsForRefusal.put("Долгая реакция менеджера", "30%");
|
||||
reasonsForRefusal.put("Скрытые условия", "40%");
|
||||
reasonsForRefusal.put("Плохие отзывы", "30%");
|
||||
reasonsForRefusal.put("Долгая реакция", "30%");
|
||||
demandAndBehavior.setReasonsForRefusal(reasonsForRefusal);
|
||||
|
||||
demandAndBehavior.setConclusion("Покупатель стал избирательным: он читает отзывы, сравнивает цены и ищет социальные доказательства. Критически важна прозрачность условий и скорость ответа.");
|
||||
demandAndBehavior.setConclusion("Пользователи активно сравнивают цены и читают отзывы перед покупкой.");
|
||||
sections.setDemandAndBehavior(demandAndBehavior);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 5. Customer Journey
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.CustomerJourney customerJourney = new MarketingAnalysisResponseV2.CustomerJourney();
|
||||
customerJourney.setTitle("Воронка продаж");
|
||||
|
||||
MarketingAnalysisResponseV2.FunnelMetrics funnelMetrics = new MarketingAnalysisResponseV2.FunnelMetrics();
|
||||
funnelMetrics.setAdTraffic("~15 000 показов");
|
||||
funnelMetrics.setSiteVisitors("~800 переходов (CTR 1.5%)"); // Средний CTR
|
||||
funnelMetrics.setLeads(150); // Конверсия лендинга ~3-5% (Реалистично для B2C)
|
||||
funnelMetrics.setBookings(60); // Квал. лиды (40% от заявок)
|
||||
funnelMetrics.setPayments(45); // Продажи (Close Rate 30% от квал. лидов)
|
||||
funnelMetrics.setSiteVisitors("~800 переходов (CTR 1.5%)");
|
||||
funnelMetrics.setLeads(150);
|
||||
funnelMetrics.setBookings(60);
|
||||
funnelMetrics.setPayments(45);
|
||||
customerJourney.setFunnelMetrics(funnelMetrics);
|
||||
|
||||
MarketingAnalysisResponseV2.ConversionRates conversionRates = new MarketingAnalysisResponseV2.ConversionRates();
|
||||
conversionRates.setLeadToBooking("40%"); // Квалификация
|
||||
conversionRates.setBookingToPayment("75%"); // Дожим
|
||||
conversionRates.setLeadToPaymentTotal("30%"); // Общая конверсия в продажу
|
||||
conversionRates.setLeadToBooking("40%");
|
||||
conversionRates.setBookingToPayment("75%");
|
||||
conversionRates.setLeadToPaymentTotal("30%");
|
||||
customerJourney.setConversionRates(conversionRates);
|
||||
|
||||
MarketingAnalysisResponseV2.FunnelBottlenecks funnelBottlenecks = new MarketingAnalysisResponseV2.FunnelBottlenecks();
|
||||
funnelBottlenecks.setLeadToBooking("Недозвон / Долгая реакция на заявку");
|
||||
funnelBottlenecks.setBookingToPayment("Возражение 'Дорого' / Отсутствие рассрочки");
|
||||
funnelBottlenecks.setLeadToBooking("Недозвон / Долгая реакция");
|
||||
funnelBottlenecks.setBookingToPayment("Возражение 'Дорого'");
|
||||
customerJourney.setFunnelBottlenecks(funnelBottlenecks);
|
||||
|
||||
customerJourney.setConclusion("Узкое место — обработка входящих заявок. Потеря 60% лидов на этапе квалификации говорит о проблемах в скриптах или скорости реакции.");
|
||||
customerJourney.setConclusion("Узкое место — обработка входящих заявок (этап квалификации).");
|
||||
sections.setCustomerJourney(customerJourney);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 6. Acquisition Channels
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.AcquisitionChannels acquisitionChannels = new MarketingAnalysisResponseV2.AcquisitionChannels();
|
||||
acquisitionChannels.setTitle("Каналы трафика");
|
||||
|
||||
MarketingAnalysisResponseV2.AcquisitionChannelsMetrics acMetrics = new MarketingAnalysisResponseV2.AcquisitionChannelsMetrics();
|
||||
acMetrics.setSearchTrafficShare("~30% (SEO + Context)");
|
||||
acMetrics.setAverageLeadCost("2500 - 4500 KZT"); // Реальный CPL для услуг
|
||||
acMetrics.setGrowthPotential("TikTok / Reels (Short Video)");
|
||||
acMetrics.setAverageLeadCost("2500 - 4500 KZT");
|
||||
acMetrics.setGrowthPotential("TikTok / Reels");
|
||||
acquisitionChannels.setMetrics(acMetrics);
|
||||
|
||||
Map<String, String> channelShares = new LinkedHashMap<>();
|
||||
channelShares.put("Instagram (Target + Content)", "50%");
|
||||
channelShares.put("Google Ads (Search)", "20%");
|
||||
channelShares.put("TikTok (Ads + Organic)", "15%");
|
||||
channelShares.put("2GIS / Maps", "10%");
|
||||
channelShares.put("Other (Referral)", "5%");
|
||||
channelShares.put("Instagram", "50%");
|
||||
channelShares.put("Google Ads", "20%");
|
||||
channelShares.put("TikTok", "15%");
|
||||
channelShares.put("2GIS", "10%");
|
||||
channelShares.put("Other", "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("kaspi",
|
||||
new MarketingAnalysisResponseV2.ChannelEfficiency("5% CPA", "Very High (Горячие)"));
|
||||
channelEfficiency.put("google_search",
|
||||
new MarketingAnalysisResponseV2.ChannelEfficiency("4000-6000 ₸", "Medium (Дорого)"));
|
||||
channelEfficiency.put("2gis",
|
||||
new MarketingAnalysisResponseV2.ChannelEfficiency("Бесплатно", "Local (Гео)"));
|
||||
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("2gis", new MarketingAnalysisResponseV2.ChannelEfficiency("Бесплатно", "Local"));
|
||||
acquisitionChannels.setChannelEfficiency(channelEfficiency);
|
||||
|
||||
acquisitionChannels.setConclusion("Instagram остается основным драйвером продаж. Google Ads эффективен, но дорог. Рекомендуется диверсификация через TikTok для снижения стоимости лида.");
|
||||
acquisitionChannels.setConclusion("Instagram остается основным драйвером продаж. Рекомендуется диверсификация через TikTok.");
|
||||
sections.setAcquisitionChannels(acquisitionChannels);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 7. Marketing Economics
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.MarketingEconomics marketingEconomics = new MarketingAnalysisResponseV2.MarketingEconomics();
|
||||
marketingEconomics.setTitle("Юнит-экономика");
|
||||
|
||||
MarketingAnalysisResponseV2.MarketingEconomicsMetrics meMetrics = new MarketingAnalysisResponseV2.MarketingEconomicsMetrics();
|
||||
meMetrics.setCustomerAcquisitionCostCac("3 500 KZT"); // Целевой CAC
|
||||
meMetrics.setRepeatSalesConversion("25-30%"); // LTV потенциал
|
||||
meMetrics.setRoi("250%"); // Здоровый ROI (3.5x ROAS)
|
||||
meMetrics.setCustomerAcquisitionCostCac("3 500 KZT");
|
||||
meMetrics.setRepeatSalesConversion("30%");
|
||||
meMetrics.setRoi("250%");
|
||||
marketingEconomics.setMetrics(meMetrics);
|
||||
|
||||
MarketingAnalysisResponseV2.FinancialPerformance financialPerformance = new MarketingAnalysisResponseV2.FinancialPerformance();
|
||||
// Бюджет 1.5 млн (Адекватная цифра для малого/среднего бизнеса)
|
||||
financialPerformance.setMarketingExpenses(
|
||||
new MarketingAnalysisResponseV2.MonthYearValue("1.5 млн KZT", "18 млн KZT"));
|
||||
|
||||
// Клиенты: 1.5млн / 3500 = ~428 клиентов
|
||||
financialPerformance.setClients(
|
||||
new MarketingAnalysisResponseV2.MonthYearValue("~430", "~5 160"));
|
||||
|
||||
financialPerformance.setCac(
|
||||
new MarketingAnalysisResponseV2.MonthYearValue("3 500 KZT", "3 200 KZT (Оптимизация)"));
|
||||
|
||||
// Выручка (Чек 25 000 * 430 = 10.7 млн)
|
||||
financialPerformance.setRevenueFromClient(
|
||||
new MarketingAnalysisResponseV2.MonthYearValue("25 000 KZT (Чек)", "300 000 KZT (LTV)"));
|
||||
|
||||
// Прибыль (Маржа 30%)
|
||||
financialPerformance.setProfitFromClient(
|
||||
new MarketingAnalysisResponseV2.MonthYearValue("7 500 KZT", "90 000 KZT"));
|
||||
|
||||
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"));
|
||||
marketingEconomics.setFinancialPerformance(financialPerformance);
|
||||
marketingEconomics.setConclusion("При текущем CAC модель масштабируема. Основной рычаг роста прибыли — увеличение LTV (повторных покупок) и среднего чека.");
|
||||
marketingEconomics.setConclusion("Модель масштабируема. Основной рычаг роста — увеличение LTV.");
|
||||
sections.setMarketingEconomics(marketingEconomics);
|
||||
|
||||
// 8. Bottlenecks
|
||||
// ---------------------------------------------------------
|
||||
// 8. Bottlenecks (ЗАПОЛНЯЕМ ОБЯЗАТЕЛЬНО!)
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.Bottlenecks bottlenecks = new MarketingAnalysisResponseV2.Bottlenecks();
|
||||
bottlenecks.setTitle("Точки роста и проблемы");
|
||||
|
||||
Map<String, String> statistics = new LinkedHashMap<>();
|
||||
statistics.put("landing_page_issues", "Высокий показатель отказов (60%)");
|
||||
statistics.put("slow_manager_responses", "Звонок > 15 мин (30% потерь)");
|
||||
@@ -1549,24 +1523,25 @@ public class MarketingAnalysisService {
|
||||
bottlenecks.setStatistics(statistics);
|
||||
|
||||
MarketingAnalysisResponseV2.BottlenecksDetails details = new MarketingAnalysisResponseV2.BottlenecksDetails();
|
||||
details.setLanding(List.of("Долгая загрузка на мобильных", "Непонятный первый экран (УТП)", "Сложная форма заявки"));
|
||||
details.setLeadManagement(List.of("Менеджеры не перезванивают", "Нет скриптов продаж", "Нет интеграции с WhatsApp"));
|
||||
details.setRetention(List.of("Нет программы лояльности", "Нет сбора обратной связи (NPS)", "Нет Email-маркетинга"));
|
||||
details.setLanding(List.of("Долгая загрузка", "Непонятный оффер", "Сложная форма"));
|
||||
details.setLeadManagement(List.of("Менеджеры не перезванивают", "Нет скриптов", "Нет CRM"));
|
||||
details.setRetention(List.of("Нет программы лояльности", "Нет NPS", "Нет Email-маркетинга"));
|
||||
bottlenecks.setDetails(details);
|
||||
|
||||
bottlenecks.setConclusion("Технические ошибки сайта и человеческий фактор в продажах — главные ограничители роста. Их устранение может удвоить конверсию без увеличения бюджета.");
|
||||
bottlenecks.setConclusion("Технические ошибки сайта и человеческий фактор в продажах — главные ограничители роста.");
|
||||
sections.setBottlenecks(bottlenecks);
|
||||
|
||||
// 9. Recommendations
|
||||
// ---------------------------------------------------------
|
||||
// 9. Recommendations (ЗАПОЛНЯЕМ ОБЯЗАТЕЛЬНО!)
|
||||
// ---------------------------------------------------------
|
||||
MarketingAnalysisResponseV2.Recommendations recommendations = new MarketingAnalysisResponseV2.Recommendations();
|
||||
recommendations.setTitle("План действий");
|
||||
recommendations.setCorePillars(List.of(
|
||||
new MarketingAnalysisResponseV2.CorePillar("Быстрые победы", "Запустить ретаргетинг на посетителей сайта и внедрить авто-ответ в WhatsApp."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Оптимизация сайта", "Упростить форму заявки до 2 полей (Имя, Телефон) и ускорить мобильную версию."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Контент-маркетинг", "Снять 10 Reels с отзывами клиентов и процессом работы для повышения доверия."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Систематизация", "Внедрить CRM для контроля пропущенных звонков и задач менеджеров.")
|
||||
new MarketingAnalysisResponseV2.CorePillar("Быстрые победы", "Запустить ретаргетинг и авто-ответ в WhatsApp."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Оптимизация сайта", "Упростить форму заявки и ускорить загрузку."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Контент", "Снять Reels с отзывами для доверия."),
|
||||
new MarketingAnalysisResponseV2.CorePillar("Систематизация", "Внедрить CRM для контроля лидов.")
|
||||
));
|
||||
recommendations.setConclusion("Фокус на ближайший квартал: повышение конверсии сайта и автоматизация первичной обработки лидов.");
|
||||
recommendations.setConclusion("Фокус на ближайший квартал: повышение конверсии и автоматизация.");
|
||||
sections.setRecommendations(recommendations);
|
||||
|
||||
response.setSections(sections);
|
||||
|
||||
Reference in New Issue
Block a user