| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- 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<String> split(String reply, String plannedProbe, boolean shouldProbe) {
- List<String> out = new ArrayList<>();
- if (reply == null || reply.isBlank()) {
- appendUnique(out, plannedProbe, shouldProbe);
- return out;
- }
- String body = UniversalDeepDialogueService.stripProbeFromReply(reply, plannedProbe);
- List<String> answerParts = new ArrayList<>();
- List<String> 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<String> 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<String> 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<String> followUps(String reply, String plannedProbe, boolean shouldProbe) {
- List<String> 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<String> out, String text, boolean required) {
- appendUnique(out, text, required, null);
- }
- private static void appendUnique(List<String> out, String text, boolean required, LinkedHashSet<String> 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;
- }
- }
|