package com.ruoyi.ai.assistant;
|
|
import com.ruoyi.ai.tools.SalesAgentTools;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.StringUtils;
|
|
import java.time.LocalDate;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeFormatter;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
@Component
|
public class SalesIntentExecutor {
|
|
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
private static final Pattern LIMIT_PATTERN = Pattern.compile("(前|最近)?\\s*(\\d{1,2})\\s*条");
|
private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})");
|
private static final Pattern RELATIVE_DAY_PATTERN = Pattern.compile("(近|最近)?\\s*(\\d{1,3})\\s*天");
|
|
private final SalesAgentTools salesAgentTools;
|
|
public SalesIntentExecutor(SalesAgentTools salesAgentTools) {
|
this.salesAgentTools = salesAgentTools;
|
}
|
|
public String tryExecute(String memoryId, String message) {
|
if (!StringUtils.hasText(message)) {
|
return null;
|
}
|
String text = message.trim();
|
|
String quickPromptResponse = tryExecuteQuickPrompt(memoryId, text);
|
if (StringUtils.hasText(quickPromptResponse)) {
|
return quickPromptResponse;
|
}
|
|
String keyword = extractKeyword(text);
|
Integer limit = extractLimit(text);
|
DateRange dateRange = extractDateRange(text);
|
String startDate = dateRange.startDate();
|
String endDate = dateRange.endDate();
|
|
if (containsAny(text, "流失", "流失风险", "客户流失", "风险分析")) {
|
return salesAgentTools.analyzeCustomerChurnRisk(memoryId, startDate, endDate, text, keyword, limit);
|
}
|
if (containsAny(text, "回款", "收款", "报价")
|
&& containsAny(text, "建议", "策略", "优化", "方案")) {
|
return salesAgentTools.suggestCollectionAndQuotationStrategy(
|
memoryId, startDate, endDate, text, keyword, limit, shouldPrioritizeHighRisk(text));
|
}
|
if (containsAny(text, "指标", "统计", "看板", "总览", "经营分析")) {
|
return salesAgentTools.getSalesDashboard(memoryId, startDate, endDate, text);
|
}
|
if (containsAny(text, "客户档案", "私海", "公海", "客户池")) {
|
return salesAgentTools.listCustomerProfiles(memoryId, extractSeaType(text), keyword, limit);
|
}
|
if (containsAny(text, "销售报价", "报价单", "报价", "询价")) {
|
return salesAgentTools.listSalesQuotations(memoryId, keyword, startDate, endDate, limit);
|
}
|
if (containsAny(text, "销售退货", "退货", "退款")) {
|
return salesAgentTools.listSalesReturns(memoryId, startDate, endDate, keyword, limit);
|
}
|
if (containsAny(text, "客户往来", "往来", "回款", "应收", "来款", "收款明细")) {
|
return salesAgentTools.listCustomerInteractions(memoryId, keyword, startDate, endDate, limit);
|
}
|
if (containsAny(text, "发货台账", "发货", "物流", "快递", "运输")) {
|
return salesAgentTools.listShippingLedgers(memoryId, keyword, startDate, endDate, limit);
|
}
|
if (containsAny(text, "销售台账", "销售合同", "销售订单", "合同台账", "订单台账")) {
|
return salesAgentTools.listSalesLedgers(memoryId, keyword, startDate, endDate, limit);
|
}
|
return null;
|
}
|
|
private String tryExecuteQuickPrompt(String memoryId, String text) {
|
String normalized = normalizeForMatch(text);
|
if ("查询私海客户档案前10条".equals(normalized)) {
|
return salesAgentTools.listCustomerProfiles(memoryId, "private", null, 10);
|
}
|
if ("查询公海客户档案".equals(normalized)) {
|
return salesAgentTools.listCustomerProfiles(memoryId, "public", null, 10);
|
}
|
if ("查询本月销售报价".equals(normalized)) {
|
DateRange range = monthRange();
|
return salesAgentTools.listSalesQuotations(memoryId, null, range.startDate(), range.endDate(), 10);
|
}
|
if ("查询本月销售台账".equals(normalized)) {
|
DateRange range = monthRange();
|
return salesAgentTools.listSalesLedgers(memoryId, null, range.startDate(), range.endDate(), 10);
|
}
|
if ("查询近30天销售退货".equals(normalized)) {
|
DateRange range = recentDaysRange(30);
|
return salesAgentTools.listSalesReturns(memoryId, range.startDate(), range.endDate(), null, 10);
|
}
|
if ("查询近30天客户回款往来".equals(normalized)) {
|
DateRange range = recentDaysRange(30);
|
return salesAgentTools.listCustomerInteractions(memoryId, null, range.startDate(), range.endDate(), 10);
|
}
|
if ("查询本月发货台账".equals(normalized)) {
|
DateRange range = monthRange();
|
return salesAgentTools.listShippingLedgers(memoryId, null, range.startDate(), range.endDate(), 10);
|
}
|
if ("查看销售指标统计".equals(normalized)) {
|
return salesAgentTools.getSalesDashboard(memoryId, null, null, "本月");
|
}
|
if ("帮我做客户流失风险分析近30天前20条".equals(normalized)) {
|
DateRange range = recentDaysRange(30);
|
return salesAgentTools.analyzeCustomerChurnRisk(memoryId, range.startDate(), range.endDate(), "近30天", null, 20);
|
}
|
if ("生成回款与报价策略建议优先高风险客户".equals(normalized)) {
|
DateRange range = recentDaysRange(30);
|
return salesAgentTools.suggestCollectionAndQuotationStrategy(memoryId, range.startDate(), range.endDate(), "近30天", null, 10, true);
|
}
|
return null;
|
}
|
|
private boolean containsAny(String text, String... keywords) {
|
for (String keyword : keywords) {
|
if (text.contains(keyword)) {
|
return true;
|
}
|
}
|
return false;
|
}
|
|
private String extractSeaType(String text) {
|
if (text.contains("公海")) {
|
return "public";
|
}
|
if (text.contains("私海")) {
|
return "private";
|
}
|
return null;
|
}
|
|
private Integer extractLimit(String text) {
|
Matcher matcher = LIMIT_PATTERN.matcher(text);
|
return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
|
}
|
|
private DateRange extractDateRange(String text) {
|
Matcher matcher = DATE_PATTERN.matcher(text);
|
if (matcher.find()) {
|
String first = matcher.group(1);
|
String second = matcher.find() ? matcher.group(1) : first;
|
return buildDateRange(first, second);
|
}
|
if (text.contains("本月")) {
|
return monthRange();
|
}
|
if (text.contains("上月")) {
|
return lastMonthRange();
|
}
|
if (text.contains("本年") || text.contains("今年")) {
|
return yearRange();
|
}
|
Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text);
|
if (relativeDayMatcher.find()) {
|
int days = Integer.parseInt(relativeDayMatcher.group(2));
|
return recentDaysRange(days);
|
}
|
return new DateRange(null, null);
|
}
|
|
private DateRange buildDateRange(String start, String end) {
|
LocalDate startDate = parseDate(start);
|
LocalDate endDate = parseDate(end);
|
if (startDate == null || endDate == null) {
|
return new DateRange(null, null);
|
}
|
if (startDate.isAfter(endDate)) {
|
LocalDate temp = startDate;
|
startDate = endDate;
|
endDate = temp;
|
}
|
return new DateRange(formatDate(startDate), formatDate(endDate));
|
}
|
|
private DateRange recentDaysRange(int days) {
|
LocalDate end = LocalDate.now();
|
int safeDays = Math.max(days, 1);
|
LocalDate start = end.minusDays(safeDays - 1L);
|
return new DateRange(formatDate(start), formatDate(end));
|
}
|
|
private DateRange monthRange() {
|
LocalDate today = LocalDate.now();
|
return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today));
|
}
|
|
private DateRange lastMonthRange() {
|
YearMonth lastMonth = YearMonth.now().minusMonths(1);
|
return new DateRange(formatDate(lastMonth.atDay(1)), formatDate(lastMonth.atEndOfMonth()));
|
}
|
|
private DateRange yearRange() {
|
LocalDate today = LocalDate.now();
|
return new DateRange(formatDate(today.withDayOfYear(1)), formatDate(today));
|
}
|
|
private LocalDate parseDate(String text) {
|
try {
|
return LocalDate.parse(text, DATE_FMT);
|
} catch (Exception ignored) {
|
return null;
|
}
|
}
|
|
private String formatDate(LocalDate date) {
|
return date == null ? null : date.format(DATE_FMT);
|
}
|
|
private String normalizeForMatch(String text) {
|
if (!StringUtils.hasText(text)) {
|
return "";
|
}
|
return text.replace(",", "")
|
.replace(",", "")
|
.replace("。", "")
|
.replace(".", "")
|
.replace("!", "")
|
.replace("!", "")
|
.replace("?", "")
|
.replace("?", "")
|
.replace(":", "")
|
.replace(":", "")
|
.replace(";", "")
|
.replace(";", "")
|
.replace(" ", "")
|
.trim();
|
}
|
|
private Boolean shouldPrioritizeHighRisk(String text) {
|
return containsAny(text, "优先高风险", "高风险客户", "高风险");
|
}
|
|
private String extractKeyword(String text) {
|
String cleaned = text
|
.replace("查询", "")
|
.replace("查看", "")
|
.replace("看下", "")
|
.replace("看看", "")
|
.replace("帮我", "")
|
.replace("请", "")
|
.replace("一下", "")
|
.replace("销售", "")
|
.replace("客户档案", "")
|
.replace("报价单", "")
|
.replace("销售报价", "")
|
.replace("销售台账", "")
|
.replace("发货台账", "")
|
.replace("客户往来", "")
|
.replace("销售退货", "")
|
.replace("前10条", "")
|
.replace("最近10条", "")
|
.replace("前20条", "")
|
.replace("最近20条", "")
|
.replace("近30天", "")
|
.replace("本月", "")
|
.replace("本年", "")
|
.replace("今年", "")
|
.replace("条", "")
|
.trim();
|
return cleaned.length() >= 2 ? cleaned : null;
|
}
|
|
private record DateRange(String startDate, String endDate) {
|
}
|
}
|