2 天以前 620bb4712a31791231c4381581f0f60088f079fe
src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,284 @@
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) {
    }
}