| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.ai.assistant; |
| | | |
| | | import com.ruoyi.ai.tools.FinancialAgentTools; |
| | | 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 FinancialIntentExecutor { |
| | | |
| | | 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 static final Pattern FUTURE_MONTH_PATTERN = Pattern.compile("(?:æªæ¥|åç»|æ¥ä¸æ¥)\\s*(\\d{1,2})\\s*(?:个)?æ"); |
| | | |
| | | private final FinancialAgentTools financialAgentTools; |
| | | |
| | | public FinancialIntentExecutor(FinancialAgentTools financialAgentTools) { |
| | | this.financialAgentTools = financialAgentTools; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | DateRange dateRange = extractDateRange(text); |
| | | Integer limit = extractLimit(text); |
| | | String keyword = extractKeyword(text); |
| | | String startDate = dateRange.startDate(); |
| | | String endDate = dateRange.endDate(); |
| | | String timeRange = dateRange.label(); |
| | | |
| | | if (containsAny(text, "ææ¬æ ¸ç®", "äº§åææ¬", "å·¥åºææ¬", "äººå·¥ææ¬", "ææ§", "æææè", "ææ¬æé«")) { |
| | | return financialAgentTools.calculateIntelligentCost(memoryId, startDate, endDate, timeRange, keyword, limit); |
| | | } |
| | | if (containsAny(text, "婿¶¦åæ", "订å婿¶¦", "äºæè®¢å", "ä½å©æ¶¦", "æèµé±å®¢æ·", "åªä¸ªå®¢æ·æèµé±", |
| | | "å®¢æ·æèµé±", "婿¶¦æé«å®¢æ·", "婿¶¦è´¡ç®æé«", "婿¶¦ä¸é")) { |
| | | return financialAgentTools.analyzeOrderProfit(memoryId, startDate, endDate, timeRange, keyword, limit); |
| | | } |
| | | if (containsAny(text, "åºåèµé", "åºå积å", "åæ»åºå", "èµéå ç¨", "å¨è½¬ç", "åºåå¨è½¬")) { |
| | | return financialAgentTools.analyzeInventoryCapital(memoryId, startDate, endDate, timeRange, keyword, limit); |
| | | } |
| | | if (containsAny(text, "ç°éæµ", "忬¾é£é©", "仿¬¾åå", "èµé缺å£", "åºæ¶", "åºä»", "忬¾é¢æµ")) { |
| | | return financialAgentTools.forecastCashFlow(memoryId, startDate, endDate, timeRange, extractForecastMonths(text)); |
| | | } |
| | | if (containsAny(text, "å¼å¸¸é¢è¦", "ç»è¥å¼å¸¸", "é£é©é¢è¦", "ææ¬å¼å¸¸", "婿¶¦å¼å¸¸", "忬¾å¼å¸¸", "订åé£é©")) { |
| | | return financialAgentTools.detectBusinessAnomalies(memoryId, startDate, endDate, timeRange, limit); |
| | | } |
| | | if (containsAny(text, "驾驶è±", "ç»è¥çæ¿", "ç»è¥æ»è§", "ç»è¥ä»ªè¡¨ç", "ç»è¥å¤§ç")) { |
| | | return financialAgentTools.getBusinessCockpit(memoryId, startDate, endDate, timeRange); |
| | | } |
| | | if (containsAny(text, "æ¥æ¥", "卿¥", "ç»è¥æ¥å", "åææ¥å")) { |
| | | return financialAgentTools.generateOperationReport(memoryId, startDate, endDate, timeRange, |
| | | containsAny(text, "卿¥") ? "weekly" : "daily"); |
| | | } |
| | | if (containsAny(text, "ä¸è´¢èå", "ä¸è´¢èå¨", "å£å¾", "ææ è§£é", "为ä»ä¹")) { |
| | | return financialAgentTools.retrieveFinancialKnowledge(memoryId, text); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String tryExecuteQuickPrompt(String memoryId, String text) { |
| | | String normalized = normalizeForMatch(text); |
| | | if ("çææ¬å¨ç»è¥å¨æ¥å©æ¶¦ä¸ç°éæµ".equals(normalized) || "çææ¬å¨ç»è¥å¨æ¥".equals(normalized) || "çæå¨æ¥".equals(normalized)) { |
| | | DateRange range = weekRange(); |
| | | return financialAgentTools.generateOperationReport(memoryId, range.startDate(), range.endDate(), range.label(), "weekly"); |
| | | } |
| | | if ("åææ¬æå©æ¶¦ä¸éåå ".equals(normalized)) { |
| | | DateRange range = monthRange(); |
| | | return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); |
| | | } |
| | | if ("è¿30天åªä¸ªå®¢æ·å©æ¶¦è´¡ç®æé«".equals(normalized)) { |
| | | DateRange range = recentDaysRange(30); |
| | | return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); |
| | | } |
| | | if ("æ¥çæ¬æç»è¥é©¾é©¶è±".equals(normalized) || "æ¥çç»è¥é©¾é©¶è±".equals(normalized)) { |
| | | DateRange range = monthRange(); |
| | | return financialAgentTools.getBusinessCockpit(memoryId, range.startDate(), range.endDate(), range.label()); |
| | | } |
| | | if ("æ¥è¯¢è¿30å¤©äºæè®¢å".equals(normalized)) { |
| | | DateRange range = recentDaysRange(30); |
| | | return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, null); |
| | | } |
| | | if ("åæè¿30天åºåèµéå ç¨".equals(normalized)) { |
| | | DateRange range = recentDaysRange(30); |
| | | return financialAgentTools.analyzeInventoryCapital(memoryId, range.startDate(), range.endDate(), range.label(), null, null); |
| | | } |
| | | if ("颿µæªæ¥3个æç°éæµ".equals(normalized)) { |
| | | return financialAgentTools.forecastCashFlow(memoryId, null, null, null, 3); |
| | | } |
| | | if ("åªä¸ªå·¥åºææ¬æé«".equals(normalized)) { |
| | | return financialAgentTools.calculateIntelligentCost(memoryId, null, null, null, null, null); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private boolean containsAny(String text, String... keywords) { |
| | | for (String keyword : keywords) { |
| | | if (text.contains(keyword)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private Integer extractLimit(String text) { |
| | | Matcher matcher = LIMIT_PATTERN.matcher(text); |
| | | return matcher.find() ? Integer.parseInt(matcher.group(1)) : null; |
| | | } |
| | | |
| | | private Integer extractForecastMonths(String text) { |
| | | Matcher matcher = FUTURE_MONTH_PATTERN.matcher(text); |
| | | return matcher.find() ? Integer.parseInt(matcher.group(1)) : null; |
| | | } |
| | | |
| | | 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, first + "è³" + second); |
| | | } |
| | | if (text.contains("æ¬æ")) { |
| | | return monthRange(); |
| | | } |
| | | if (text.contains("䏿")) { |
| | | return lastMonthRange(); |
| | | } |
| | | if (text.contains("ä»å¹´") || text.contains("æ¬å¹´")) { |
| | | return yearRange(); |
| | | } |
| | | if (text.contains("æ¬å¨")) { |
| | | return weekRange(); |
| | | } |
| | | Matcher relativeDayMatcher = RELATIVE_DAY_PATTERN.matcher(text); |
| | | if (relativeDayMatcher.find()) { |
| | | int days = Integer.parseInt(relativeDayMatcher.group(1)); |
| | | return recentDaysRange(days); |
| | | } |
| | | return new DateRange(null, null, null); |
| | | } |
| | | |
| | | private DateRange buildDateRange(String start, String end, String label) { |
| | | LocalDate startDate = parseDate(start); |
| | | LocalDate endDate = parseDate(end); |
| | | if (startDate == null || endDate == null) { |
| | | return new DateRange(null, null, null); |
| | | } |
| | | if (startDate.isAfter(endDate)) { |
| | | LocalDate temp = startDate; |
| | | startDate = endDate; |
| | | endDate = temp; |
| | | } |
| | | return new DateRange(formatDate(startDate), formatDate(endDate), label); |
| | | } |
| | | |
| | | 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), "è¿" + safeDays + "天"); |
| | | } |
| | | |
| | | private DateRange monthRange() { |
| | | LocalDate today = LocalDate.now(); |
| | | return new DateRange(formatDate(today.withDayOfMonth(1)), formatDate(today), "æ¬æ"); |
| | | } |
| | | |
| | | private DateRange weekRange() { |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate start = today.minusDays(today.getDayOfWeek().getValue() - 1L); |
| | | return new DateRange(formatDate(start), 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("ï¼", "") |
| | | .replace(":", "") |
| | | .replace("ï¼", "") |
| | | .replace(";", "") |
| | | .replace(" ", "") |
| | | .trim(); |
| | | } |
| | | |
| | | private String extractKeyword(String text) { |
| | | String cleaned = text |
| | | .replaceAll("\\d{4}-\\d{2}-\\d{2}", "") |
| | | .replaceAll("(?:è¿|æè¿)\\s*\\d{1,3}\\s*天", "") |
| | | .replaceAll("(?:å|æè¿|å±ç¤º|è¿å)?\\s*\\d{1,2}\\s*(?:æ¡|个|å)", "") |
| | | .replace("æ¥è¯¢", "") |
| | | .replace("æ¥ç", "") |
| | | .replace("çä¸", "") |
| | | .replace("çç", "") |
| | | .replace("帮æ", "") |
| | | .replace("请", "") |
| | | .replace("ä¸ä¸ª", "") |
| | | .replace("为ä»ä¹", "") |
| | | .replace("åªä¸ªå®¢æ·æèµé±", "") |
| | | .replace("æè¿åªä¸ªå®¢æ·æèµé±", "") |
| | | .replace("æ¬æåªä¸ªå®¢æ·æèµé±", "") |
| | | .replace("è¿30天åªä¸ªå®¢æ·æèµé±", "") |
| | | .replace("æèµé±å®¢æ·", "") |
| | | .replace("å®¢æ·æèµé±", "") |
| | | .replace("åªä¸ªå®¢æ·å©æ¶¦æé«", "") |
| | | .replace("婿¶¦æé«å®¢æ·", "") |
| | | .replace("åªä¸ªå®¢æ·å©æ¶¦è´¡ç®æé«", "") |
| | | .replace("婿¶¦è´¡ç®æé«å®¢æ·", "") |
| | | .replace("æ¬æ", "") |
| | | .replace("æ¬å¨", "") |
| | | .replace("æ¬å¹´", "") |
| | | .replace("ä»å¹´", "") |
| | | .replace("䏿", "") |
| | | .replace("è¿30天", "") |
| | | .replace("è¿7天", "") |
| | | .replace("è¿90天", "") |
| | | .replace("å10æ¡", "") |
| | | .replace("æè¿10æ¡", "") |
| | | .replace("å20æ¡", "") |
| | | .replace("æè¿20æ¡", "") |
| | | .replace("订å婿¶¦åæ", "") |
| | | .replace("婿¶¦åæ", "") |
| | | .replace("åºåèµéåæ", "") |
| | | .replace("ç°éæµé¢æµ", "") |
| | | .replace("ç»è¥é©¾é©¶è±", "") |
| | | .replace("æ¥æ¥", "") |
| | | .replace("卿¥", "") |
| | | .replace("å¼å¸¸é¢è¦", "") |
| | | .replace("æ¡", "") |
| | | .trim(); |
| | | return cleaned.length() >= 2 ? cleaned : null; |
| | | } |
| | | |
| | | private record DateRange(String startDate, String endDate, String label) { |
| | | } |
| | | } |