package com.ruoyi.ai.assistant;
|
|
import com.ruoyi.ai.tools.PurchaseAgentTools;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.StringUtils;
|
|
import java.time.DayOfWeek;
|
import java.time.LocalDate;
|
import java.time.format.DateTimeFormatter;
|
import java.util.Locale;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
@Component
|
public class PurchaseIntentExecutor {
|
|
private static final Pattern ID_PATTERN = Pattern.compile("\\b\\d{1,12}\\b");
|
private static final Pattern LIMIT_PATTERN = Pattern.compile("(前|最近)?(\\d{1,2})条");
|
private static final Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
|
private static final Pattern RELATIVE_RANGE_PATTERN = Pattern.compile("(近|最近)(\\d+)(天|周|个月|月|年)");
|
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
private final PurchaseAgentTools purchaseAgentTools;
|
|
public PurchaseIntentExecutor(PurchaseAgentTools purchaseAgentTools) {
|
this.purchaseAgentTools = purchaseAgentTools;
|
}
|
|
public String tryExecute(String memoryId, String message) {
|
if (!StringUtils.hasText(message)) {
|
return null;
|
}
|
String text = message.trim();
|
String startDate = extractStartDate(text);
|
String endDate = extractEndDate(text);
|
Integer limit = extractLimit(text);
|
|
if (containsAny(text, "排行", "排名", "前几", "前五", "前十") && containsAny(text, "物料", "产品", "原材料", "采购金额", "金额")) {
|
return purchaseAgentTools.rankPurchaseMaterials(
|
memoryId,
|
startDate,
|
endDate,
|
text,
|
limit
|
);
|
}
|
if (containsAny(text, "未入库", "待入库", "没有入库", "还未入库")) {
|
return purchaseAgentTools.listUnstockedPurchaseOrders(
|
memoryId,
|
startDate,
|
endDate,
|
extractKeyword(text),
|
limit
|
);
|
}
|
if (containsAny(text, "到货异常", "到货有异常", "异常到货", "到货问题", "供应商到货异常")) {
|
return purchaseAgentTools.listArrivalExceptions(
|
memoryId,
|
startDate,
|
endDate,
|
text,
|
limit
|
);
|
}
|
if (containsAny(text, "待付款", "未付款", "未付清", "待支付", "应付")) {
|
return purchaseAgentTools.listPendingPaymentOrders(
|
memoryId,
|
startDate,
|
endDate,
|
extractKeyword(text),
|
limit
|
);
|
}
|
if (containsAny(text, "退货", "退料", "拒收")) {
|
return purchaseAgentTools.listPurchaseReturns(
|
memoryId,
|
startDate,
|
endDate,
|
extractKeyword(text),
|
limit
|
);
|
}
|
if (isStatsIntent(text)) {
|
return purchaseAgentTools.getPurchaseStats(
|
memoryId,
|
startDate,
|
endDate,
|
text
|
);
|
}
|
if (containsAny(text, "详情", "明细") && extractId(text) != null) {
|
return purchaseAgentTools.getPurchaseLedgerDetail(memoryId, extractId(text));
|
}
|
if (containsAny(text, "台账", "采购单", "采购订单", "订单", "合同", "列表", "查询")) {
|
return purchaseAgentTools.listPurchaseLedgers(
|
memoryId,
|
extractKeyword(text),
|
startDate,
|
endDate,
|
limit
|
);
|
}
|
return null;
|
}
|
|
private boolean isStatsIntent(String text) {
|
if (containsAny(text, "统计", "分析", "报表", "汇总", "趋势", "数据看板", "情况", "有多少")) {
|
return true;
|
}
|
boolean queryWord = containsAny(text, "查询", "查看", "看下", "看看", "获取");
|
boolean dataWord = containsAny(text, "数据", "金额", "数量", "合同额", "付款额", "发票额");
|
boolean timeWord = containsAny(text, "今天", "本周", "本月", "上月", "今年", "去年", "近半年", "最近半个月", "半个月")
|
|| DATE_PATTERN.matcher(text).find();
|
return queryWord && dataWord && timeWord;
|
}
|
|
private boolean containsAny(String text, String... keywords) {
|
for (String keyword : keywords) {
|
if (text.contains(keyword)) {
|
return true;
|
}
|
}
|
return false;
|
}
|
|
private Long extractId(String text) {
|
Matcher matcher = ID_PATTERN.matcher(text);
|
if (!matcher.find()) {
|
return null;
|
}
|
return Long.parseLong(matcher.group());
|
}
|
|
private Integer extractLimit(String text) {
|
Matcher matcher = LIMIT_PATTERN.matcher(text);
|
return matcher.find() ? Integer.parseInt(matcher.group(2)) : 10;
|
}
|
|
private String extractStartDate(String text) {
|
Matcher matcher = DATE_PATTERN.matcher(text);
|
if (matcher.find()) {
|
return matcher.group();
|
}
|
DateRange range = extractRelativeDateRange(text);
|
return range == null ? null : range.start().format(DATE_FMT);
|
}
|
|
private String extractEndDate(String text) {
|
Matcher matcher = DATE_PATTERN.matcher(text);
|
if (!matcher.find()) {
|
DateRange range = extractRelativeDateRange(text);
|
return range == null ? null : range.end().format(DATE_FMT);
|
}
|
return matcher.find() ? matcher.group() : null;
|
}
|
|
private String extractKeyword(String text) {
|
String cleaned = text
|
.replace("查询", "")
|
.replace("查看", "")
|
.replace("采购", "")
|
.replace("采购单", "")
|
.replace("采购订单", "")
|
.replace("订单", "")
|
.replace("今年", "")
|
.replace("本年", "")
|
.replace("去年", "")
|
.replace("本月", "")
|
.replace("上月", "")
|
.replace("本周", "")
|
.replace("上周", "")
|
.replace("今天", "")
|
.replace("昨天", "")
|
.replace("近半年", "")
|
.replace("最近半年", "")
|
.replace("最近半个月", "")
|
.replace("半个月", "")
|
.replace("台账", "")
|
.replace("列表", "")
|
.replace("哪些", "")
|
.replace("什么", "")
|
.replace("情况", "")
|
.replace("有没有", "")
|
.replace("有啥", "")
|
.replace("有无", "")
|
.replace("列出", "")
|
.replace("帮我", "")
|
.replace("给我", "")
|
.replace("我", "")
|
.replace("最近10条", "")
|
.replace("前10条", "")
|
.trim();
|
cleaned = DATE_PATTERN.matcher(cleaned).replaceAll("");
|
cleaned = RELATIVE_RANGE_PATTERN.matcher(cleaned).replaceAll("");
|
return cleaned.length() >= 2 ? cleaned : null;
|
}
|
|
private DateRange extractRelativeDateRange(String text) {
|
if (!StringUtils.hasText(text)) {
|
return null;
|
}
|
String normalized = text.toLowerCase(Locale.ROOT);
|
LocalDate today = LocalDate.now();
|
|
if (normalized.contains("今天")) {
|
return new DateRange(today, today);
|
}
|
if (normalized.contains("昨天")) {
|
LocalDate yesterday = today.minusDays(1);
|
return new DateRange(yesterday, yesterday);
|
}
|
if (normalized.contains("今年") || normalized.contains("本年")) {
|
return new DateRange(today.withDayOfYear(1), today);
|
}
|
if (normalized.contains("去年")) {
|
LocalDate first = today.minusYears(1).withDayOfYear(1);
|
LocalDate last = first.withDayOfYear(first.lengthOfYear());
|
return new DateRange(first, last);
|
}
|
if (normalized.contains("本月")) {
|
return new DateRange(today.withDayOfMonth(1), today);
|
}
|
if (normalized.contains("上月")) {
|
LocalDate first = today.minusMonths(1).withDayOfMonth(1);
|
LocalDate last = first.withDayOfMonth(first.lengthOfMonth());
|
return new DateRange(first, last);
|
}
|
if (normalized.contains("本周")) {
|
LocalDate weekStart = today.with(DayOfWeek.MONDAY);
|
return new DateRange(weekStart, today);
|
}
|
if (normalized.contains("上周")) {
|
LocalDate weekStart = today.with(DayOfWeek.MONDAY).minusWeeks(1);
|
return new DateRange(weekStart, weekStart.plusDays(6));
|
}
|
if (normalized.contains("近半年") || normalized.contains("最近半年")) {
|
return new DateRange(today.minusMonths(6).plusDays(1), today);
|
}
|
if (normalized.contains("近半个月") || normalized.contains("最近半个月") || normalized.contains("半个月")) {
|
return new DateRange(today.minusDays(14), today);
|
}
|
|
Matcher matcher = RELATIVE_RANGE_PATTERN.matcher(normalized);
|
if (matcher.find()) {
|
int amount = Integer.parseInt(matcher.group(2));
|
String unit = matcher.group(3);
|
LocalDate start = switch (unit) {
|
case "天" -> today.minusDays(Math.max(amount - 1L, 0));
|
case "周" -> today.minusWeeks(Math.max(amount, 1)).plusDays(1);
|
case "个月", "月" -> today.minusMonths(Math.max(amount, 1)).plusDays(1);
|
case "年" -> today.minusYears(Math.max(amount, 1)).plusDays(1);
|
default -> today.minusDays(29);
|
};
|
return new DateRange(start, today);
|
}
|
return null;
|
}
|
|
private record DateRange(LocalDate start, LocalDate end) {
|
}
|
}
|