This commit is contained in:
root
2025-12-20 22:55:53 +05:00
parent e5aa373c61
commit 156997e510
2 changed files with 19 additions and 10 deletions
@@ -1351,7 +1351,8 @@ public class MarketingAnalysisService {
* Жесткая санитизация: убирает запрещённые фразы про отсутствие данных и, при
* необходимости, хвостовые плейсхолдеры [[CHART_*]]/[[TABLE_*]].
*
* Цель: в финальном отчёте не должно быть ни одной фразы "данные отсутствуют"/"нет данных"
* Цель: в финальном отчёте не должно быть ни одной фразы "данные
* отсутствуют"/"нет данных"
* и не должно оставаться токенов [[CHART_...]].
*/
private String hardSanitizeReportText(String text, boolean removePlaceholders) {
@@ -1361,7 +1362,8 @@ public class MarketingAnalysisService {
String cleaned = text;
// 1) Replace "no data" sentences with a neutral analytical extrapolation statement.
// 1) Replace "no data" sentences with a neutral analytical extrapolation
// statement.
String[] noDataSentencePatterns = new String[] {
"(?i)\\\\s*сожалению\\b[^\\n\\.\\!\\?]*\\bданн[а-яё]*\\b[^\\n\\.\\!\\?]*(нет|не\\s*представлен[а-яё]*)[^\\n\\.\\!\\?]*[\\.\\!\\?]?",
"(?i)\\bданные\\s*(отсутствуют|не\\s*представлен[а-яё]*|не\\s*доступн[а-яё]*)\\b[^\\n\\.\\!\\?]*[\\.\\!\\?]?",
@@ -1372,7 +1374,8 @@ public class MarketingAnalysisService {
cleaned = cleaned.replaceAll(p, "Экстраполяция: применяем консервативные допущения и методику расчета.");
}
// 2) Remove lingering short phrases (in case model wrote it without punctuation)
// 2) Remove lingering short phrases (in case model wrote it without
// punctuation)
cleaned = cleaned.replaceAll("(?i)\\b(нет\\s*данных|данные\\s*отсутствуют|нет\\s*информации)\\b", "");
// 3) Optionally remove any leftover placeholders
@@ -2255,12 +2258,13 @@ public class MarketingAnalysisService {
promptBuilder.append(
"- Вставь [[CHART_CHANNEL_MATRIX]] рядом с абзацем, где ты объясняешь поведение сегментов в каналах.\n");
promptBuilder.append(
"- Объясни на основе матрицы, почему для сегмента \"Молодежь\" приоритет Instagram выше, чем Facebook (с привязкой к значениям matrix).\n\n");
"- ОБЯЗАТЕЛЬНО проанализируй матрицу: объясни, почему для конкретного сегмента (например, \"Молодежь\") один канал имеет приоритет High, а другой Low. Делай выводы ТОЛЬКО с привязкой к конкретным ячейкам segmentsChannelMatrix (значения High/Medium/Low).\n\n");
promptBuilder.append("ВАЖНО:\n");
promptBuilder.append("- Начинай сразу с заголовка \"VII. Каналы продвижения и их потенциал\"\n");
promptBuilder.append("- Не добавляй вступления или заключения\n");
promptBuilder.append("- Используй данные из полей channels, channelsPotential\n");
promptBuilder.append("- Используй audienceAnalysis.segmentsChannelMatrix (если есть) для обоснования приоритетов.\n");
promptBuilder.append(
"- Используй audienceAnalysis.segmentsChannelMatrix (если есть) для обоснования приоритетов.\n");
promptBuilder.append("- Для каждого канала дай конкретные рекомендации\n\n");
promptBuilder.append("JSON ДАННЫЕ:\n");
promptBuilder.append(jsonString);
@@ -3629,7 +3633,8 @@ public class MarketingAnalysisService {
.replace("[[CHART_CHANNEL_MATRIX]]", "")
.replace("[[CHART_FUNNEL]]", "")
.replace("[[CHART_SWOT]]", "");
processedTextReport = processedTextReport.replaceAll("(?i)\\[\\[\\s*(CHART|TABLE)_[A-Za-z0-9_]+\\s*\\]\\]",
processedTextReport = processedTextReport.replaceAll(
"(?i)\\[\\[\\s*(CHART|TABLE)_[A-Za-z0-9_]+\\s*\\]\\]",
"");
}
@@ -3640,7 +3645,8 @@ public class MarketingAnalysisService {
// Очищаем текст: ошибки/отказы + "пустые" фразы про графики без реального блока
String cleanedTextReport = processedTextReport != null ? removeErrorMessages(processedTextReport) : null;
cleanedTextReport = cleanedTextReport != null ? removeDanglingChartNarration(cleanedTextReport) : null;
// Final hard sanitize: remove forbidden "no data" wording and any leftover placeholders
// Final hard sanitize: remove forbidden "no data" wording and any leftover
// placeholders
cleanedTextReport = cleanedTextReport != null ? hardSanitizeReportText(cleanedTextReport, true) : null;
if (cleanedTextReport != null && cleanedTextReport.trim().isEmpty()) {
cleanedTextReport = "Анализ не удалось сгенерировать.";
@@ -3828,7 +3834,8 @@ public class MarketingAnalysisService {
placeholderMap.put("[[CHART_AGE_DISTRIBUTION]]", new ChartMapping("audienceAge", "audienceAge"));
placeholderMap.put("[[CHART_GENDER_DISTRIBUTION]]", new ChartMapping("audienceGender", "audienceGender"));
placeholderMap.put("[[CHART_CHANNELS]]", new ChartMapping("channelsPotential", "channelsPotential"));
placeholderMap.put("[[CHART_CHANNEL_MATRIX]]", new ChartMapping("segmentsChannelMatrix", "segmentsChannelMatrix"));
placeholderMap.put("[[CHART_CHANNEL_MATRIX]]",
new ChartMapping("segmentsChannelMatrix", "segmentsChannelMatrix"));
placeholderMap.put("[[CHART_FUNNEL]]", new ChartMapping("conversionFunnel", "funnel"));
placeholderMap.put("[[CHART_SWOT]]", new ChartMapping("swot", "swot"));
@@ -33,7 +33,8 @@ class MarketingAnalysisServiceChartPlacementTest {
placeholderMap.put("[[TABLE_COMPARISON]]", ctor.newInstance("comparisonTable", "comparisonTable"));
placeholderMap.put("[[CHART_SWOT]]", ctor.newInstance("swot", "swot"));
placeholderMap.put("[[CHART_CHANNELS]]", ctor.newInstance("channelsPotential", "channelsPotential"));
placeholderMap.put("[[CHART_CHANNEL_MATRIX]]", ctor.newInstance("segmentsChannelMatrix", "segmentsChannelMatrix"));
placeholderMap.put("[[CHART_CHANNEL_MATRIX]]",
ctor.newInstance("segmentsChannelMatrix", "segmentsChannelMatrix"));
placeholderMap.put("[[CHART_FUNNEL]]", ctor.newInstance("conversionFunnel", "funnel"));
return placeholderMap;
}
@@ -149,6 +150,7 @@ class MarketingAnalysisServiceChartPlacementTest {
assertTrue(s7Start >= 0 && s8Start > s7Start, "Sanity check: VII before VIII");
String section7Body = out.substring(s7Start, s8Start);
assertTrue(section7Body.contains("[[CHART_CHANNELS]]"), "Must insert CHART_CHANNELS into section VII");
assertTrue(section7Body.contains("[[CHART_CHANNEL_MATRIX]]"), "Must insert CHART_CHANNEL_MATRIX into section VII");
assertTrue(section7Body.contains("[[CHART_CHANNEL_MATRIX]]"),
"Must insert CHART_CHANNEL_MATRIX into section VII");
}
}