package com.fs.company.service.workflow.deepdialogue; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.regex.Pattern; /** * Split customer-facing text into: main answer first, then each question as its own message. */ public final class CustomerFacingMessageSplitter { private static final Pattern SENTENCE_SPLIT = Pattern.compile("[。!??!;\\n]+"); private CustomerFacingMessageSplitter() { } /** * @return non-empty list: index 0 = answer body; rest = follow-up / rhetorical questions */ public static List split(String reply, String plannedProbe, boolean shouldProbe) { List out = new ArrayList<>(); if (reply == null || reply.isBlank()) { appendUnique(out, plannedProbe, shouldProbe); return out; } String body = UniversalDeepDialogueService.stripProbeFromReply(reply, plannedProbe); List answerParts = new ArrayList<>(); List questionParts = new ArrayList<>(); for (String sentence : SENTENCE_SPLIT.split(body)) { String part = sentence != null ? sentence.trim() : ""; if (part.isEmpty()) { continue; } if (isQuestionSentence(part)) { questionParts.add(normalizeQuestion(part)); } else { answerParts.add(part); } } String answer = String.join("。", answerParts).trim(); if (!answer.isEmpty() && !answer.endsWith("。") && !answer.endsWith("!") && !answer.endsWith("!") && !answer.endsWith("~") && !answer.endsWith("…")) { answer = answer + "。"; } appendUnique(out, answer.isEmpty() ? null : answer.replaceAll("。+$", "。"), false); LinkedHashSet seen = new LinkedHashSet<>(); if (!out.isEmpty() && out.get(0) != null) { seen.add(out.get(0)); } for (String q : questionParts) { appendUnique(out, q, false, seen); } appendUnique(out, plannedProbe, shouldProbe, seen); return out; } /** Keep declarative sentences only; questions are sent as separate follow-up messages. */ public static String extractAnswerOnly(String reply) { if (reply == null || reply.isBlank()) { return reply; } List parts = split(reply, null, false); if (parts.isEmpty()) { return reply.trim(); } String answer = parts.get(0); return answer != null && !answer.isBlank() ? answer.trim() : reply.trim(); } public static List followUps(String reply, String plannedProbe, boolean shouldProbe) { List all = split(reply, plannedProbe, shouldProbe); if (all.size() <= 1) { return List.of(); } return new ArrayList<>(all.subList(1, all.size())); } private static void appendUnique(List out, String text, boolean required) { appendUnique(out, text, required, null); } private static void appendUnique(List out, String text, boolean required, LinkedHashSet seen) { if (!required && (text == null || text.isBlank())) { return; } if (text == null || text.isBlank()) { return; } String normalized = text.trim(); if (seen != null) { String key = normalized.length() > 12 ? normalized.substring(0, 12) : normalized; if (seen.contains(key) || seen.stream().anyMatch(s -> s != null && s.contains(key))) { return; } seen.add(key); } out.add(normalized); } static boolean isQuestionSentence(String sentence) { if (sentence == null || sentence.isBlank()) { return false; } String t = sentence.trim(); if (t.endsWith("?") || t.endsWith("?")) { return true; } return t.matches(".*(吗|呢|吗?|呢?|么|啊|吧|嘛|是不是|能不能|可不可以|要不要|有没有|多少|几|哪|谁)[??]?$"); } private static String normalizeQuestion(String sentence) { String t = sentence.trim(); if (!t.endsWith("?") && !t.endsWith("?")) { t = t + "?"; } return t; } }