.
This commit is contained in:
@@ -112,7 +112,7 @@ public class MarketingAnalysisService {
|
|||||||
// Match lines like: "I. Title" or "## I. Title"
|
// Match lines like: "I. Title" or "## I. Title"
|
||||||
java.util.regex.Pattern p = java.util.regex.Pattern.compile(
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile(
|
||||||
"^(\\s*)(#{0,6}\\s*)?(" + java.util.regex.Pattern.quote(roman)
|
"^(\\s*)(#{0,6}\\s*)?(" + java.util.regex.Pattern.quote(roman)
|
||||||
+ ")\\.(\\s+[^\\n\\r]+)\\s*$",
|
+ ")\\.(\\s*\\S[^\\n\\r]*)\\s*$",
|
||||||
java.util.regex.Pattern.MULTILINE);
|
java.util.regex.Pattern.MULTILINE);
|
||||||
java.util.regex.Matcher m = p.matcher(result);
|
java.util.regex.Matcher m = p.matcher(result);
|
||||||
if (!m.find()) {
|
if (!m.find()) {
|
||||||
@@ -142,8 +142,8 @@ public class MarketingAnalysisService {
|
|||||||
}
|
}
|
||||||
for (String roman : SECTION_ROMANS) {
|
for (String roman : SECTION_ROMANS) {
|
||||||
java.util.regex.Pattern p = java.util.regex.Pattern.compile(
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile(
|
||||||
"^(?:\\s*<a\\s+id=\"[^\"]+\"\\s*></a>\\s*\\n)?\\s*##\\s*(" + java.util.regex.Pattern.quote(roman)
|
"^(?:\\s*<a\\s+id=\"[^\"]+\"\\s*></a>\\s*\\n)?\\s*(?:#{1,6}\\s*)?("
|
||||||
+ ")\\.(\\s+[^\\n\\r]+)\\s*$",
|
+ java.util.regex.Pattern.quote(roman) + ")\\.(\\s*\\S[^\\n\\r]*)\\s*$",
|
||||||
java.util.regex.Pattern.MULTILINE);
|
java.util.regex.Pattern.MULTILINE);
|
||||||
java.util.regex.Matcher m = p.matcher(fullAnalysis);
|
java.util.regex.Matcher m = p.matcher(fullAnalysis);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
@@ -2038,6 +2038,10 @@ public class MarketingAnalysisService {
|
|||||||
promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n");
|
promptBuilder.append("2. Стиль: деловой, убедительный для владельца бизнеса\n");
|
||||||
promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n");
|
promptBuilder.append("3. Глубина: аналитические инсайты с практическими выводами\n");
|
||||||
promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n");
|
promptBuilder.append("4. Данные: используй ТОЛЬКО данные из JSON, не выдумывай цифры\n");
|
||||||
|
promptBuilder.append(
|
||||||
|
"ВНИМАНИЕ: Проверяй математическую логику. Количество покупок НЕ МОЖЕТ быть больше количества заявок. "
|
||||||
|
+ "Конверсия не может превышать 100%. Если данные в JSON противоречивы, используй логические значения "
|
||||||
|
+ "(например, конверсия 10%) и сделай пометку 'Требуется уточнение данных'.\n");
|
||||||
promptBuilder.append("5. РАЗДЕЛ НЕЛЬЗЯ ПРОПУСКАТЬ:\n");
|
promptBuilder.append("5. РАЗДЕЛ НЕЛЬЗЯ ПРОПУСКАТЬ:\n");
|
||||||
promptBuilder.append(
|
promptBuilder.append(
|
||||||
" - Если в JSON нет funnel/conversionFunnel: построй воронку как ГИПОТЕЗУ (этапы + логика), но все числа замени на переменные (X1, X2...) и подпиши \"нет данных в JSON\".\n");
|
" - Если в JSON нет funnel/conversionFunnel: построй воронку как ГИПОТЕЗУ (этапы + логика), но все числа замени на переменные (X1, X2...) и подпиши \"нет данных в JSON\".\n");
|
||||||
@@ -2233,6 +2237,10 @@ public class MarketingAnalysisService {
|
|||||||
promptBuilder.append("КРИТИЧНО - ПРОГНОЗ И РАСЧЕТЫ НА ОСНОВЕ ВОРОНКИ:\n");
|
promptBuilder.append("КРИТИЧНО - ПРОГНОЗ И РАСЧЕТЫ НА ОСНОВЕ ВОРОНКИ:\n");
|
||||||
promptBuilder.append(
|
promptBuilder.append(
|
||||||
"1. Возьми воронку из strategyAnalysis.funnel (или из funnel, если strategyAnalysis отсутствует) и выполни расчеты.\n");
|
"1. Возьми воронку из strategyAnalysis.funnel (или из funnel, если strategyAnalysis отсутствует) и выполни расчеты.\n");
|
||||||
|
promptBuilder.append(
|
||||||
|
"ВНИМАНИЕ: Проверяй математическую логику. Количество покупок НЕ МОЖЕТ быть больше количества заявок. "
|
||||||
|
+ "Конверсия не может превышать 100%. Если данные в JSON противоречивы, используй логические значения "
|
||||||
|
+ "(например, конверсия 10%) и сделай пометку 'Требуется уточнение данных'.\n");
|
||||||
promptBuilder.append(
|
promptBuilder.append(
|
||||||
"2. Дай минимум 3 прогнозных показателя с формулами и подстановкой чисел из JSON (например: конверсия между этапами, ожидаемое число покупок, требуемый объем верхнего этапа для достижения цели).\n");
|
"2. Дай минимум 3 прогнозных показателя с формулами и подстановкой чисел из JSON (например: конверсия между этапами, ожидаемое число покупок, требуемый объем верхнего этапа для достижения цели).\n");
|
||||||
promptBuilder.append(
|
promptBuilder.append(
|
||||||
@@ -3378,6 +3386,9 @@ public class MarketingAnalysisService {
|
|||||||
for (String roman : SECTION_ROMANS) {
|
for (String roman : SECTION_ROMANS) {
|
||||||
String id = ROMAN_TO_ANCHOR_ID.get(roman);
|
String id = ROMAN_TO_ANCHOR_ID.get(roman);
|
||||||
String label = sectionTitles.getOrDefault(roman, "Раздел " + roman);
|
String label = sectionTitles.getOrDefault(roman, "Раздел " + roman);
|
||||||
|
if ("V".equals(roman) && ("Раздел V".equals(label) || label == null || label.isBlank())) {
|
||||||
|
label = "V. Анализ конкурентов";
|
||||||
|
}
|
||||||
markdown.append("- [").append(label).append("](#").append(id).append(")\n");
|
markdown.append("- [").append(label).append("](#").append(id).append(")\n");
|
||||||
}
|
}
|
||||||
markdown.append("\n");
|
markdown.append("\n");
|
||||||
@@ -3711,6 +3722,15 @@ public class MarketingAnalysisService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если JSON-блок для этого графика уже присутствует в секции — значит он уже
|
||||||
|
// вставлен/обработан; не добавляем повторно в конец секции
|
||||||
|
if (mapping.chartKey != null && sectionContainsJsonBlock(sectionText, mapping.chartKey)) {
|
||||||
|
if (processedPlaceholders != null) {
|
||||||
|
processedPlaceholders.add(normalizedPlaceholder);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Если данные отсутствуют — не добавляем тег (он будет удален final pass-ом)
|
// Если данные отсутствуют — не добавляем тег (он будет удален final pass-ом)
|
||||||
if (chartsData == null || !chartsData.containsKey(mapping.dataKey)) {
|
if (chartsData == null || !chartsData.containsKey(mapping.dataKey)) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
@@ -3764,6 +3784,19 @@ public class MarketingAnalysisService {
|
|||||||
.find();
|
.find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean sectionContainsJsonBlock(String sectionText, String chartKey) {
|
||||||
|
if (sectionText == null || sectionText.isEmpty() || chartKey == null || chartKey.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Matches blocks like:
|
||||||
|
// ```json:seasonality
|
||||||
|
// {...}
|
||||||
|
// ```
|
||||||
|
String regex = "```\\s*json\\s*:\\s*" + java.util.regex.Pattern.quote(chartKey.trim()) + "\\b";
|
||||||
|
return java.util.regex.Pattern.compile(regex, java.util.regex.Pattern.CASE_INSENSITIVE).matcher(sectionText)
|
||||||
|
.find();
|
||||||
|
}
|
||||||
|
|
||||||
public MarketingAnalysisResult getAnalysisResult(String analysisId) {
|
public MarketingAnalysisResult getAnalysisResult(String analysisId) {
|
||||||
Optional<MarketingAnalysis> optAnalysis = repository.findById(analysisId);
|
Optional<MarketingAnalysis> optAnalysis = repository.findById(analysisId);
|
||||||
if (optAnalysis.isEmpty()) {
|
if (optAnalysis.isEmpty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user