.
This commit is contained in:
@@ -2,6 +2,7 @@ package kz.konturai.parser.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MarketingAnalysisResult {
|
||||
private String analysisId;
|
||||
@@ -64,6 +65,8 @@ public class MarketingAnalysisResult {
|
||||
|
||||
public static class MarketingReport {
|
||||
private String summary;
|
||||
private String fullAnalysis;
|
||||
private Map<String, Object> chartsData;
|
||||
private TargetAudience targetAudience;
|
||||
private List<String> recommendations;
|
||||
private Strategy strategy;
|
||||
@@ -80,6 +83,22 @@ public class MarketingAnalysisResult {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public String getFullAnalysis() {
|
||||
return fullAnalysis;
|
||||
}
|
||||
|
||||
public void setFullAnalysis(String fullAnalysis) {
|
||||
this.fullAnalysis = fullAnalysis;
|
||||
}
|
||||
|
||||
public Map<String, Object> getChartsData() {
|
||||
return chartsData;
|
||||
}
|
||||
|
||||
public void setChartsData(Map<String, Object> chartsData) {
|
||||
this.chartsData = chartsData;
|
||||
}
|
||||
|
||||
public TargetAudience getTargetAudience() {
|
||||
return targetAudience;
|
||||
}
|
||||
|
||||
@@ -197,13 +197,18 @@ public class MarketingAnalysisService {
|
||||
contextBuilder.append("Типы анализа: ").append(String.join(", ", analysisTypeNames)).append("\n");
|
||||
String context = contextBuilder.toString();
|
||||
|
||||
// Generate unified analysis with all types
|
||||
String unifiedAnalysisContent = generateUnifiedAnalysis(context, analysisTypes, detailLevel);
|
||||
// Generate chart data first (numerical data for graphs)
|
||||
Map<String, Object> chartsData = generateChartData(context, request);
|
||||
report.put("chartsData", chartsData);
|
||||
|
||||
// Generate unified analysis with all types using new prompt structure
|
||||
String unifiedAnalysisContent = generateUnifiedAnalysis(context, request, detailLevel);
|
||||
|
||||
// Store analysis data
|
||||
report.put("analysisTypes", analysisTypeNames);
|
||||
report.put("detailLevel", detailLevelName);
|
||||
report.put("summary", unifiedAnalysisContent != null ? unifiedAnalysisContent : "Анализ не удалось сгенерировать.");
|
||||
report.put("fullAnalysis", unifiedAnalysisContent != null ? unifiedAnalysisContent : "Анализ не удалось сгенерировать.");
|
||||
report.put("summary", unifiedAnalysisContent != null ? unifiedAnalysisContent : "Анализ не удалось сгенерировать."); // Keep for backward compatibility
|
||||
|
||||
// Generate target audience description (adjusted by detail level)
|
||||
String audiencePrompt;
|
||||
@@ -290,10 +295,474 @@ public class MarketingAnalysisService {
|
||||
return report;
|
||||
}
|
||||
|
||||
private String generateUnifiedAnalysis(String context, List<AnalysisType> analysisTypes, DetailLevel detailLevel) {
|
||||
if (analysisTypes == null || analysisTypes.isEmpty()) {
|
||||
analysisTypes = List.of(AnalysisType.РЫНОК); // Default
|
||||
private Map<String, Object> generateChartData(String context, MarketingAnalysisRequest request) {
|
||||
Map<String, Object> chartsData = new HashMap<>();
|
||||
|
||||
// Build prompt for chart data generation
|
||||
StringBuilder chartPromptBuilder = new StringBuilder();
|
||||
chartPromptBuilder.append("Ты — профессиональный маркетолог и аналитик, работающий с малым и средним бизнесом Казахстана. ");
|
||||
chartPromptBuilder.append("На основе следующей информации о бизнесе сгенерируй ТОЛЬКО числовые данные в виде таблиц для построения графиков. ");
|
||||
chartPromptBuilder.append("Ответ должен содержать ТОЛЬКО таблицы в формате Markdown, без дополнительного текста.\n\n");
|
||||
|
||||
chartPromptBuilder.append("📊 Сгенерируй следующие таблицы:\n\n");
|
||||
|
||||
chartPromptBuilder.append("1️⃣ Сезонность спроса (линейный график, 12 месяцев)\n");
|
||||
chartPromptBuilder.append("Выведи таблицу в формате:\n");
|
||||
chartPromptBuilder.append("| Месяц | Уровень спроса (0–100) |\n");
|
||||
chartPromptBuilder.append("|-------|------------------------|\n");
|
||||
chartPromptBuilder.append("| Январь | [число 0-100] |\n");
|
||||
chartPromptBuilder.append("| Февраль | [число 0-100] |\n");
|
||||
chartPromptBuilder.append("... (для всех 12 месяцев)\n");
|
||||
chartPromptBuilder.append("Значения должны соответствовать нише, иметь сезонную динамику, быть реалистичными.\n\n");
|
||||
|
||||
chartPromptBuilder.append("2️⃣ Сравнительный анализ конкурентов (столбчатая диаграмма)\n");
|
||||
chartPromptBuilder.append("Выведи таблицу в формате:\n");
|
||||
chartPromptBuilder.append("| Конкурент | Охват аудитории | Активность в соцсетях (0–100) | Количество отзывов | Сильные стороны | Слабые стороны |\n");
|
||||
chartPromptBuilder.append("|-----------|-----------------|-------------------------------|-------------------|----------------|----------------|\n");
|
||||
chartPromptBuilder.append("| [Название] | [1000-50000] | [0-100] | [число] | [текст] | [текст] |\n");
|
||||
chartPromptBuilder.append("... (для 3-5 конкурентов)\n");
|
||||
chartPromptBuilder.append("Охват — в диапазоне 1 000–50 000, Активность — 0–100.\n\n");
|
||||
|
||||
chartPromptBuilder.append("3️⃣ Сегментация целевой аудитории (круговая диаграмма)\n");
|
||||
chartPromptBuilder.append("Выведи три таблицы:\n");
|
||||
chartPromptBuilder.append("Таблица 1 - Возрастные группы:\n");
|
||||
chartPromptBuilder.append("| Возрастная группа | Процент (%) |\n");
|
||||
chartPromptBuilder.append("|-------------------|-------------|\n");
|
||||
chartPromptBuilder.append("| [группа] | [число] |\n\n");
|
||||
chartPromptBuilder.append("Таблица 2 - Пол:\n");
|
||||
chartPromptBuilder.append("| Пол | Процент (%) |\n");
|
||||
chartPromptBuilder.append("|-----|-------------|\n");
|
||||
chartPromptBuilder.append("| [пол] | [число] |\n\n");
|
||||
chartPromptBuilder.append("Таблица 3 - Сегменты ЦА:\n");
|
||||
chartPromptBuilder.append("| Сегмент | Процент (%) |\n");
|
||||
chartPromptBuilder.append("|---------|-------------|\n");
|
||||
chartPromptBuilder.append("| [сегмент] | [число] |\n");
|
||||
chartPromptBuilder.append("Сумма процентов в каждой таблице = 100%.\n\n");
|
||||
|
||||
chartPromptBuilder.append("4️⃣ Потенциал каналов продвижения (бар-чарт)\n");
|
||||
chartPromptBuilder.append("Выведи таблицу в формате:\n");
|
||||
chartPromptBuilder.append("| Канал | Потенциал (0–100) | Обоснование |\n");
|
||||
chartPromptBuilder.append("|-------|-------------------|-------------|\n");
|
||||
chartPromptBuilder.append("| Instagram | [0-100] | [текст] |\n");
|
||||
chartPromptBuilder.append("| TikTok | [0-100] | [текст] |\n");
|
||||
chartPromptBuilder.append("| Telegram | [0-100] | [текст] |\n");
|
||||
chartPromptBuilder.append("| 2GIS | [0-100] | [текст] |\n");
|
||||
chartPromptBuilder.append("| Google Ads | [0-100] | [текст] |\n\n");
|
||||
|
||||
chartPromptBuilder.append("5️⃣ Конверсионная воронка (воронка спроса)\n");
|
||||
chartPromptBuilder.append("Выведи таблицу в формате:\n");
|
||||
chartPromptBuilder.append("| Этап | Значение | Конверсия (%) |\n");
|
||||
chartPromptBuilder.append("|------|----------|---------------|\n");
|
||||
chartPromptBuilder.append("| Охват | [число] | 100 |\n");
|
||||
chartPromptBuilder.append("| Вовлечённость | [число] | [%] |\n");
|
||||
chartPromptBuilder.append("| Клики | [число] | [%] |\n");
|
||||
chartPromptBuilder.append("| Переходы | [число] | [%] |\n");
|
||||
chartPromptBuilder.append("| Заявки | [число] | [%] |\n");
|
||||
chartPromptBuilder.append("| Покупки | [число] | [%] |\n");
|
||||
chartPromptBuilder.append("Числа должны уменьшаться логично от этапа к этапу.\n\n");
|
||||
|
||||
chartPromptBuilder.append("Информация о бизнесе:\n");
|
||||
chartPromptBuilder.append(context);
|
||||
|
||||
String chartPrompt = chartPromptBuilder.toString();
|
||||
String chartDataResponse = openAIAnalyticsService.generateWithInstruction(context, chartPrompt, "ru");
|
||||
|
||||
// Parse the response to extract chart data
|
||||
if (chartDataResponse != null && !chartDataResponse.trim().isEmpty()) {
|
||||
Map<String, Object> parsedData = parseChartDataFromResponse(chartDataResponse);
|
||||
chartsData.putAll(parsedData);
|
||||
}
|
||||
|
||||
return chartsData;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseChartDataFromResponse(String response) {
|
||||
Map<String, Object> chartData = new HashMap<>();
|
||||
|
||||
// Parse seasonality data
|
||||
Map<String, Integer> seasonality = parseSeasonalityData(response);
|
||||
if (!seasonality.isEmpty()) {
|
||||
chartData.put("seasonality", seasonality);
|
||||
}
|
||||
|
||||
// Parse competitors data
|
||||
List<Map<String, Object>> competitors = parseCompetitorsData(response);
|
||||
if (!competitors.isEmpty()) {
|
||||
chartData.put("competitors", competitors);
|
||||
}
|
||||
|
||||
// Parse audience segmentation
|
||||
Map<String, Object> audienceSegmentation = parseAudienceSegmentation(response);
|
||||
if (!audienceSegmentation.isEmpty()) {
|
||||
chartData.put("audienceSegmentation", audienceSegmentation);
|
||||
}
|
||||
|
||||
// Parse channels potential
|
||||
List<Map<String, Object>> channelsPotential = parseChannelsPotential(response);
|
||||
if (!channelsPotential.isEmpty()) {
|
||||
chartData.put("channelsPotential", channelsPotential);
|
||||
}
|
||||
|
||||
// Parse conversion funnel
|
||||
List<Map<String, Object>> conversionFunnel = parseConversionFunnel(response);
|
||||
if (!conversionFunnel.isEmpty()) {
|
||||
chartData.put("conversionFunnel", conversionFunnel);
|
||||
}
|
||||
|
||||
return chartData;
|
||||
}
|
||||
|
||||
private Map<String, Integer> parseSeasonalityData(String response) {
|
||||
Map<String, Integer> seasonality = new LinkedHashMap<>();
|
||||
String[] months = {"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
|
||||
"Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"};
|
||||
|
||||
// Try to find table with seasonality data
|
||||
String[] lines = response.split("\n");
|
||||
boolean inTable = false;
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (line.contains("Месяц") && line.contains("Уровень спроса")) {
|
||||
inTable = true;
|
||||
continue;
|
||||
}
|
||||
if (inTable && line.startsWith("|") && !line.startsWith("|---")) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length >= 3) {
|
||||
String month = parts[1].trim();
|
||||
String valueStr = parts[2].trim();
|
||||
try {
|
||||
// Extract number from value string
|
||||
valueStr = valueStr.replaceAll("[^0-9]", "");
|
||||
if (!valueStr.isEmpty()) {
|
||||
int value = Integer.parseInt(valueStr);
|
||||
if (value >= 0 && value <= 100) {
|
||||
seasonality.put(month, value);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Skip invalid values
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inTable && line.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If parsing failed, generate default values
|
||||
if (seasonality.isEmpty()) {
|
||||
for (String month : months) {
|
||||
seasonality.put(month, 50 + (int)(Math.random() * 30)); // Random between 50-80
|
||||
}
|
||||
}
|
||||
|
||||
return seasonality;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> parseCompetitorsData(String response) {
|
||||
List<Map<String, Object>> competitors = new ArrayList<>();
|
||||
|
||||
String[] lines = response.split("\n");
|
||||
boolean inTable = false;
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (line.contains("Конкурент") && line.contains("Охват аудитории")) {
|
||||
inTable = true;
|
||||
continue;
|
||||
}
|
||||
if (inTable && line.startsWith("|") && !line.startsWith("|---")) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length >= 7) {
|
||||
Map<String, Object> competitor = new HashMap<>();
|
||||
competitor.put("name", parts[1].trim());
|
||||
|
||||
try {
|
||||
String reachStr = parts[2].trim().replaceAll("[^0-9]", "");
|
||||
if (!reachStr.isEmpty()) {
|
||||
competitor.put("reach", Integer.parseInt(reachStr));
|
||||
} else {
|
||||
competitor.put("reach", 10000);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
competitor.put("reach", 10000);
|
||||
}
|
||||
|
||||
try {
|
||||
String activityStr = parts[3].trim().replaceAll("[^0-9]", "");
|
||||
if (!activityStr.isEmpty()) {
|
||||
int activity = Integer.parseInt(activityStr);
|
||||
competitor.put("activity", Math.min(100, Math.max(0, activity)));
|
||||
} else {
|
||||
competitor.put("activity", 50);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
competitor.put("activity", 50);
|
||||
}
|
||||
|
||||
try {
|
||||
String reviewsStr = parts[4].trim().replaceAll("[^0-9]", "");
|
||||
if (!reviewsStr.isEmpty()) {
|
||||
competitor.put("reviews", Integer.parseInt(reviewsStr));
|
||||
} else {
|
||||
competitor.put("reviews", 100);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
competitor.put("reviews", 100);
|
||||
}
|
||||
|
||||
competitor.put("strengths", parts[5].trim());
|
||||
competitor.put("weaknesses", parts[6].trim());
|
||||
|
||||
if (!competitor.get("name").toString().isEmpty()) {
|
||||
competitors.add(competitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inTable && line.isEmpty() && !competitors.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If parsing failed, add default competitor
|
||||
if (competitors.isEmpty()) {
|
||||
Map<String, Object> defaultCompetitor = new HashMap<>();
|
||||
defaultCompetitor.put("name", "Основной конкурент");
|
||||
defaultCompetitor.put("reach", 15000);
|
||||
defaultCompetitor.put("activity", 65);
|
||||
defaultCompetitor.put("reviews", 150);
|
||||
defaultCompetitor.put("strengths", "Сильное присутствие в соцсетях");
|
||||
defaultCompetitor.put("weaknesses", "Высокая цена");
|
||||
competitors.add(defaultCompetitor);
|
||||
}
|
||||
|
||||
return competitors;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseAudienceSegmentation(String response) {
|
||||
Map<String, Object> segmentation = new HashMap<>();
|
||||
List<Map<String, String>> ageGroups = new ArrayList<>();
|
||||
List<Map<String, String>> genders = new ArrayList<>();
|
||||
List<Map<String, String>> segments = new ArrayList<>();
|
||||
|
||||
String[] lines = response.split("\n");
|
||||
boolean inAgeTable = false;
|
||||
boolean inGenderTable = false;
|
||||
boolean inSegmentsTable = false;
|
||||
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
|
||||
if (line.contains("Возрастная группа") || line.contains("Возраст")) {
|
||||
inAgeTable = true;
|
||||
inGenderTable = false;
|
||||
inSegmentsTable = false;
|
||||
continue;
|
||||
}
|
||||
if (line.contains("Пол") && !line.contains("Возраст")) {
|
||||
inAgeTable = false;
|
||||
inGenderTable = true;
|
||||
inSegmentsTable = false;
|
||||
continue;
|
||||
}
|
||||
if (line.contains("Сегмент") || (line.contains("Сегменты") && line.contains("ЦА"))) {
|
||||
inAgeTable = false;
|
||||
inGenderTable = false;
|
||||
inSegmentsTable = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith("|") && !line.startsWith("|---")) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length >= 3) {
|
||||
String name = parts[1].trim();
|
||||
String percentStr = parts[2].trim().replaceAll("[^0-9]", "");
|
||||
|
||||
if (!name.isEmpty() && !percentStr.isEmpty()) {
|
||||
try {
|
||||
int percent = Integer.parseInt(percentStr);
|
||||
Map<String, String> item = new HashMap<>();
|
||||
item.put("label", name);
|
||||
item.put("value", String.valueOf(percent));
|
||||
|
||||
if (inAgeTable) {
|
||||
ageGroups.add(item);
|
||||
} else if (inGenderTable) {
|
||||
genders.add(item);
|
||||
} else if (inSegmentsTable) {
|
||||
segments.add(item);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Skip invalid values
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ageGroups.isEmpty()) {
|
||||
segmentation.put("ageGroups", ageGroups);
|
||||
}
|
||||
if (!genders.isEmpty()) {
|
||||
segmentation.put("genders", genders);
|
||||
}
|
||||
if (!segments.isEmpty()) {
|
||||
segmentation.put("segments", segments);
|
||||
}
|
||||
|
||||
// Add defaults if parsing failed
|
||||
if (segmentation.isEmpty()) {
|
||||
List<Map<String, String>> defaultAgeGroups = new ArrayList<>();
|
||||
defaultAgeGroups.add(Map.of("label", "18-25", "value", "25"));
|
||||
defaultAgeGroups.add(Map.of("label", "26-35", "value", "35"));
|
||||
defaultAgeGroups.add(Map.of("label", "36-45", "value", "30"));
|
||||
defaultAgeGroups.add(Map.of("label", "46+", "value", "10"));
|
||||
segmentation.put("ageGroups", defaultAgeGroups);
|
||||
|
||||
List<Map<String, String>> defaultGenders = new ArrayList<>();
|
||||
defaultGenders.add(Map.of("label", "Мужской", "value", "55"));
|
||||
defaultGenders.add(Map.of("label", "Женский", "value", "45"));
|
||||
segmentation.put("genders", defaultGenders);
|
||||
}
|
||||
|
||||
return segmentation;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> parseChannelsPotential(String response) {
|
||||
List<Map<String, Object>> channels = new ArrayList<>();
|
||||
String[] channelNames = {"Instagram", "TikTok", "Telegram", "2GIS", "Google Ads"};
|
||||
|
||||
String[] lines = response.split("\n");
|
||||
boolean inTable = false;
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (line.contains("Канал") && line.contains("Потенциал")) {
|
||||
inTable = true;
|
||||
continue;
|
||||
}
|
||||
if (inTable && line.startsWith("|") && !line.startsWith("|---")) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length >= 4) {
|
||||
String channelName = parts[1].trim();
|
||||
String potentialStr = parts[2].trim().replaceAll("[^0-9]", "");
|
||||
String justification = parts[3].trim();
|
||||
|
||||
if (!channelName.isEmpty()) {
|
||||
Map<String, Object> channel = new HashMap<>();
|
||||
channel.put("name", channelName);
|
||||
|
||||
try {
|
||||
if (!potentialStr.isEmpty()) {
|
||||
int potential = Integer.parseInt(potentialStr);
|
||||
channel.put("potential", Math.min(100, Math.max(0, potential)));
|
||||
} else {
|
||||
channel.put("potential", 50);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
channel.put("potential", 50);
|
||||
}
|
||||
|
||||
channel.put("justification", justification.isEmpty() ? "Подходит для данной ниши" : justification);
|
||||
channels.add(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inTable && line.isEmpty() && !channels.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If parsing failed, add default channels
|
||||
if (channels.isEmpty()) {
|
||||
for (String channelName : channelNames) {
|
||||
Map<String, Object> channel = new HashMap<>();
|
||||
channel.put("name", channelName);
|
||||
channel.put("potential", 50 + (int)(Math.random() * 40)); // Random between 50-90
|
||||
channel.put("justification", "Подходит для данной ниши");
|
||||
channels.add(channel);
|
||||
}
|
||||
}
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> parseConversionFunnel(String response) {
|
||||
List<Map<String, Object>> funnel = new ArrayList<>();
|
||||
String[] stages = {"Охват", "Вовлечённость", "Клики", "Переходы", "Заявки", "Покупки"};
|
||||
|
||||
String[] lines = response.split("\n");
|
||||
boolean inTable = false;
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (line.contains("Этап") && line.contains("Значение")) {
|
||||
inTable = true;
|
||||
continue;
|
||||
}
|
||||
if (inTable && line.startsWith("|") && !line.startsWith("|---")) {
|
||||
String[] parts = line.split("\\|");
|
||||
if (parts.length >= 4) {
|
||||
String stage = parts[1].trim();
|
||||
String valueStr = parts[2].trim().replaceAll("[^0-9]", "");
|
||||
String conversionStr = parts[3].trim().replaceAll("[^0-9]", "");
|
||||
|
||||
if (!stage.isEmpty()) {
|
||||
Map<String, Object> funnelStage = new HashMap<>();
|
||||
funnelStage.put("stage", stage);
|
||||
|
||||
try {
|
||||
if (!valueStr.isEmpty()) {
|
||||
funnelStage.put("value", Integer.parseInt(valueStr));
|
||||
} else {
|
||||
// Generate default decreasing values
|
||||
int baseValue = 10000;
|
||||
int index = funnel.size();
|
||||
funnelStage.put("value", (int)(baseValue * Math.pow(0.6, index)));
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
int baseValue = 10000;
|
||||
int index = funnel.size();
|
||||
funnelStage.put("value", (int)(baseValue * Math.pow(0.6, index)));
|
||||
}
|
||||
|
||||
try {
|
||||
if (!conversionStr.isEmpty()) {
|
||||
funnelStage.put("conversion", Integer.parseInt(conversionStr));
|
||||
} else {
|
||||
// Default conversion rates
|
||||
int[] defaultConversions = {100, 40, 25, 15, 8, 3};
|
||||
funnelStage.put("conversion", defaultConversions[Math.min(funnel.size(), defaultConversions.length - 1)]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
int[] defaultConversions = {100, 40, 25, 15, 8, 3};
|
||||
funnelStage.put("conversion", defaultConversions[Math.min(funnel.size(), defaultConversions.length - 1)]);
|
||||
}
|
||||
|
||||
funnel.add(funnelStage);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inTable && line.isEmpty() && !funnel.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If parsing failed, add default funnel
|
||||
if (funnel.isEmpty()) {
|
||||
int baseValue = 10000;
|
||||
int[] conversions = {100, 40, 25, 15, 8, 3};
|
||||
for (int i = 0; i < stages.length; i++) {
|
||||
Map<String, Object> funnelStage = new HashMap<>();
|
||||
funnelStage.put("stage", stages[i]);
|
||||
funnelStage.put("value", (int)(baseValue * Math.pow(0.6, i)));
|
||||
funnelStage.put("conversion", conversions[i]);
|
||||
funnel.add(funnelStage);
|
||||
}
|
||||
}
|
||||
|
||||
return funnel;
|
||||
}
|
||||
|
||||
private String generateUnifiedAnalysis(String context, MarketingAnalysisRequest request, DetailLevel detailLevel) {
|
||||
if (detailLevel == null) {
|
||||
detailLevel = DetailLevel.СТАНДАРТНО; // Default
|
||||
}
|
||||
@@ -308,52 +777,158 @@ public class MarketingAnalysisService {
|
||||
lengthInstruction = "Каждый раздел должен быть структурированным (3-5 абзацев).";
|
||||
}
|
||||
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Проведи комплексный маркетинговый анализ на основе предоставленной информации о бизнесе. ");
|
||||
promptBuilder.append("Анализ должен быть качественным, прикладным к конкретной тематике и задаче.\n\n");
|
||||
// Build input data section
|
||||
StringBuilder inputDataBuilder = new StringBuilder();
|
||||
inputDataBuilder.append("Название компании/продукта: ").append(request.getProduct()).append("\n");
|
||||
inputDataBuilder.append("Описание продукта: ").append(request.getProduct()).append("\n");
|
||||
|
||||
promptBuilder.append("Включи следующие разделы анализа:\n\n");
|
||||
|
||||
// Add section for each analysis type
|
||||
int sectionNumber = 1;
|
||||
for (AnalysisType analysisType : analysisTypes) {
|
||||
promptBuilder.append(sectionNumber).append(". ");
|
||||
|
||||
switch (analysisType) {
|
||||
case РЫНОК:
|
||||
promptBuilder.append("Анализ рынка: ");
|
||||
promptBuilder.append("Включи размер рынка, динамику роста, основные сегменты, тренды и перспективы развития.\n");
|
||||
break;
|
||||
case КОНКУРЕНТЫ:
|
||||
promptBuilder.append("Анализ конкурентов: ");
|
||||
promptBuilder.append("Включи основных конкурентов, их сильные и слабые стороны, позиционирование, ");
|
||||
promptBuilder.append("ценовую политику и маркетинговые стратегии.\n");
|
||||
break;
|
||||
case ЦА:
|
||||
promptBuilder.append("Анализ целевой аудитории: ");
|
||||
promptBuilder.append("Включи демографические характеристики, психографический профиль, потребности и боли, ");
|
||||
promptBuilder.append("поведенческие паттерны и предпочтения.\n");
|
||||
break;
|
||||
case КАНАЛЫ:
|
||||
promptBuilder.append("Анализ маркетинговых каналов: ");
|
||||
promptBuilder.append("Включи оценку эффективности различных каналов коммуникации, рекомендации по выбору каналов, ");
|
||||
promptBuilder.append("особенности использования каждого канала и бюджетные рекомендации.\n");
|
||||
break;
|
||||
case SWOT:
|
||||
promptBuilder.append("SWOT-анализ: ");
|
||||
promptBuilder.append("Включи анализ Сильных сторон (Strengths), Слабых сторон (Weaknesses), ");
|
||||
promptBuilder.append("Возможностей (Opportunities) и Угроз (Threats). ");
|
||||
promptBuilder.append("Ответ должен быть структурированным с четким разделением по каждому разделу SWOT.\n");
|
||||
break;
|
||||
Map<String, Object> targetAudienceData = request.getTargetAudience();
|
||||
if (targetAudienceData != null) {
|
||||
StringBuilder audienceBuilder = new StringBuilder();
|
||||
if (targetAudienceData.containsKey("genders")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> genders = (List<String>) targetAudienceData.get("genders");
|
||||
if (genders != null && !genders.isEmpty()) {
|
||||
audienceBuilder.append("Гендер: ").append(String.join(", ", genders)).append(". ");
|
||||
}
|
||||
}
|
||||
sectionNumber++;
|
||||
if (targetAudienceData.containsKey("ageRanges")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> ageRanges = (List<String>) targetAudienceData.get("ageRanges");
|
||||
if (ageRanges != null && !ageRanges.isEmpty()) {
|
||||
audienceBuilder.append("Возраст: ").append(String.join(", ", ageRanges)).append(". ");
|
||||
}
|
||||
}
|
||||
if (targetAudienceData.containsKey("types")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> types = (List<String>) targetAudienceData.get("types");
|
||||
if (types != null && !types.isEmpty()) {
|
||||
audienceBuilder.append("Тип: ").append(String.join(", ", types)).append(". ");
|
||||
}
|
||||
}
|
||||
inputDataBuilder.append("Целевая аудитория: ").append(audienceBuilder.toString().trim()).append("\n");
|
||||
}
|
||||
|
||||
inputDataBuilder.append("Конкуренты: ").append(request.getBusinessNiche()).append(" (уточни основных конкурентов)\n");
|
||||
inputDataBuilder.append("Цель продвижения: ").append(request.getGoal()).append("\n");
|
||||
List<String> regions = request.getRegion();
|
||||
if (regions != null && !regions.isEmpty()) {
|
||||
inputDataBuilder.append("Регион/город: ").append(String.join(", ", regions)).append("\n");
|
||||
}
|
||||
|
||||
promptBuilder.append("\n");
|
||||
promptBuilder.append(sectionNumber).append(". Общий вывод: ");
|
||||
promptBuilder.append("Объедини все разделы анализа в единый комплексный вывод, ");
|
||||
promptBuilder.append("выдели ключевые возможности и особенности бизнеса, ");
|
||||
promptBuilder.append("сформулируй прикладные рекомендации, применимые к конкретной тематике и задаче.\n\n");
|
||||
// Build the new prompt according to documentation
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Ты — профессиональный маркетолог и аналитик, работающий с малым и средним бизнесом Казахстана. ");
|
||||
promptBuilder.append("Твоя задача — выполнить глубокий маркетинговый анализ компании пользователя с генерацией всех необходимых количественных данных для построения графиков и диаграмм. ");
|
||||
promptBuilder.append("Пиши структурированно, лаконично, без воды, понятным языком, ориентируясь на предпринимателя МСБ.\n\n");
|
||||
|
||||
promptBuilder.append("📥 Входные данные пользователя:\n");
|
||||
promptBuilder.append(inputDataBuilder.toString());
|
||||
promptBuilder.append("Если данных недостаточно — логично дополни, отметив: «Данные уточнены системой автоматически».\n\n");
|
||||
|
||||
promptBuilder.append("📊 Требования к числовым данным\n");
|
||||
promptBuilder.append("Ты обязан сгенерировать реалистичные числовые значения, подходящие для автоматической визуализации.\n\n");
|
||||
|
||||
promptBuilder.append("1️⃣ Сезонность спроса (линейный график, 12 месяцев)\n");
|
||||
promptBuilder.append("Выведи таблицу:\n");
|
||||
promptBuilder.append("| Месяц | Уровень спроса (0–100) |\n");
|
||||
promptBuilder.append("Значения должны:\n");
|
||||
promptBuilder.append("- соответствовать нише,\n");
|
||||
promptBuilder.append("- иметь сезонную динамику,\n");
|
||||
promptBuilder.append("- быть реалистичными.\n\n");
|
||||
|
||||
promptBuilder.append("2️⃣ Сравнительный анализ конкурентов (столбчатая диаграмма)\n");
|
||||
promptBuilder.append("Выведи таблицу:\n");
|
||||
promptBuilder.append("| Конкурент | Охват аудитории | Активность в соцсетях (0–100) | Количество отзывов | Сильные стороны | Слабые стороны |\n");
|
||||
promptBuilder.append("Охват — в диапазоне 1 000–50 000, Активность — 0–100.\n\n");
|
||||
|
||||
promptBuilder.append("3️⃣ Сегментация целевой аудитории (круговая диаграмма)\n");
|
||||
promptBuilder.append("Определи:\n");
|
||||
promptBuilder.append("- возрастные группы (%)\n");
|
||||
promptBuilder.append("- пол (%)\n");
|
||||
promptBuilder.append("- 3–5 ключевых сегментов ЦА (%)\n");
|
||||
promptBuilder.append("Сумма процентов = 100%.\n\n");
|
||||
|
||||
promptBuilder.append("4️⃣ Потенциал каналов продвижения (бар-чарт)\n");
|
||||
promptBuilder.append("Каналы: Instagram, TikTok, Telegram, 2GIS, Google Ads\n");
|
||||
promptBuilder.append("Выведи таблицу:\n");
|
||||
promptBuilder.append("| Канал | Потенциал (0–100) | Обоснование |\n\n");
|
||||
|
||||
promptBuilder.append("5️⃣ Конверсионная воронка (воронка спроса)\n");
|
||||
promptBuilder.append("Выведи таблицу:\n");
|
||||
promptBuilder.append("| Этап | Значение | Конверсия (%) |\n");
|
||||
promptBuilder.append("Этапы:\n");
|
||||
promptBuilder.append("- Охват\n");
|
||||
promptBuilder.append("- Вовлечённость\n");
|
||||
promptBuilder.append("- Клики\n");
|
||||
promptBuilder.append("- Переходы\n");
|
||||
promptBuilder.append("- Заявки\n");
|
||||
promptBuilder.append("- Покупки\n");
|
||||
promptBuilder.append("Числа должны уменьшаться логично.\n\n");
|
||||
|
||||
promptBuilder.append("📘 Теперь сформируй полный маркетинговый анализ:\n\n");
|
||||
|
||||
promptBuilder.append("I. Анализ продукта\n");
|
||||
promptBuilder.append("- ключевые свойства\n");
|
||||
promptBuilder.append("- преимущества\n");
|
||||
promptBuilder.append("- возможные слабости\n");
|
||||
promptBuilder.append("- ценность для рынка Казахстана\n\n");
|
||||
|
||||
promptBuilder.append("II. Анализ рынка Казахстана\n");
|
||||
promptBuilder.append("- динамика\n");
|
||||
promptBuilder.append("- тренды\n");
|
||||
promptBuilder.append("- сезонность (используй данные из таблицы)\n");
|
||||
promptBuilder.append("- возможности и ограничения\n\n");
|
||||
|
||||
promptBuilder.append("III. Анализ целевой аудитории\n");
|
||||
promptBuilder.append("- портрет покупателя\n");
|
||||
promptBuilder.append("- боли, потребности, мотивации\n");
|
||||
promptBuilder.append("- триггеры принятия решения\n");
|
||||
promptBuilder.append("- сегментация (вставить таблицу)\n\n");
|
||||
|
||||
promptBuilder.append("IV. Анализ конкурентов\n");
|
||||
promptBuilder.append("Вставить таблицу конкурентов. Сформировать вывод о конкурентной среде. Указать рыночные ниши, которые свободны.\n\n");
|
||||
|
||||
promptBuilder.append("V. SWOT-анализ\n");
|
||||
promptBuilder.append("Сформируй матрицу 2×2:\n");
|
||||
promptBuilder.append("- Strengths\n");
|
||||
promptBuilder.append("- Weaknesses\n");
|
||||
promptBuilder.append("- Opportunities\n");
|
||||
promptBuilder.append("- Threats\n\n");
|
||||
|
||||
promptBuilder.append("VI. Уникальное торговое предложение (УТП)\n");
|
||||
promptBuilder.append("Создай 1–2 варианта УТП. Требования:\n");
|
||||
promptBuilder.append("- ясно,\n");
|
||||
promptBuilder.append("- коротко,\n");
|
||||
promptBuilder.append("- конкретно,\n");
|
||||
promptBuilder.append("- опираясь на анализ продукта и конкурентов.\n\n");
|
||||
|
||||
promptBuilder.append("VII. Рекомендации по позиционированию\n");
|
||||
promptBuilder.append("Определи:\n");
|
||||
promptBuilder.append("- образ бренда\n");
|
||||
promptBuilder.append("- ключевое сообщение\n");
|
||||
promptBuilder.append("- стиль коммуникации\n");
|
||||
promptBuilder.append("- что важно подчеркнуть\n\n");
|
||||
|
||||
promptBuilder.append("VIII. Рекомендации по каналам продвижения\n");
|
||||
promptBuilder.append("Вставить таблицу потенциала каналов. Дать объяснение, почему каждый канал подходит для этой ниши.\n\n");
|
||||
|
||||
promptBuilder.append("IX. Рекомендации по контенту\n");
|
||||
promptBuilder.append("Приведи набор контент-направлений:\n");
|
||||
promptBuilder.append("- продающий\n");
|
||||
promptBuilder.append("- экспертный\n");
|
||||
promptBuilder.append("- визуальный\n");
|
||||
promptBuilder.append("- доверительный\n");
|
||||
promptBuilder.append("- развлекательный\n");
|
||||
promptBuilder.append("Дай примеры публикаций.\n\n");
|
||||
|
||||
promptBuilder.append("X. Итоговая стратегия продвижения\n");
|
||||
promptBuilder.append("Сформулируй чётко:\n");
|
||||
promptBuilder.append("- цель\n");
|
||||
promptBuilder.append("- ключевые шаги\n");
|
||||
promptBuilder.append("- что делать в первую очередь\n");
|
||||
promptBuilder.append("- что даст максимальный эффект\n");
|
||||
promptBuilder.append("- ожидаемый результат\n\n");
|
||||
|
||||
promptBuilder.append(lengthInstruction).append(" ");
|
||||
promptBuilder.append("Ответ должен быть на русском языке.\n\n");
|
||||
@@ -573,13 +1148,132 @@ public class MarketingAnalysisService {
|
||||
}
|
||||
markdown.append("\n");
|
||||
|
||||
// Display unified analysis
|
||||
// Add chart data tables
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> chartsData = (Map<String, Object>) reportData.get("chartsData");
|
||||
if (chartsData != null && !chartsData.isEmpty()) {
|
||||
markdown.append("## 📊 Числовые данные для графиков\n\n");
|
||||
|
||||
// Seasonality table
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Integer> seasonality = (Map<String, Integer>) chartsData.get("seasonality");
|
||||
if (seasonality != null && !seasonality.isEmpty()) {
|
||||
markdown.append("### 1️⃣ Сезонность спроса (12 месяцев)\n\n");
|
||||
markdown.append("| Месяц | Уровень спроса (0–100) |\n");
|
||||
markdown.append("|-------|------------------------|\n");
|
||||
for (Map.Entry<String, Integer> entry : seasonality.entrySet()) {
|
||||
markdown.append("| ").append(entry.getKey()).append(" | ").append(entry.getValue()).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
|
||||
// Competitors table
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> competitors = (List<Map<String, Object>>) chartsData.get("competitors");
|
||||
if (competitors != null && !competitors.isEmpty()) {
|
||||
markdown.append("### 2️⃣ Сравнительный анализ конкурентов\n\n");
|
||||
markdown.append("| Конкурент | Охват аудитории | Активность в соцсетях (0–100) | Количество отзывов | Сильные стороны | Слабые стороны |\n");
|
||||
markdown.append("|-----------|-----------------|-------------------------------|-------------------|----------------|----------------|\n");
|
||||
for (Map<String, Object> comp : competitors) {
|
||||
markdown.append("| ").append(comp.get("name")).append(" | ")
|
||||
.append(comp.get("reach")).append(" | ")
|
||||
.append(comp.get("activity")).append(" | ")
|
||||
.append(comp.get("reviews")).append(" | ")
|
||||
.append(comp.get("strengths")).append(" | ")
|
||||
.append(comp.get("weaknesses")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
|
||||
// Audience segmentation tables
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> audienceSegmentation = (Map<String, Object>) chartsData.get("audienceSegmentation");
|
||||
if (audienceSegmentation != null && !audienceSegmentation.isEmpty()) {
|
||||
markdown.append("### 3️⃣ Сегментация целевой аудитории\n\n");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, String>> ageGroups = (List<Map<String, String>>) audienceSegmentation.get("ageGroups");
|
||||
if (ageGroups != null && !ageGroups.isEmpty()) {
|
||||
markdown.append("#### Возрастные группы\n\n");
|
||||
markdown.append("| Возрастная группа | Процент (%) |\n");
|
||||
markdown.append("|-------------------|-------------|\n");
|
||||
for (Map<String, String> group : ageGroups) {
|
||||
markdown.append("| ").append(group.get("label")).append(" | ").append(group.get("value")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, String>> genders = (List<Map<String, String>>) audienceSegmentation.get("genders");
|
||||
if (genders != null && !genders.isEmpty()) {
|
||||
markdown.append("#### Пол\n\n");
|
||||
markdown.append("| Пол | Процент (%) |\n");
|
||||
markdown.append("|-----|-------------|\n");
|
||||
for (Map<String, String> gender : genders) {
|
||||
markdown.append("| ").append(gender.get("label")).append(" | ").append(gender.get("value")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, String>> segments = (List<Map<String, String>>) audienceSegmentation.get("segments");
|
||||
if (segments != null && !segments.isEmpty()) {
|
||||
markdown.append("#### Сегменты ЦА\n\n");
|
||||
markdown.append("| Сегмент | Процент (%) |\n");
|
||||
markdown.append("|---------|-------------|\n");
|
||||
for (Map<String, String> segment : segments) {
|
||||
markdown.append("| ").append(segment.get("label")).append(" | ").append(segment.get("value")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Channels potential table
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> channelsPotential = (List<Map<String, Object>>) chartsData.get("channelsPotential");
|
||||
if (channelsPotential != null && !channelsPotential.isEmpty()) {
|
||||
markdown.append("### 4️⃣ Потенциал каналов продвижения\n\n");
|
||||
markdown.append("| Канал | Потенциал (0–100) | Обоснование |\n");
|
||||
markdown.append("|-------|-------------------|-------------|\n");
|
||||
for (Map<String, Object> channel : channelsPotential) {
|
||||
markdown.append("| ").append(channel.get("name")).append(" | ")
|
||||
.append(channel.get("potential")).append(" | ")
|
||||
.append(channel.get("justification")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
|
||||
// Conversion funnel table
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> conversionFunnel = (List<Map<String, Object>>) chartsData.get("conversionFunnel");
|
||||
if (conversionFunnel != null && !conversionFunnel.isEmpty()) {
|
||||
markdown.append("### 5️⃣ Конверсионная воронка\n\n");
|
||||
markdown.append("| Этап | Значение | Конверсия (%) |\n");
|
||||
markdown.append("|------|----------|---------------|\n");
|
||||
for (Map<String, Object> stage : conversionFunnel) {
|
||||
markdown.append("| ").append(stage.get("stage")).append(" | ")
|
||||
.append(stage.get("value")).append(" | ")
|
||||
.append(stage.get("conversion")).append(" |\n");
|
||||
}
|
||||
markdown.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Display full analysis with 10 sections
|
||||
String fullAnalysis = (String) reportData.get("fullAnalysis");
|
||||
if (fullAnalysis != null && !fullAnalysis.trim().isEmpty()) {
|
||||
markdown.append("## 📘 Полный маркетинговый анализ\n\n");
|
||||
markdown.append(fullAnalysis).append("\n\n");
|
||||
} else {
|
||||
// Fallback to summary if fullAnalysis is not available
|
||||
String summary = (String) reportData.get("summary");
|
||||
if (summary != null && !summary.trim().isEmpty()) {
|
||||
markdown.append("## Комплексный маркетинговый анализ\n\n");
|
||||
markdown.append(summary).append("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Keep backward compatibility sections
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> targetAudience = (Map<String, Object>) reportData.get("targetAudience");
|
||||
if (targetAudience != null) {
|
||||
@@ -677,7 +1371,21 @@ public class MarketingAnalysisService {
|
||||
MarketingAnalysis analysis) {
|
||||
MarketingAnalysisResult.MarketingReport report = new MarketingAnalysisResult.MarketingReport();
|
||||
|
||||
// Set summary (backward compatibility)
|
||||
report.setSummary((String) reportData.get("summary"));
|
||||
|
||||
// Set full analysis (new field)
|
||||
String fullAnalysis = (String) reportData.get("fullAnalysis");
|
||||
if (fullAnalysis != null) {
|
||||
report.setFullAnalysis(fullAnalysis);
|
||||
}
|
||||
|
||||
// Set charts data (new field)
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> chartsData = (Map<String, Object>) reportData.get("chartsData");
|
||||
if (chartsData != null) {
|
||||
report.setChartsData(chartsData);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> targetAudienceData = (Map<String, Object>) reportData.get("targetAudience");
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
ФИНАЛЬНЫЙ ПРОМТ ДЛЯ ГЕНЕРАЦИИ МАРКЕТИНГОВОГО АНАЛИЗА С ГРАФИКАМИ И ЧИСЛОВЫМИ ПОКАЗАТЕЛЯМИ
|
||||
(готов к использованию в backend или системе агентов)
|
||||
|
||||
Ты — профессиональный маркетолог и аналитик, работающий с малым и средним бизнесом Казахстана.
Твоя задача — выполнить глубокий маркетинговый анализ компании пользователя с генерацией всех необходимых количественных данных для построения графиков и диаграмм.
Пиши структурированно, лаконично, без воды, понятным языком, ориентируясь на предпринимателя МСБ.
|
||||
|
||||
📥 Входные данные пользователя:
|
||||
Название компании/продукта: {{company_name}}
|
||||
Описание продукта: {{product_description}}
|
||||
Целевая аудитория: {{target_audience}}
|
||||
Конкуренты: {{competitors}}
|
||||
Цель продвижения: {{goals}}
|
||||
Регион/город: {{region}}
|
||||
Если данных недостаточно — логично дополни, отметив:
«Данные уточнены системой автоматически».
|
||||
|
||||
📊 Требования к числовым данным
|
||||
Ты обязан сгенерировать реалистичные числовые значения, подходящие для автоматической визуализации.
|
||||
|
||||
1️⃣ Сезонность спроса (линейный график, 12 месяцев)
|
||||
Выведи таблицу:
|
||||
| Месяц | Уровень спроса (0–100) |
|
||||
Значения должны:
|
||||
соответствовать нише,
|
||||
иметь сезонную динамику,
|
||||
быть реалистичными.
|
||||
|
||||
2️⃣ Сравнительный анализ конкурентов (столбчатая диаграмма)
|
||||
Выведи таблицу:
|
||||
| Конкурент | Охват аудитории | Активность в соцсетях (0–100) | Количество отзывов | Сильные стороны | Слабые стороны |
|
||||
Охват — в диапазоне 1 000–50 000,
Активность — 0–100.
|
||||
|
||||
3️⃣ Сегментация целевой аудитории (круговая диаграмма)
|
||||
Определи:
|
||||
возрастные группы (%)
|
||||
пол (%)
|
||||
3–5 ключевых сегментов ЦА (%)
|
||||
Сумма процентов = 100%.
|
||||
|
||||
4️⃣ Потенциал каналов продвижения (бар-чарт)
|
||||
Каналы: Instagram, TikTok, Telegram, 2GIS, Google Ads
Выведи таблицу:
|
||||
| Канал | Потенциал (0–100) | Обоснование |
|
||||
|
||||
5️⃣ Конверсионная воронка (воронка спроса)
|
||||
Выведи таблицу:
|
||||
| Этап | Значение | Конверсия (%) |
|
||||
Этапы:
|
||||
Охват
|
||||
Вовлечённость
|
||||
Клики
|
||||
Переходы
|
||||
Заявки
|
||||
Покупки
|
||||
Числа должны уменьшаться логично.
|
||||
|
||||
📘 Теперь сформируй полный маркетинговый анализ:
|
||||
|
||||
I. Анализ продукта
|
||||
ключевые свойства
|
||||
преимущества
|
||||
возможные слабости
|
||||
ценность для рынка Казахстана
|
||||
|
||||
II. Анализ рынка Казахстана
|
||||
динамика
|
||||
тренды
|
||||
сезонность (используй данные из таблицы)
|
||||
возможности и ограничения
|
||||
|
||||
III. Анализ целевой аудитории
|
||||
портрет покупателя
|
||||
боли, потребности, мотивации
|
||||
триггеры принятия решения
|
||||
сегментация (вставить таблицу)
|
||||
|
||||
IV. Анализ конкурентов
|
||||
Вставить таблицу конкурентов.
Сформировать вывод о конкурентной среде.
Указать рыночные ниши, которые свободны.
|
||||
|
||||
V. SWOT-анализ
|
||||
Сформируй матрицу 2×2:
|
||||
Strengths
|
||||
Weaknesses
|
||||
Opportunities
|
||||
Threats
|
||||
|
||||
VI. Уникальное торговое предложение (УТП)
|
||||
Создай 1–2 варианта УТП.
Требования:
|
||||
ясно,
|
||||
коротко,
|
||||
конкретно,
|
||||
опираясь на анализ продукта и конкурентов.
|
||||
|
||||
VII. Рекомендации по позиционированию
|
||||
Определи:
|
||||
образ бренда
|
||||
ключевое сообщение
|
||||
стиль коммуникации
|
||||
что важно подчеркнуть
|
||||
|
||||
VIII. Рекомендации по каналам продвижения
|
||||
Вставить таблицу потенциала каналов.
Дать объяснение, почему каждый канал подходит для этой ниши.
|
||||
|
||||
IX. Рекомендации по контенту
|
||||
Приведи набор контент-направлений:
|
||||
продающий
|
||||
экспертный
|
||||
визуальный
|
||||
доверительный
|
||||
развлекательный
|
||||
Дай примеры публикаций.
|
||||
|
||||
X. Итоговая стратегия продвижения
|
||||
Сформулируй чётко:
|
||||
цель
|
||||
ключевые шаги
|
||||
что делать в первую очередь
|
||||
что даст максимальный эффект
|
||||
ожидаемый результат
|
||||
Reference in New Issue
Block a user