.
This commit is contained in:
@@ -403,6 +403,326 @@ public class MarketingAnalysisService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Глубокая генерация текстового отчёта на основе JSON (4 этапа)
|
||||
*/
|
||||
private String generateDeepTextReport(Map<String, Object> analysisJson) {
|
||||
if (analysisJson == null || analysisJson.isEmpty()) {
|
||||
logger.warn("Empty analysisJson provided for deep text report generation");
|
||||
return "Не удалось сгенерировать текстовый отчёт: отсутствуют данные JSON-анализа.";
|
||||
}
|
||||
|
||||
try {
|
||||
// Преобразование JSON в строку для контекста
|
||||
String jsonContext = objectMapper.writeValueAsString(analysisJson);
|
||||
|
||||
// Генерация всех 4 этапов последовательно
|
||||
String stage1 = generateStage1MarketAndProduct(jsonContext);
|
||||
String stage2 = generateStage2AudienceAndCompetitors(jsonContext);
|
||||
String stage3 = generateStage3StrategyAndFunnel(jsonContext);
|
||||
String stage4 = generateStage4RecommendationsAndContent(jsonContext);
|
||||
|
||||
// Склеивание всех частей с двойными переносами строк
|
||||
StringBuilder fullReport = new StringBuilder();
|
||||
|
||||
if (stage1 != null && !stage1.trim().isEmpty()) {
|
||||
fullReport.append(stage1.trim());
|
||||
} else {
|
||||
fullReport.append("I. Краткое резюме\n\nII. Анализ продукта\n\nIII. Анализ рынка и сезонности\n\n");
|
||||
logger.warn("Stage 1 generation returned empty result");
|
||||
}
|
||||
|
||||
if (stage2 != null && !stage2.trim().isEmpty()) {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append(stage2.trim());
|
||||
} else {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append("IV. Анализ целевой аудитории\n\nV. Анализ конкурентов\n\n");
|
||||
logger.warn("Stage 2 generation returned empty result");
|
||||
}
|
||||
|
||||
if (stage3 != null && !stage3.trim().isEmpty()) {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append(stage3.trim());
|
||||
} else {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append(
|
||||
"VI. SWOT-анализ\n\nVII. Каналы продвижения и их потенциал\n\nVIII. Воронка спроса\n\n");
|
||||
logger.warn("Stage 3 generation returned empty result");
|
||||
}
|
||||
|
||||
if (stage4 != null && !stage4.trim().isEmpty()) {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append(stage4.trim());
|
||||
} else {
|
||||
if (fullReport.length() > 0) {
|
||||
fullReport.append("\n\n");
|
||||
}
|
||||
fullReport.append(
|
||||
"IX. Рекомендации по позиционированию и УТП\n\nX. Рекомендации по контенту\n\nXI. Итоговая стратегия: что делать в первую очередь\n\n");
|
||||
logger.warn("Stage 4 generation returned empty result");
|
||||
}
|
||||
|
||||
return fullReport.toString();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating deep text report from JSON: {}", e.getMessage(), e);
|
||||
return "Ошибка при генерации текстового отчёта: " + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Этап 1: Рынок и Продукт
|
||||
* Разделы: I. Краткое резюме, II. Анализ продукта, III. Анализ рынка и
|
||||
* сезонности
|
||||
*/
|
||||
private String generateStage1MarketAndProduct(String jsonContext) {
|
||||
try {
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Ты — профессиональный маркетолог и аналитик.\n\n");
|
||||
promptBuilder.append("Тебе передан JSON с результатами маркетингового анализа.\n\n");
|
||||
promptBuilder
|
||||
.append("ТВОЯ ЗАДАЧА: Напиши ТОЛЬКО следующие разделы отчета (без вступлений, без пояснений):\n\n");
|
||||
promptBuilder.append("I. Краткое резюме\n");
|
||||
promptBuilder.append(" Опиши бизнес, его цель и общий вывод (2-3 абзаца).\n\n");
|
||||
promptBuilder.append("II. Анализ продукта\n");
|
||||
promptBuilder.append(
|
||||
" Детально проанализируй продукт/услугу, его особенности, преимущества и позиционирование.\n");
|
||||
promptBuilder.append(" Пиши максимально подробно, анализируй тренды.\n\n");
|
||||
promptBuilder.append("III. Анализ рынка и сезонности\n");
|
||||
promptBuilder.append(" Проанализируй рынок, его динамику, сезонные колебания спроса.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"seasonality\" JSON.\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_SEASONALITY]] в логичном месте раздела, где график будет уместен.\n");
|
||||
promptBuilder.append(" Пиши максимально подробно, анализируй тренды.\n\n");
|
||||
promptBuilder.append("ВАЖНО:\n");
|
||||
promptBuilder.append("- Верни ТОЛЬКО эти три раздела, без вступлений типа \"Конечно, вот ваш отчет...\"\n");
|
||||
promptBuilder.append("- Начинай сразу с \"I. Краткое резюме\"\n");
|
||||
promptBuilder.append("- Используй данные ТОЛЬКО из переданного JSON\n");
|
||||
promptBuilder.append("- Пиши простым, деловым языком, с акцентом на практическую пользу\n");
|
||||
promptBuilder.append("- Не выдумывай новые цифры — используй только те, что есть в JSON\n");
|
||||
|
||||
String prompt = promptBuilder.toString();
|
||||
String result = openAIAnalyticsService.generateWithInstruction(jsonContext, prompt, "ru");
|
||||
|
||||
if (result == null || result.trim().isEmpty()) {
|
||||
logger.warn("Stage 1 returned null or empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Очистка от возможных вступлений
|
||||
String cleaned = result.trim();
|
||||
if (cleaned.toLowerCase().startsWith("конечно") ||
|
||||
cleaned.toLowerCase().startsWith("вот") ||
|
||||
cleaned.toLowerCase().startsWith("ниже")) {
|
||||
// Пытаемся найти начало первого раздела
|
||||
int firstSection = cleaned.indexOf("I. ");
|
||||
if (firstSection > 0) {
|
||||
cleaned = cleaned.substring(firstSection);
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating stage 1 (Market and Product): {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Этап 2: Аудитория и Конкуренты
|
||||
* Разделы: IV. Анализ целевой аудитории, V. Анализ конкурентов
|
||||
*/
|
||||
private String generateStage2AudienceAndCompetitors(String jsonContext) {
|
||||
try {
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Ты — профессиональный маркетолог и аналитик.\n\n");
|
||||
promptBuilder.append("Тебе передан JSON с результатами маркетингового анализа.\n\n");
|
||||
promptBuilder
|
||||
.append("ТВОЯ ЗАДАЧА: Напиши ТОЛЬКО следующие разделы отчета (без вступлений, без пояснений):\n\n");
|
||||
promptBuilder.append("IV. Анализ целевой аудитории\n");
|
||||
promptBuilder.append(" Проведи глубокий психологический разбор целевой аудитории.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"audienceSegments\" JSON.\n");
|
||||
promptBuilder.append(
|
||||
" Опиши демографические характеристики, психографический профиль, потребности, поведенческие паттерны.\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_AUDIENCE]] в логичном месте раздела, где график будет уместен.\n");
|
||||
promptBuilder.append(" Сделай глубокий психологический разбор аудитории.\n\n");
|
||||
promptBuilder.append("V. Анализ конкурентов\n");
|
||||
promptBuilder.append(" Детально сравни конкурентов.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"competitors\" JSON.\n");
|
||||
promptBuilder.append(" Опиши их сильные и слабые стороны, позиционирование, стратегии.\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_COMPETITORS]] в логичном месте раздела, где график будет уместен.\n");
|
||||
promptBuilder.append(" Детально сравни конкурентов.\n\n");
|
||||
promptBuilder.append("ВАЖНО:\n");
|
||||
promptBuilder.append("- Верни ТОЛЬКО эти два раздела, без вступлений типа \"Конечно, вот ваш отчет...\"\n");
|
||||
promptBuilder.append("- Начинай сразу с \"IV. Анализ целевой аудитории\"\n");
|
||||
promptBuilder.append("- Используй данные ТОЛЬКО из переданного JSON\n");
|
||||
promptBuilder.append("- Пиши простым, деловым языком, с акцентом на практическую пользу\n");
|
||||
promptBuilder.append("- Не выдумывай новые цифры — используй только те, что есть в JSON\n");
|
||||
|
||||
String prompt = promptBuilder.toString();
|
||||
String result = openAIAnalyticsService.generateWithInstruction(jsonContext, prompt, "ru");
|
||||
|
||||
if (result == null || result.trim().isEmpty()) {
|
||||
logger.warn("Stage 2 returned null or empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Очистка от возможных вступлений
|
||||
String cleaned = result.trim();
|
||||
if (cleaned.toLowerCase().startsWith("конечно") ||
|
||||
cleaned.toLowerCase().startsWith("вот") ||
|
||||
cleaned.toLowerCase().startsWith("ниже")) {
|
||||
// Пытаемся найти начало первого раздела
|
||||
int firstSection = cleaned.indexOf("IV. ");
|
||||
if (firstSection > 0) {
|
||||
cleaned = cleaned.substring(firstSection);
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating stage 2 (Audience and Competitors): {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Этап 3: Стратегия и Воронка
|
||||
* Разделы: VI. SWOT-анализ, VII. Каналы продвижения, VIII. Воронка спроса
|
||||
*/
|
||||
private String generateStage3StrategyAndFunnel(String jsonContext) {
|
||||
try {
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Ты — профессиональный маркетолог и аналитик.\n\n");
|
||||
promptBuilder.append("Тебе передан JSON с результатами маркетингового анализа.\n\n");
|
||||
promptBuilder
|
||||
.append("ТВОЯ ЗАДАЧА: Напиши ТОЛЬКО следующие разделы отчета (без вступлений, без пояснений):\n\n");
|
||||
promptBuilder.append("VI. SWOT-анализ\n");
|
||||
promptBuilder.append(
|
||||
" Представь SWOT-анализ в виде 4 списков: Сильные стороны, Слабые стороны, Возможности, Угрозы.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"swot\" JSON.\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_SWOT]] в логичном месте раздела, где график/таблица будет уместна.\n\n");
|
||||
promptBuilder.append("VII. Каналы продвижения и их потенциал\n");
|
||||
promptBuilder.append(" Опиши рекомендуемые каналы продвижения.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"channels\" JSON.\n");
|
||||
promptBuilder.append(" Дай обоснование каждому каналу (почему он важен, как его использовать).\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_CHANNELS]] в логичном месте раздела, где график будет уместен.\n\n");
|
||||
promptBuilder.append("VIII. Воронка спроса\n");
|
||||
promptBuilder.append(" Опиши этапы воронки спроса.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"funnel\" JSON.\n");
|
||||
promptBuilder.append(" Опиши узкие места воронки (где происходят наибольшие потери конверсии).\n");
|
||||
promptBuilder.append(
|
||||
" Вставь плейсхолдер [[CHART_FUNNEL]] в логичном месте раздела, где график будет уместен.\n\n");
|
||||
promptBuilder.append("ВАЖНО:\n");
|
||||
promptBuilder.append("- Верни ТОЛЬКО эти три раздела, без вступлений типа \"Конечно, вот ваш отчет...\"\n");
|
||||
promptBuilder.append("- Начинай сразу с \"VI. SWOT-анализ\"\n");
|
||||
promptBuilder.append("- Используй данные ТОЛЬКО из переданного JSON\n");
|
||||
promptBuilder.append("- Пиши простым, деловым языком, с акцентом на практическую пользу\n");
|
||||
promptBuilder.append("- Не выдумывай новые цифры — используй только те, что есть в JSON\n");
|
||||
|
||||
String prompt = promptBuilder.toString();
|
||||
String result = openAIAnalyticsService.generateWithInstruction(jsonContext, prompt, "ru");
|
||||
|
||||
if (result == null || result.trim().isEmpty()) {
|
||||
logger.warn("Stage 3 returned null or empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Очистка от возможных вступлений
|
||||
String cleaned = result.trim();
|
||||
if (cleaned.toLowerCase().startsWith("конечно") ||
|
||||
cleaned.toLowerCase().startsWith("вот") ||
|
||||
cleaned.toLowerCase().startsWith("ниже")) {
|
||||
// Пытаемся найти начало первого раздела
|
||||
int firstSection = cleaned.indexOf("VI. ");
|
||||
if (firstSection > 0) {
|
||||
cleaned = cleaned.substring(firstSection);
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating stage 3 (Strategy and Funnel): {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Этап 4: Рекомендации и Контент
|
||||
* Разделы: IX. Позиционирование и УТП, X. Рекомендации по контенту, XI.
|
||||
* Итоговая стратегия (Roadmap)
|
||||
*/
|
||||
private String generateStage4RecommendationsAndContent(String jsonContext) {
|
||||
try {
|
||||
StringBuilder promptBuilder = new StringBuilder();
|
||||
promptBuilder.append("Ты — профессиональный маркетолог и аналитик.\n\n");
|
||||
promptBuilder.append("Тебе передан JSON с результатами маркетингового анализа.\n\n");
|
||||
promptBuilder
|
||||
.append("ТВОЯ ЗАДАЧА: Напиши ТОЛЬКО следующие разделы отчета (без вступлений, без пояснений):\n\n");
|
||||
promptBuilder.append("IX. Рекомендации по позиционированию и УТП\n");
|
||||
promptBuilder.append(" Опиши позиционирование бренда и уникальное торговое предложение.\n");
|
||||
promptBuilder.append(" Используй данные из полей \"positioning\" и \"valueProposition\" JSON.\n");
|
||||
promptBuilder.append(" Представь практические рекомендации по позиционированию.\n\n");
|
||||
promptBuilder.append("X. Рекомендации по контенту\n");
|
||||
promptBuilder.append(" Дай практические рекомендации по типам контента для маркетинга.\n");
|
||||
promptBuilder.append(" Используй данные из поля \"contentRecommendations\" JSON.\n");
|
||||
promptBuilder
|
||||
.append(" Опиши, какой контент использовать для продаж, экспертизы, доверия, развлечения.\n\n");
|
||||
promptBuilder.append("XI. Итоговая стратегия: что делать в первую очередь\n");
|
||||
promptBuilder.append(" Создай практический Roadmap (дорожную карту) действий.\n");
|
||||
promptBuilder.append(" Укажи конкретные шаги, приоритеты, последовательность действий.\n");
|
||||
promptBuilder.append(
|
||||
" Пиши практические шаги, бери данные из полей \"positioning\", \"valueProposition\", \"contentRecommendations\" JSON.\n\n");
|
||||
promptBuilder.append("ВАЖНО:\n");
|
||||
promptBuilder.append("- Верни ТОЛЬКО эти три раздела, без вступлений типа \"Конечно, вот ваш отчет...\"\n");
|
||||
promptBuilder.append("- Начинай сразу с \"IX. Рекомендации по позиционированию и УТП\"\n");
|
||||
promptBuilder.append("- Используй данные ТОЛЬКО из переданного JSON\n");
|
||||
promptBuilder.append("- Пиши простым, деловым языком, с акцентом на практическую пользу\n");
|
||||
promptBuilder.append("- Не выдумывай новые цифры — используй только те, что есть в JSON\n");
|
||||
promptBuilder.append(
|
||||
"- Пиши практические шаги, бери данные из полей positioning, valueProposition, contentRecommendations\n");
|
||||
|
||||
String prompt = promptBuilder.toString();
|
||||
String result = openAIAnalyticsService.generateWithInstruction(jsonContext, prompt, "ru");
|
||||
|
||||
if (result == null || result.trim().isEmpty()) {
|
||||
logger.warn("Stage 4 returned null or empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Очистка от возможных вступлений
|
||||
String cleaned = result.trim();
|
||||
if (cleaned.toLowerCase().startsWith("конечно") ||
|
||||
cleaned.toLowerCase().startsWith("вот") ||
|
||||
cleaned.toLowerCase().startsWith("ниже")) {
|
||||
// Пытаемся найти начало первого раздела
|
||||
int firstSection = cleaned.indexOf("IX. ");
|
||||
if (firstSection > 0) {
|
||||
cleaned = cleaned.substring(firstSection);
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error generating stage 4 (Recommendations and Content): {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Валидация JSON-анализа
|
||||
*/
|
||||
@@ -778,8 +1098,8 @@ public class MarketingAnalysisService {
|
||||
// Сохраняем JSON в отчёт
|
||||
report.put("analysisJson", analysisJson);
|
||||
|
||||
// Шаг 2: Генерация текстового отчёта на основе JSON (Промпт №2)
|
||||
String textReport = generateTextReportFromJson(analysisJson);
|
||||
// Шаг 2: Глубокая генерация текстового отчёта на основе JSON (4 этапа)
|
||||
String textReport = generateDeepTextReport(analysisJson);
|
||||
|
||||
// Извлекаем данные для графиков из JSON
|
||||
Map<String, Object> chartsData = parseChartDataFromJson(analysisJson);
|
||||
|
||||
Reference in New Issue
Block a user