| | |
| | | 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; |
| | | |
| | |
| | | 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; |
| | | |
| | |
| | | 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, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text, |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "未入库", "待入库", "没有入库", "还未入库")) { |
| | | return purchaseAgentTools.listUnstockedPurchaseOrders( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "到货异常", "到货有异常", "异常到货", "到货问题", "供应商到货异常")) { |
| | | return purchaseAgentTools.listArrivalExceptions( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text, |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "待付款", "未付款", "未付清", "待支付", "应付")) { |
| | | return purchaseAgentTools.listPendingPaymentOrders( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (containsAny(text, "退货", "退料", "拒收")) { |
| | | return purchaseAgentTools.listPurchaseReturns( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | extractKeyword(text), |
| | | extractLimit(text) |
| | | limit |
| | | ); |
| | | } |
| | | if (isStatsIntent(text)) { |
| | | return purchaseAgentTools.getPurchaseStats( |
| | | memoryId, |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | startDate, |
| | | endDate, |
| | | text |
| | | ); |
| | | } |
| | |
| | | return purchaseAgentTools.listPurchaseLedgers( |
| | | memoryId, |
| | | extractKeyword(text), |
| | | extractStartDate(text), |
| | | extractEndDate(text), |
| | | extractLimit(text) |
| | | startDate, |
| | | endDate, |
| | | limit |
| | | ); |
| | | } |
| | | return null; |
| | |
| | | |
| | | private String extractStartDate(String text) { |
| | | Matcher matcher = DATE_PATTERN.matcher(text); |
| | | return matcher.find() ? matcher.group() : null; |
| | | 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()) { |
| | | return null; |
| | | DateRange range = extractRelativeDateRange(text); |
| | | return range == null ? null : range.end().format(DATE_FMT); |
| | | } |
| | | return matcher.find() ? matcher.group() : null; |
| | | } |
| | |
| | | .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) { |
| | | } |
| | | } |