diff --git a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java index 43456bf..1f65d44 100644 --- a/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java +++ b/src/main/java/kz/konturai/parser/service/MarketingAnalysisService.java @@ -40,6 +40,9 @@ public class MarketingAnalysisService { @Value("${openai.model.name.text:gpt-4o}") private String textModelName; + @Value("${openai.model.name:gpt-4o-mini}") + private String miniModelName; + public MarketingAnalysisService( MarketingAnalysisRepository repository, OpenAIAnalyticsService openAIAnalyticsService, @@ -1407,6 +1410,722 @@ public class MarketingAnalysisService { } } + /** + * Подготавливает контекстный JSON для конкретного раздела отчета. + * Извлекает только релевантные данные для экономии токенов. + * + * @param fullJson Полный JSON анализа + * @param section Название раздела (summary, product, market, audience, + * competitors, swot, channels, funnel, positioning, content, + * strategy) + * @return Контекстный JSON с базовыми полями и специфичными для раздела данными + */ + private Map prepareSectionContext(Map fullJson, String section) { + Map context = new HashMap<>(); + + // Всегда включаем базовые поля + if (fullJson.containsKey("product")) { + context.put("product", fullJson.get("product")); + } + if (fullJson.containsKey("businessNiche")) { + context.put("businessNiche", fullJson.get("businessNiche")); + } + if (fullJson.containsKey("goal")) { + context.put("goal", fullJson.get("goal")); + } + if (fullJson.containsKey("regions")) { + context.put("regions", fullJson.get("regions")); + } + if (fullJson.containsKey("detailLevel")) { + context.put("detailLevel", fullJson.get("detailLevel")); + } + + // Добавляем специфичные данные для каждого раздела + switch (section) { + case "summary": + // Для резюме достаточно базовых полей + meta если есть + if (fullJson.containsKey("meta")) { + context.put("meta", fullJson.get("meta")); + } + break; + case "product": + // Для продукта добавляем позиционирование и УТП если есть + if (fullJson.containsKey("positioning")) { + context.put("positioning", fullJson.get("positioning")); + } + if (fullJson.containsKey("valueProposition")) { + context.put("valueProposition", fullJson.get("valueProposition")); + } + break; + case "market": + if (fullJson.containsKey("seasonality")) { + context.put("seasonality", fullJson.get("seasonality")); + } + if (fullJson.containsKey("market")) { + context.put("market", fullJson.get("market")); + } + break; + case "audience": + if (fullJson.containsKey("audienceSegments")) { + context.put("audienceSegments", fullJson.get("audienceSegments")); + } + break; + case "competitors": + if (fullJson.containsKey("competitors")) { + context.put("competitors", fullJson.get("competitors")); + } + if (fullJson.containsKey("comparisonTable")) { + context.put("comparisonTable", fullJson.get("comparisonTable")); + } + if (fullJson.containsKey("swotCompetitors")) { + context.put("swotCompetitors", fullJson.get("swotCompetitors")); + } + if (fullJson.containsKey("marketShareChart")) { + context.put("marketShareChart", fullJson.get("marketShareChart")); + } + break; + case "swot": + if (fullJson.containsKey("swot")) { + context.put("swot", fullJson.get("swot")); + } + break; + case "channels": + if (fullJson.containsKey("channels")) { + context.put("channels", fullJson.get("channels")); + } + if (fullJson.containsKey("channelsPotential")) { + context.put("channelsPotential", fullJson.get("channelsPotential")); + } + break; + case "funnel": + if (fullJson.containsKey("funnel")) { + context.put("funnel", fullJson.get("funnel")); + } + if (fullJson.containsKey("conversionFunnel")) { + context.put("conversionFunnel", fullJson.get("conversionFunnel")); + } + break; + case "positioning": + if (fullJson.containsKey("positioning")) { + context.put("positioning", fullJson.get("positioning")); + } + if (fullJson.containsKey("valueProposition")) { + context.put("valueProposition", fullJson.get("valueProposition")); + } + break; + case "content": + if (fullJson.containsKey("contentRecommendations")) { + context.put("contentRecommendations", fullJson.get("contentRecommendations")); + } + break; + case "strategy": + // Для итоговой стратегии включаем все ключевые данные + if (fullJson.containsKey("swot")) { + context.put("swot", fullJson.get("swot")); + } + if (fullJson.containsKey("channels")) { + context.put("channels", fullJson.get("channels")); + } + if (fullJson.containsKey("funnel")) { + context.put("funnel", fullJson.get("funnel")); + } + if (fullJson.containsKey("positioning")) { + context.put("positioning", fullJson.get("positioning")); + } + if (fullJson.containsKey("valueProposition")) { + context.put("valueProposition", fullJson.get("valueProposition")); + } + if (fullJson.containsKey("contentRecommendations")) { + context.put("contentRecommendations", fullJson.get("contentRecommendations")); + } + break; + } + + return context; + } + + /** + * Генерирует раздел I: Краткое резюме + */ + private String genSectionSummary(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder + .append("На основе следующего JSON напиши РАЗДЕЛ I (Краткое резюме) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("I. Краткое резюме\n\n"); + promptBuilder.append("Опиши:\n"); + promptBuilder.append("- Что за бизнес (ниша, продукт/услуга)\n"); + promptBuilder.append("- Какую цель преследует бизнес на 6-12 месяцев\n"); + promptBuilder.append("- Ключевые выводы из анализа (3-4 главных инсайта)\n"); + promptBuilder.append("- Общую оценку потенциала и перспектив\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"I. Краткое резюме\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Пиши так, чтобы отчет был полезен для принятия бизнес-решений\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", miniModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionSummary: AI returned empty result"); + return "I. Краткое резюме\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionSummary: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionSummary: Error generating section: {}", e.getMessage(), e); + return "I. Краткое резюме\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел II: Анализ продукта + */ + private String genSectionProduct(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder + .append("На основе следующего JSON напиши РАЗДЕЛ II (Анализ продукта) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("II. Анализ продукта\n\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"); + promptBuilder.append("- Начинай сразу с заголовка \"II. Анализ продукта\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из полей product, businessNiche, positioning, valueProposition\n"); + promptBuilder.append("- Пиши максимально подробно, анализируй тренды\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", miniModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionProduct: AI returned empty result"); + return "II. Анализ продукта\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionProduct: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionProduct: Error generating section: {}", e.getMessage(), e); + return "II. Анализ продукта\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел III: Анализ рынка и сезонности + */ + private String genSectionMarket(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ III (Анализ рынка и сезонности) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("III. Анализ рынка и сезонности\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Рынок Казахстана в данной нише, его размер и динамику\n"); + promptBuilder.append("- Макроэкономические факторы, влияющие на нишу\n"); + promptBuilder.append("- Тренды и изменения в отрасли\n"); + promptBuilder.append("- Сезонные колебания спроса (используй данные из поля seasonality)\n"); + promptBuilder.append("- Как сезонность влияет на кэшфлоу бизнеса\n"); + promptBuilder.append("- Конкретные рекомендации по работе с сезонностью (акции, планирование)\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после описания сезонности) вставь плейсхолдер [[CHART_SEASONALITY]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"III. Анализ рынка и сезонности\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из полей seasonality, market, regions\n"); + promptBuilder.append("- Пиши максимально подробно, анализируй тренды\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionMarket: AI returned empty result"); + return "III. Анализ рынка и сезонности\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionMarket: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionMarket: Error generating section: {}", e.getMessage(), e); + return "III. Анализ рынка и сезонности\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел IV: Анализ целевой аудитории + */ + private String genSectionAudience(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ IV (Анализ целевой аудитории) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("IV. Анализ целевой аудитории\n\n"); + promptBuilder.append("Детально проанализируй КАЖДЫЙ сегмент из audienceSegments:\n"); + promptBuilder.append("- Демографические характеристики (возраст, пол, доход)\n"); + promptBuilder.append("- Психографический портрет (потребности, мотивация, ценности)\n"); + promptBuilder.append( + "- Customer Journey Map для каждого сегмента (этапы от первого контакта до покупки и лояльности)\n"); + promptBuilder.append("- Ключевые потребности и боли сегмента\n"); + promptBuilder.append("- Как продукт решает проблемы каждого сегмента\n"); + promptBuilder.append("- Рекомендации по коммуникации с каждым сегментом\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после описания сегментов) вставь плейсхолдер [[CHART_AUDIENCE]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"IV. Анализ целевой аудитории\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из поля audienceSegments\n"); + promptBuilder.append("- Для каждого сегмента создай детальный портрет клиента\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionAudience: AI returned empty result"); + return "IV. Анализ целевой аудитории\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionAudience: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionAudience: Error generating section: {}", e.getMessage(), e); + return "IV. Анализ целевой аудитории\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел V: Анализ конкурентов + */ + private String genSectionCompetitors(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ V (Анализ конкурентов) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("V. Анализ конкурентов\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Позиции каждого конкурента на рынке (используй данные из competitors)\n"); + promptBuilder.append("- Сильные и слабые стороны конкурентов (из comparisonTable и swotCompetitors)\n"); + promptBuilder.append("- Стратегии конкурентов (ценовая политика, каналы продвижения)\n"); + promptBuilder.append( + "- Контент-воронки конкурентов: какие типы контента они используют на каждом этапе воронки, какие каналы задействуют, какие месседжи доносят\n"); + promptBuilder.append("- Глубокое сравнение нашего бренда с конкурентами (используй comparisonTable)\n"); + promptBuilder.append("- Рекомендации по дифференциации и конкурентным преимуществам\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после анализа конкурентов) вставь плейсхолдер [[CHART_COMPETITORS]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"V. Анализ конкурентов\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append( + "- Используй данные из полей competitors, comparisonTable, swotCompetitors, marketShareChart\n"); + promptBuilder.append("- Делай глубокие сравнения нашего бренда с конкурентами\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionCompetitors: AI returned empty result"); + return "V. Анализ конкурентов\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionCompetitors: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionCompetitors: Error generating section: {}", e.getMessage(), e); + return "V. Анализ конкурентов\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел VI: SWOT-анализ + */ + private String genSectionSWOT(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append("На основе следующего JSON напиши РАЗДЕЛ VI (SWOT-анализ) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("VI. SWOT-анализ\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Сильные стороны (Strengths) - как их использовать\n"); + promptBuilder.append("- Слабые стороны (Weaknesses) - как их минимизировать\n"); + promptBuilder.append("- Возможности (Opportunities) - как их реализовать\n"); + promptBuilder.append("- Угрозы (Threats) - как им противостоять\n"); + promptBuilder.append("- КРИТИЧНО: Проведи перекрестный анализ:\n"); + promptBuilder.append(" * Как сильные стороны помогут использовать возможности\n"); + promptBuilder.append(" * Как слабые стороны могут помешать противостоять угрозам\n"); + promptBuilder.append(" * Стратегические комбинации (SO, ST, WO, WT)\n"); + promptBuilder.append("- Практические рекомендации на основе SWOT-матрицы\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после SWOT-анализа) вставь плейсхолдер [[CHART_SWOT]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"VI. SWOT-анализ\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из поля swot\n"); + promptBuilder.append("- Обязательно проведи перекрестный анализ пересечений\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionSWOT: AI returned empty result"); + return "VI. SWOT-анализ\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionSWOT: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionSWOT: Error generating section: {}", e.getMessage(), e); + return "VI. SWOT-анализ\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел VII: Каналы продвижения и их потенциал + */ + private String genSectionChannels(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ VII (Каналы продвижения и их потенциал) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("VII. Каналы продвижения и их потенциал\n\n"); + promptBuilder.append("Детально проанализируй КАЖДЫЙ канал из channels:\n"); + promptBuilder.append("- Потенциал канала для данной ниши (potentialIndex)\n"); + promptBuilder.append("- Приоритетность канала (priorityLevel) и обоснование\n"); + promptBuilder.append("- Роль канала в общей стратегии (roleInStrategy)\n"); + promptBuilder.append("- Обоснование важности канала (justification)\n"); + promptBuilder.append("- Рекомендации по использованию каждого канала\n"); + promptBuilder.append("- Бюджетные рекомендации и ожидаемая эффективность\n"); + promptBuilder.append("- Интеграция каналов в единую маркетинговую стратегию\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после анализа каналов) вставь плейсхолдер [[CHART_CHANNELS]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"VII. Каналы продвижения и их потенциал\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из полей channels, channelsPotential\n"); + promptBuilder.append("- Для каждого канала дай конкретные рекомендации\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionChannels: AI returned empty result"); + return "VII. Каналы продвижения и их потенциал\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionChannels: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionChannels: Error generating section: {}", e.getMessage(), e); + return "VII. Каналы продвижения и их потенциал\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел VIII: Воронка спроса + */ + private String genSectionFunnel(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder + .append("На основе следующего JSON напиши РАЗДЕЛ VIII (Воронка спроса) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("VIII. Воронка спроса\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Каждый этап воронки (stages из funnel): название, значение, конверсия\n"); + promptBuilder.append("- Где находится \"узкое место\" воронки (самая низкая конверсия)\n"); + promptBuilder.append("- Причины низкой конверсии на проблемных этапах\n"); + promptBuilder.append("- Конкретные рекомендации по улучшению каждого этапа\n"); + promptBuilder.append("- Как оптимизировать узкое место для увеличения общего конверсионного потока\n"); + promptBuilder.append("- Ожидаемый эффект от оптимизации (количественные оценки)\n"); + promptBuilder.append("- Интеграция воронки с каналами продвижения\n\n"); + promptBuilder.append("КРИТИЧНО - ВСТАВКА ГРАФИКА:\n"); + promptBuilder.append( + "1. В логичном месте раздела (после описания этапов) вставь плейсхолдер [[CHART_FUNNEL]] на отдельной строке\n"); + promptBuilder.append( + "2. ПЕРЕД графиком напиши вводный абзац (2-3 предложения), начинающийся с: \"Анализ данных на графике ниже показывает...\"\n"); + promptBuilder.append( + "3. ПОСЛЕ графика напиши интерпретацию данных (2-3 предложения), начинающуюся с: \"Из этих показателей следует, что...\"\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"VIII. Воронка спроса\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из полей funnel, conversionFunnel\n"); + promptBuilder.append("- Обязательно укажи, где \"узкое место\" и как его исправить\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", textModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionFunnel: AI returned empty result"); + return "VIII. Воронка спроса\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionFunnel: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionFunnel: Error generating section: {}", e.getMessage(), e); + return "VIII. Воронка спроса\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел IX: Рекомендации по позиционированию и УТП + */ + private String genSectionPositioning(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ IX (Рекомендации по позиционированию и УТП) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("IX. Рекомендации по позиционированию и УТП\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Позиционирование бренда (brandImage, keyMessage, toneOfVoice)\n"); + promptBuilder.append("- Уникальное торговое предложение (УТП) - как его сформулировать и донести\n"); + promptBuilder.append("- Факторы доверия (trustFactors) и как их использовать\n"); + promptBuilder.append("- Как позиционирование дифференцирует от конкурентов\n"); + promptBuilder.append("- Рекомендации по коммуникации позиционирования через разные каналы\n"); + promptBuilder.append("- Как УТП решает проблемы целевой аудитории\n"); + promptBuilder.append("- Практические шаги по внедрению позиционирования\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"IX. Рекомендации по позиционированию и УТП\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из полей positioning, valueProposition\n"); + promptBuilder.append("- Давай конкретные, практические рекомендации\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", miniModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionPositioning: AI returned empty result"); + return "IX. Рекомендации по позиционированию и УТП\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionPositioning: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionPositioning: Error generating section: {}", e.getMessage(), e); + return "IX. Рекомендации по позиционированию и УТП\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел X: Рекомендации по контенту + */ + private String genSectionContent(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ X (Рекомендации по контенту) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("X. Рекомендации по контенту\n\n"); + promptBuilder.append("Детально проанализируй:\n"); + promptBuilder.append("- Типы контента для разных целей (из contentRecommendations)\n"); + promptBuilder.append("- Форматы контента для разных каналов продвижения\n"); + promptBuilder.append("- Контент для разных этапов воронки (осведомленность, интерес, решение, действие)\n"); + promptBuilder.append("- Контент для разных сегментов целевой аудитории\n"); + promptBuilder.append("- Рекомендации по календарю контента (частота, темы, сезонность)\n"); + promptBuilder.append("- Как контент поддерживает позиционирование и УТП\n"); + promptBuilder.append("- Метрики эффективности контента и KPI\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder.append("- Начинай сразу с заголовка \"X. Рекомендации по контенту\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append("- Используй данные из поля contentRecommendations\n"); + promptBuilder.append("- Давай конкретные, практические рекомендации по типам и форматам контента\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", miniModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionContent: AI returned empty result"); + return "X. Рекомендации по контенту\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionContent: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionContent: Error generating section: {}", e.getMessage(), e); + return "X. Рекомендации по контенту\n\nОшибка при генерации раздела: " + e.getMessage(); + } + } + + /** + * Генерирует раздел XI: Итоговая стратегия + */ + private String genSectionStrategy(Map contextJson) { + try { + String jsonString = objectMapper.writeValueAsString(contextJson); + StringBuilder promptBuilder = new StringBuilder(); + promptBuilder.append("Ты — высокооплачиваемый бизнес-консультант и маркетинговый аналитик.\n\n"); + promptBuilder.append( + "На основе следующего JSON напиши РАЗДЕЛ XI (Итоговая стратегия: что делать в первую очередь) маркетингового отчета.\n\n"); + promptBuilder.append("ТРЕБОВАНИЯ:\n"); + promptBuilder.append("1. Объем: минимум 500-700 слов\n"); + promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n"); + promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n"); + promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n\n"); + promptBuilder.append("СТРУКТУРА РАЗДЕЛА:\n"); + promptBuilder.append("XI. Итоговая стратегия: что делать в первую очередь\n\n"); + promptBuilder.append("Создай конкретный план действий на 6-12 месяцев:\n"); + promptBuilder.append("- Приоритетные задачи (что делать в первую очередь, во вторую, в третью)\n"); + promptBuilder.append("- Конкретные шаги с указанием сроков и ответственных\n"); + promptBuilder.append("- Интеграция всех элементов: позиционирование, каналы, контент, воронка\n"); + promptBuilder.append("- Как использовать сильные стороны и возможности (из SWOT)\n"); + promptBuilder.append("- Как минимизировать слабые стороны и угрозы (из SWOT)\n"); + promptBuilder.append("- Ожидаемые результаты и метрики успеха\n"); + promptBuilder.append("- Бюджетные рекомендации и распределение ресурсов\n"); + promptBuilder.append("- Критические точки контроля и корректировки стратегии\n\n"); + promptBuilder.append("ВАЖНО:\n"); + promptBuilder + .append("- Начинай сразу с заголовка \"XI. Итоговая стратегия: что делать в первую очередь\"\n"); + promptBuilder.append("- Не добавляй вступления или заключения\n"); + promptBuilder.append( + "- Используй данные из всех предыдущих разделов (swot, channels, funnel, positioning, valueProposition, contentRecommendations)\n"); + promptBuilder.append("- Давай конкретный, практический план действий с приоритетами\n"); + promptBuilder.append("- Учитывай цель бизнеса на 6-12 месяцев (goal)\n\n"); + promptBuilder.append("JSON ДАННЫЕ:\n"); + promptBuilder.append(jsonString); + + String result = openAIAnalyticsService.generateWithInstructionWithModel( + jsonString, promptBuilder.toString(), "ru", miniModelName); + + if (result == null || result.trim().isEmpty()) { + logger.warn("genSectionStrategy: AI returned empty result"); + return "XI. Итоговая стратегия: что делать в первую очередь\n\nНе удалось сгенерировать раздел."; + } + + logger.info("genSectionStrategy: Section generated successfully. Length: {} chars", result.length()); + return result; + } catch (Exception e) { + logger.error("genSectionStrategy: Error generating section: {}", e.getMessage(), e); + return "XI. Итоговая стратегия: что делать в первую очередь\n\nОшибка при генерации раздела: " + + e.getMessage(); + } + } + /** * Генерирует профессиональный текстовый маркетинговый отчет на основе * JSON-анализа.